mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 18:13:01 +00:00
following improvements: - Arch/OS/platform-specific files are now included/excluded via the preprocessor, rather than via the build system. This is more consistent (we use the pre-processor for small arch/OS/platform-specific chunks within files) and makes the build system much simpler, as the sources for all programs are the same on all platforms. - Vast amounts of cut+paste Makefile.am code has been factored out. If a new platform is implemented, you need to add 11 extra Makefile.am lines. Previously it was over 100 lines. - Vex has been autotoolised. Dependency checking now works in Vex (no more incomplete builds). Parallel builds now also work. --with-vex no longer works; it's little use and a pain to support. VEX/Makefile is still in the Vex repository and gets overwritten at configure-time; it should probably be renamed Makefile-gcc to avoid possible problems, such as accidentally committing a generated Makefile. There's a bunch of hacky copying to deal with the fact that autotools don't handle same-named files in different directories. Julian plans to rename the files to avoid this problem. - Various small Makefile.am things have been made more standard automake style, eg. the use of pkginclude/pkglib prefixes instead of rolling our own. - The existing five top-level Makefile.am include files have been consolidated into three. - Most Makefile.am files now are structured more clearly, with comment headers separating sections, declarations relating to the same things next to each other, better spacing and layout, etc. - Removed the unused exp-ptrcheck/tests/x86 directory. - Renamed some XML files. - Factored out some duplicated dSYM handling code. - Split auxprogs/ into auxprogs/ and mpi/, which allowed the resulting Makefile.am files to be much more standard. - Cleaned up m_coredump by merging a bunch of files that had been overzealously separated. The net result is 630 fewer lines of Makefile.am code, or 897 if you exclude the added Makefile.vex.am, or 997 once the hacky file copying for Vex is removed. And the build system is much simpler. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10364
2619 lines
92 KiB
C
2619 lines
92 KiB
C
|
|
/*---------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- A library of wrappers for MPI 2 functions. ---*/
|
|
/*--- ---*/
|
|
/*---------------------------------------------------------------*/
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
Notice that the following BSD-style license applies to this one
|
|
file (mpiwrap.c) only. The rest of Valgrind is licensed under the
|
|
terms of the GNU General Public License, version 2, unless
|
|
otherwise indicated. See the COPYING file in the source
|
|
distribution for details.
|
|
|
|
----------------------------------------------------------------
|
|
|
|
This file is part of Valgrind, a dynamic binary instrumentation
|
|
framework.
|
|
|
|
Copyright (C) 2006-2009 OpenWorks LLP. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
2. The origin of this software must not be misrepresented; you must
|
|
not claim that you wrote the original software. If you use this
|
|
software in a product, an acknowledgment in the product
|
|
documentation would be appreciated but is not required.
|
|
|
|
3. Altered source versions must be plainly marked as such, and must
|
|
not be misrepresented as being the original software.
|
|
|
|
4. The name of the author may not be used to endorse or promote
|
|
products derived from this software without specific prior written
|
|
permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
Neither the names of the U.S. Department of Energy nor the
|
|
University of California nor the names of its contributors may be
|
|
used to endorse or promote products derived from this software
|
|
without prior written permission.
|
|
*/
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- includes ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <unistd.h> /* getpid */
|
|
#include <stdlib.h> /* exit */
|
|
#include <string.h> /* strstr */
|
|
#include <pthread.h> /* pthread_mutex_{lock,unlock} */
|
|
|
|
/* Include Valgrind magic macros for writing wrappers. */
|
|
#include "../memcheck/memcheck.h"
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Connect to MPI library ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* Include headers for whatever MPI implementation the wrappers are to
|
|
be used with. The configure system will tell us what the path to
|
|
the chosen MPI implementation is, via -I.. to the compiler. */
|
|
#include "mpi.h"
|
|
|
|
/* Where are API symbols?
|
|
Open MPI lib/libmpi.so, soname = libmpi.so.0
|
|
Quadrics MPI lib/libmpi.so, soname = libmpi.so.0
|
|
MPICH libmpich.so.1.0, soname = libmpich.so.1.0
|
|
AIX: in /usr/lpp/ppe.poe/lib/libmpi_r.a(mpicore*_r.o)
|
|
|
|
For the non-AIX targets, a suitable soname to match with
|
|
is "libmpi*.so*".
|
|
*/
|
|
#if defined(_AIX)
|
|
# define I_WRAP_FNNAME_U(_name) \
|
|
I_WRAP_SONAME_FNNAME_ZU(libmpiZurZdaZLmpicoreZaZurZdoZR,_name)
|
|
/* Don't change this without also changing all the names in
|
|
libmpiwrap.exp. */
|
|
#else
|
|
# define I_WRAP_FNNAME_U(_name) \
|
|
I_WRAP_SONAME_FNNAME_ZU(libmpiZaZdsoZa,_name)
|
|
|
|
#endif
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Decls ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
typedef unsigned char Bool;
|
|
#define False ((Bool)0)
|
|
#define True ((Bool)1)
|
|
|
|
/* Word, UWord are machine words - same size as a pointer. This is
|
|
checked at startup. The wrappers below use 'long' to mean a
|
|
machine word - this too is tested at startup. */
|
|
typedef signed long Word;
|
|
typedef unsigned long UWord;
|
|
|
|
#if !defined(offsetof)
|
|
# define offsetof(type,memb) ((int)&((type*)0)->memb)
|
|
#endif
|
|
|
|
/* Find the size of long double image (not 'sizeof(long double)').
|
|
See comments in sizeofOneNamedTy. */
|
|
static long sizeof_long_double_image ( void );
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Simple helpers ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* ------ Helpers for debug printing ------ */
|
|
|
|
/* constant */
|
|
static const char* preamble = "valgrind MPI wrappers";
|
|
|
|
/* established at startup */
|
|
static pid_t my_pid = -1;
|
|
static char* options_str = NULL;
|
|
static int opt_verbosity = 1;
|
|
static Bool opt_missing = 0; /* 0:silent; 1:warn; 2:abort */
|
|
static Bool opt_help = False;
|
|
static Bool opt_initkludge = False;
|
|
|
|
static void before ( char* fnname )
|
|
{
|
|
/* This isn't thread-safe wrt 'done' (no locking). It's not
|
|
critical. */
|
|
static int done = 0;
|
|
if (done == 0) {
|
|
done = 1;
|
|
my_pid = getpid();
|
|
options_str = getenv("MPIWRAP_DEBUG");
|
|
if (options_str) {
|
|
if (NULL != strstr(options_str, "warn"))
|
|
opt_missing = 1;
|
|
if (NULL != strstr(options_str, "strict"))
|
|
opt_missing = 2;
|
|
if (NULL != strstr(options_str, "verbose"))
|
|
opt_verbosity++;
|
|
if (NULL != strstr(options_str, "quiet"))
|
|
opt_verbosity--;
|
|
if (NULL != strstr(options_str, "help"))
|
|
opt_help = True;
|
|
if (NULL != strstr(options_str, "initkludge"))
|
|
opt_initkludge = True;
|
|
}
|
|
if (opt_verbosity > 0)
|
|
fprintf(stderr, "%s %5d: Active for pid %d\n",
|
|
preamble, my_pid, my_pid);
|
|
/* Sanity check - that Word/UWord really are machine words. */
|
|
assert(sizeof(Word) == sizeof(void*));
|
|
assert(sizeof(UWord) == sizeof(void*));
|
|
/* Sanity check - char is byte-sized (else address calculations
|
|
in walk_type don't work. */
|
|
assert(sizeof(char) == 1);
|
|
if (opt_help) {
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "Valid options for the MPIWRAP_DEBUG environment"
|
|
" variable are:\n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, " quiet be silent except for errors\n");
|
|
fprintf(stderr, " verbose show wrapper entries/exits\n");
|
|
fprintf(stderr, " strict abort the program if a function"
|
|
" with no wrapper is used\n");
|
|
fprintf(stderr, " warn give a warning if a function"
|
|
" with no wrapper is used\n");
|
|
fprintf(stderr, " help display this message, then exit\n");
|
|
fprintf(stderr, " initkludge debugging hack; do not use\n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "Multiple options are allowed, eg"
|
|
" MPIWRAP_DEBUG=strict,verbose\n");
|
|
fprintf(stderr, "Note: 'warn' generates output even if 'quiet'"
|
|
" is also specified\n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "%s %5d: exiting now\n", preamble, my_pid );
|
|
exit(1);
|
|
}
|
|
if (opt_verbosity > 0)
|
|
fprintf(stderr,
|
|
"%s %5d: Try MPIWRAP_DEBUG=help for possible options\n",
|
|
preamble, my_pid);
|
|
|
|
}
|
|
if (opt_verbosity > 1)
|
|
fprintf(stderr, "%s %5d: enter PMPI_%s\n", preamble, my_pid, fnname );
|
|
}
|
|
|
|
static __inline__ void after ( char* fnname, int err )
|
|
{
|
|
if (opt_verbosity > 1)
|
|
fprintf(stderr, "%s %5d: exit PMPI_%s (err = %d)\n",
|
|
preamble, my_pid, fnname, err );
|
|
}
|
|
|
|
static void barf ( char* msg )
|
|
{
|
|
fprintf(stderr, "%s %5d: fatal: %s\n", preamble, my_pid, msg);
|
|
fprintf(stderr, "%s %5d: exiting now\n", preamble, my_pid );
|
|
exit(1);
|
|
}
|
|
|
|
/* Half-hearted type-showing function (for debugging). */
|
|
static void showTy ( FILE* f, MPI_Datatype ty )
|
|
{
|
|
if (ty == MPI_DATATYPE_NULL) fprintf(f,"DATATYPE_NULL");
|
|
else if (ty == MPI_BYTE) fprintf(f,"BYTE");
|
|
else if (ty == MPI_PACKED) fprintf(f,"PACKED");
|
|
else if (ty == MPI_CHAR) fprintf(f,"CHAR");
|
|
else if (ty == MPI_SHORT) fprintf(f,"SHORT");
|
|
else if (ty == MPI_INT) fprintf(f,"INT");
|
|
else if (ty == MPI_LONG) fprintf(f,"LONG");
|
|
else if (ty == MPI_FLOAT) fprintf(f,"FLOAT");
|
|
else if (ty == MPI_DOUBLE) fprintf(f,"DOUBLE");
|
|
else if (ty == MPI_LONG_DOUBLE) fprintf(f,"LONG_DOUBLE");
|
|
else if (ty == MPI_UNSIGNED_CHAR) fprintf(f,"UNSIGNED_CHAR");
|
|
else if (ty == MPI_UNSIGNED_SHORT) fprintf(f,"UNSIGNED_SHORT");
|
|
else if (ty == MPI_UNSIGNED_LONG) fprintf(f,"UNSIGNED_LONG");
|
|
else if (ty == MPI_UNSIGNED) fprintf(f,"UNSIGNED");
|
|
else if (ty == MPI_FLOAT_INT) fprintf(f,"FLOAT_INT");
|
|
else if (ty == MPI_DOUBLE_INT) fprintf(f,"DOUBLE_INT");
|
|
else if (ty == MPI_LONG_DOUBLE_INT) fprintf(f,"LONG_DOUBLE_INT");
|
|
else if (ty == MPI_LONG_INT) fprintf(f,"LONG_INT");
|
|
else if (ty == MPI_SHORT_INT) fprintf(f,"SHORT_INT");
|
|
else if (ty == MPI_2INT) fprintf(f,"2INT");
|
|
else if (ty == MPI_UB) fprintf(f,"UB");
|
|
else if (ty == MPI_LB) fprintf(f,"LB");
|
|
# if defined(MPI_WCHAR)
|
|
else if (ty == MPI_WCHAR) fprintf(f,"WCHAR");
|
|
# endif
|
|
else if (ty == MPI_LONG_LONG_INT) fprintf(f,"LONG_LONG_INT");
|
|
# if defined(MPI_LONG_LONG)
|
|
else if (ty == MPI_LONG_LONG) fprintf(f,"LONG_LONG");
|
|
# endif
|
|
# if defined(MPI_UNSIGNED_LONG_LONG)
|
|
else if (ty == MPI_UNSIGNED_LONG_LONG) fprintf(f,"UNSIGNED_LONG_LONG");
|
|
# endif
|
|
# if defined(MPI_REAL8)
|
|
else if (ty == MPI_REAL8) fprintf(f, "REAL8");
|
|
# endif
|
|
# if defined(MPI_REAL4)
|
|
else if (ty == MPI_REAL4) fprintf(f, "REAL4");
|
|
# endif
|
|
# if defined(MPI_REAL)
|
|
else if (ty == MPI_REAL) fprintf(f, "REAL");
|
|
# endif
|
|
# if defined(MPI_INTEGER8)
|
|
else if (ty == MPI_INTEGER8) fprintf(f, "INTEGER8");
|
|
# endif
|
|
# if defined(MPI_INTEGER4)
|
|
else if (ty == MPI_INTEGER4) fprintf(f, "INTEGER4");
|
|
# endif
|
|
# if defined(MPI_INTEGER)
|
|
else if (ty == MPI_INTEGER) fprintf(f, "INTEGER");
|
|
# endif
|
|
# if defined(MPI_DOUBLE_PRECISION)
|
|
else if (ty == MPI_DOUBLE_PRECISION) fprintf(f, "DOUBLE_PRECISION");
|
|
# endif
|
|
# if defined(MPI_COMPLEX)
|
|
else if (ty == MPI_COMPLEX) fprintf(f, "COMPLEX");
|
|
# endif
|
|
# if defined(MPI_DOUBLE_COMPLEX)
|
|
else if (ty == MPI_DOUBLE_COMPLEX) fprintf(f, "DOUBLE_COMPLEX");
|
|
# endif
|
|
# if defined(MPI_LOGICAL)
|
|
else if (ty == MPI_LOGICAL) fprintf(f, "LOGICAL");
|
|
# endif
|
|
# if defined(MPI_2INTEGER)
|
|
else if (ty == MPI_2INTEGER) fprintf(f, "2INTEGER");
|
|
# endif
|
|
# if defined(MPI_2COMPLEX)
|
|
else if (ty == MPI_2COMPLEX) fprintf(f, "2COMPLEX");
|
|
# endif
|
|
# if defined(MPI_2DOUBLE_COMPLEX)
|
|
else if (ty == MPI_2DOUBLE_COMPLEX) fprintf(f, "2DOUBLE_COMPLEX");
|
|
# endif
|
|
# if defined(MPI_2REAL)
|
|
else if (ty == MPI_2REAL) fprintf(f, "2REAL");
|
|
# endif
|
|
# if defined(MPI_2DOUBLE_PRECISION)
|
|
else if (ty == MPI_2DOUBLE_PRECISION) fprintf(f, "2DOUBLE_PRECISION");
|
|
# endif
|
|
# if defined(MPI_CHARACTER)
|
|
else if (ty == MPI_CHARACTER) fprintf(f, "CHARACTER");
|
|
# endif
|
|
else fprintf(f,"showTy:???");
|
|
}
|
|
|
|
static void showCombiner ( FILE* f, int combiner )
|
|
{
|
|
switch (combiner) {
|
|
case MPI_COMBINER_NAMED: fprintf(f, "NAMED"); break;
|
|
#if defined(MPI_COMBINER_DUP)
|
|
case MPI_COMBINER_DUP: fprintf(f, "DUP"); break;
|
|
# endif
|
|
case MPI_COMBINER_CONTIGUOUS: fprintf(f, "CONTIGUOUS"); break;
|
|
case MPI_COMBINER_VECTOR: fprintf(f, "VECTOR"); break;
|
|
#if defined(MPI_COMBINER_HVECTOR_INTEGER)
|
|
case MPI_COMBINER_HVECTOR_INTEGER: fprintf(f, "HVECTOR_INTEGER"); break;
|
|
# endif
|
|
case MPI_COMBINER_HVECTOR: fprintf(f, "HVECTOR"); break;
|
|
case MPI_COMBINER_INDEXED: fprintf(f, "INDEXED"); break;
|
|
#if defined(MPI_COMBINER_HINDEXED_INTEGER)
|
|
case MPI_COMBINER_HINDEXED_INTEGER: fprintf(f, "HINDEXED_INTEGER"); break;
|
|
# endif
|
|
case MPI_COMBINER_HINDEXED: fprintf(f, "HINDEXED"); break;
|
|
#if defined(MPI_COMBINER_INDEXED_BLOCK)
|
|
case MPI_COMBINER_INDEXED_BLOCK: fprintf(f, "INDEXED_BLOCK"); break;
|
|
# endif
|
|
#if defined(MPI_COMBINER_STRUCT_INTEGER)
|
|
case MPI_COMBINER_STRUCT_INTEGER: fprintf(f, "STRUCT_INTEGER"); break;
|
|
# endif
|
|
case MPI_COMBINER_STRUCT: fprintf(f, "STRUCT"); break;
|
|
#if defined(MPI_COMBINER_SUBARRAY)
|
|
case MPI_COMBINER_SUBARRAY: fprintf(f, "SUBARRAY"); break;
|
|
# endif
|
|
#if defined(MPI_COMBINER_DARRAY)
|
|
case MPI_COMBINER_DARRAY: fprintf(f, "DARRAY"); break;
|
|
# endif
|
|
#if defined(MPI_COMBINER_F90_REAL)
|
|
case MPI_COMBINER_F90_REAL: fprintf(f, "F90_REAL"); break;
|
|
# endif
|
|
#if defined(MPI_COMBINER_F90_COMPLEX)
|
|
case MPI_COMBINER_F90_COMPLEX: fprintf(f, "F90_COMPLEX"); break;
|
|
# endif
|
|
#if defined(MPI_COMBINER_F90_INTEGER)
|
|
case MPI_COMBINER_F90_INTEGER: fprintf(f, "F90_INTEGER"); break;
|
|
# endif
|
|
#if defined(MPI_COMBINER_RESIZED)
|
|
case MPI_COMBINER_RESIZED: fprintf(f, "RESIZED"); break;
|
|
# endif
|
|
default: fprintf(f, "showCombiner:??"); break;
|
|
}
|
|
}
|
|
|
|
|
|
/* ------ Get useful bits of info ------ */
|
|
|
|
/* Note, PMPI_Comm_rank/size are themselves wrapped. Should work
|
|
fine. */
|
|
|
|
static __inline__ int comm_rank ( MPI_Comm comm )
|
|
{
|
|
int err, r;
|
|
err = PMPI_Comm_rank(comm, &r);
|
|
return err ? 0/*arbitrary*/ : r;
|
|
}
|
|
|
|
static __inline__ int comm_size ( MPI_Comm comm )
|
|
{
|
|
int err, r;
|
|
err = PMPI_Comm_size(comm, &r);
|
|
return err ? 0/*arbitrary*/ : r;
|
|
}
|
|
|
|
static __inline__ Bool count_from_Status( /*OUT*/int* recv_count,
|
|
MPI_Datatype datatype,
|
|
MPI_Status* status)
|
|
{
|
|
int n;
|
|
int err = PMPI_Get_count(status, datatype, &n);
|
|
if (err == MPI_SUCCESS) {
|
|
*recv_count = n;
|
|
return True;
|
|
} else {
|
|
return False;
|
|
}
|
|
}
|
|
|
|
/* It's critical that we can do equality on MPI_Requests.
|
|
Unfortunately these are opaque objects to us (handles, in the
|
|
parlance of the MPI 1.1 spec). Fortunately Sec 2.4.1 ("Opaque
|
|
Objects") specifies that "In C, [...] These [handles] should be
|
|
types that support assignment and equality operations." Hence the
|
|
following function should compile for any compliant definition of
|
|
MPI_Request. */
|
|
static __inline__
|
|
Bool eq_MPI_Request ( MPI_Request r1, MPI_Request r2 )
|
|
{
|
|
return r1 == r2;
|
|
}
|
|
|
|
/* Get the 'extent' of a type. Note, as per the MPI spec this
|
|
includes whatever padding would be required when using 'ty' in an
|
|
array. */
|
|
static long extentOfTy ( MPI_Datatype ty )
|
|
{
|
|
int r;
|
|
MPI_Aint n;
|
|
r = PMPI_Type_extent(ty, &n);
|
|
assert(r == MPI_SUCCESS);
|
|
return (long)n;
|
|
}
|
|
|
|
/* Free up *ty, if it is safe to do so */
|
|
static void maybeFreeTy ( MPI_Datatype* ty )
|
|
{
|
|
int r, n_ints, n_addrs, n_dtys, tycon;
|
|
|
|
r = PMPI_Type_get_envelope( *ty, &n_ints, &n_addrs, &n_dtys, &tycon );
|
|
assert(r == MPI_SUCCESS);
|
|
|
|
/* can't free named types */
|
|
if (tycon == MPI_COMBINER_NAMED)
|
|
return;
|
|
|
|
/* some kinds of structs are predefined so we can't free them
|
|
either. */
|
|
if (*ty == MPI_FLOAT_INT || *ty == MPI_DOUBLE_INT
|
|
|| *ty == MPI_LONG_INT || *ty == MPI_2INT
|
|
|| *ty == MPI_SHORT_INT || *ty == MPI_LONG_DOUBLE_INT)
|
|
return;
|
|
|
|
/* Looks OK - free it. */
|
|
if (0) {
|
|
/* show me what you're about to free .. */
|
|
fprintf(stderr, "freeing combiner ");
|
|
showCombiner(stderr,tycon);
|
|
fprintf(stderr, " ty= ");
|
|
showTy(stderr,*ty);
|
|
fprintf(stderr,"\n");
|
|
}
|
|
r = PMPI_Type_free(ty);
|
|
assert(r == MPI_SUCCESS);
|
|
}
|
|
|
|
/* How big is a "named" (base) type? Returns 0 if not known. Note.
|
|
There is a subtlety, which is that this is required to return the
|
|
exact size of one item of the type, NOT the size of it when padded
|
|
suitably to make an array of them. In particular that's why the
|
|
size of LONG_DOUBLE is computed by looking at the result of doing a
|
|
long double store, rather than just asking what is the sizeof(long
|
|
double).
|
|
|
|
For LONG_DOUBLE on x86-linux and amd64-linux my impression is that
|
|
the right answer is 10 even though sizeof(long double) says 12 and
|
|
16 respectively. On ppc32-linux it appears to be 16.
|
|
|
|
Ref: MPI 1.1 doc p18 */
|
|
static long sizeofOneNamedTy ( MPI_Datatype ty )
|
|
{
|
|
if (ty == MPI_CHAR) return sizeof(signed char);
|
|
if (ty == MPI_SHORT) return sizeof(signed short int);
|
|
if (ty == MPI_INT) return sizeof(signed int);
|
|
if (ty == MPI_LONG) return sizeof(signed long int);
|
|
if (ty == MPI_UNSIGNED_CHAR) return sizeof(unsigned char);
|
|
if (ty == MPI_UNSIGNED_SHORT) return sizeof(unsigned short int);
|
|
if (ty == MPI_UNSIGNED) return sizeof(unsigned int);
|
|
if (ty == MPI_UNSIGNED_LONG) return sizeof(unsigned long int);
|
|
if (ty == MPI_FLOAT) return sizeof(float);
|
|
if (ty == MPI_DOUBLE) return sizeof(double);
|
|
if (ty == MPI_BYTE) return 1;
|
|
if (ty == MPI_LONG_DOUBLE) return sizeof_long_double_image();
|
|
if (ty == MPI_PACKED) return 1;
|
|
if (ty == MPI_LONG_LONG_INT) return sizeof(signed long long int);
|
|
|
|
# if defined(MPI_REAL8)
|
|
if (ty == MPI_REAL8) return 8; /* MPI2 spec */;
|
|
# endif
|
|
# if defined(MPI_REAL4)
|
|
if (ty == MPI_REAL4) return 4; /* MPI2 spec */;
|
|
# endif
|
|
# if defined(MPI_REAL)
|
|
if (ty == MPI_REAL) return 4; /* MPI2 spec */;
|
|
# endif
|
|
# if defined(MPI_INTEGER8)
|
|
if (ty == MPI_INTEGER8) return 8; /* MPI2 spec */;
|
|
# endif
|
|
# if defined(MPI_INTEGER4)
|
|
if (ty == MPI_INTEGER4) return 4; /* MPI2 spec */;
|
|
# endif
|
|
# if defined(MPI_INTEGER)
|
|
if (ty == MPI_INTEGER) return 4; /* MPI2 spec */;
|
|
# endif
|
|
# if defined(MPI_DOUBLE_PRECISION)
|
|
if (ty == MPI_DOUBLE_PRECISION) return 8; /* MPI2 spec */;
|
|
# endif
|
|
|
|
/* new in MPI2: */
|
|
# if defined(MPI_WCHAR)
|
|
if (ty == MPI_WCHAR) return 2; /* MPI2 spec */;
|
|
# endif
|
|
# if defined(MPI_SIGNED_CHAR)
|
|
if (ty == MPI_SIGNED_CHAR) return 1; /* MPI2 spec */;
|
|
# endif
|
|
# if defined(MPI_UNSIGNED_LONG_LONG)
|
|
if (ty == MPI_UNSIGNED_LONG_LONG) return 8; /* MPI2 spec */;
|
|
# endif
|
|
# if defined(MPI_COMPLEX)
|
|
if (ty == MPI_COMPLEX) return 2 * 4; /* MPI2 spec */
|
|
# endif
|
|
# if defined(MPI_DOUBLE_COMPLEX)
|
|
if (ty == MPI_DOUBLE_COMPLEX) return 2 * 8; /* MPI2 spec */
|
|
# endif
|
|
# if defined(MPI_LOGICAL)
|
|
if (ty == MPI_LOGICAL) return 4; /* MPI2 spec */
|
|
# endif
|
|
# if defined(MPI_2INTEGER)
|
|
if (ty == MPI_2INTEGER) return 2 * 4; /* undocumented in MPI2 */
|
|
# endif
|
|
# if defined(MPI_2COMPLEX)
|
|
if (ty == MPI_2COMPLEX) return 2 * 8; /* undocumented in MPI2 */
|
|
# endif
|
|
# if defined(MPI_2DOUBLE_COMPLEX)
|
|
/* 32: this is how openmpi-1.2.2 behaves on x86-linux, but I have
|
|
really no idea if this is right. */
|
|
if (ty == MPI_2DOUBLE_COMPLEX) return 32; /* undocumented in MPI2 */
|
|
# endif
|
|
# if defined(MPI_2REAL)
|
|
if (ty == MPI_2REAL) return 2 * 4; /* undocumented in MPI2 */
|
|
# endif
|
|
# if defined(MPI_2DOUBLE_PRECISION)
|
|
if (ty == MPI_2DOUBLE_PRECISION) return 2 * 8; /* undocumented in MPI2 */
|
|
# endif
|
|
# if defined(MPI_CHARACTER)
|
|
if (ty == MPI_CHARACTER) return 1; /* MPI2 spec */
|
|
# endif
|
|
|
|
/* Note: the following are named structs, not named basic types,
|
|
and so are not handled here:
|
|
FLOAT_INT DOUBLE_INT LONG_INT 2INT SHORT_INT LONG_DOUBLE_INT
|
|
My guess is they are probably for doing max-w-index style
|
|
reductions, the INT carrying the index of the max/min and the
|
|
other type its actual value.
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Find the size of long double image (not 'sizeof(long double)').
|
|
See comments in sizeofOneNamedTy.
|
|
*/
|
|
static long sizeof_long_double_image ( void )
|
|
{
|
|
long i;
|
|
unsigned char* p;
|
|
static long cached_result = 0;
|
|
|
|
/* Hopefully we have it already. */
|
|
if (cached_result != 0) {
|
|
assert(cached_result == 10 || cached_result == 16 || cached_result == 8);
|
|
return cached_result;
|
|
}
|
|
|
|
/* No? Then we'll have to compute it. This isn't thread-safe but
|
|
it doesn't really matter since all races to compute it should
|
|
produce the same answer. */
|
|
p = malloc(64);
|
|
assert(p);
|
|
for (i = 0; i < 64; i++)
|
|
p[i] = 0x55;
|
|
|
|
/* Write a value which isn't known at compile time and therefore
|
|
must come out of a register. If we just store a constant here,
|
|
some compilers write more data than a store from a machine
|
|
register would. Therefore we have to force a store from a
|
|
machine register by storing a value which isn't known at compile
|
|
time. Since getpid() will return a value < 1 million, turn it
|
|
into a zero by dividing by 1e+30. */
|
|
*(long double*)(&p[16]) = (long double)(1.0e-30 * (double)getpid());
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
assert(p[i] == 0x55);
|
|
assert(p[i+48] == 0x55);
|
|
}
|
|
for (i = 16; i <= 48; i++) {
|
|
if (p[i] == 0x55)
|
|
break;
|
|
}
|
|
|
|
assert(i < 48);
|
|
assert(i > 16);
|
|
free(p);
|
|
cached_result = i - 16;
|
|
|
|
if (0)
|
|
printf("sizeof_long_double_image: computed %d\n", (int)cached_result);
|
|
|
|
assert(cached_result == 10 || cached_result == 16 || cached_result == 8);
|
|
return cached_result;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Unpicking datatypes ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
static __inline__
|
|
void walk_type_array ( void(*f)(void*,long), char* base,
|
|
MPI_Datatype ty, long count );
|
|
|
|
|
|
/* Walk over all fragments of the object of type 'ty' with base
|
|
address 'base', and apply 'f' to the start/length of each
|
|
contiguous fragment. */
|
|
static
|
|
void walk_type ( void(*f)(void*,long), char* base, MPI_Datatype ty )
|
|
{
|
|
int r, n_ints, n_addrs, n_dtys, tycon;
|
|
long ex, i;
|
|
int* ints = NULL;
|
|
MPI_Aint* addrs = NULL;
|
|
MPI_Datatype* dtys = NULL;
|
|
|
|
/* Stuff for limiting how much complaining text it spews out */
|
|
static int complaints = 3;
|
|
static int last_complained_about_tycon = -987654321; /* presumably bogus */
|
|
|
|
if (0)
|
|
printf("walk_type %p\n", (void*)(unsigned long)ty);
|
|
|
|
r = PMPI_Type_get_envelope( ty, &n_ints, &n_addrs, &n_dtys, &tycon );
|
|
assert(r == MPI_SUCCESS);
|
|
|
|
/* Handle the base cases fast(er/ish). */
|
|
if (tycon == MPI_COMBINER_NAMED) {
|
|
long sz = sizeofOneNamedTy(ty);
|
|
if (sz > 0) {
|
|
f(base, sz);
|
|
return;
|
|
}
|
|
/* Hmm. Perhaps it's a named struct? Unfortunately we can't
|
|
take them to bits so we have to do a really ugly hack, which
|
|
makes assumptions about how the MPI implementation has laid
|
|
out these types. At least Open MPI 1.0.1 appears to put
|
|
the 'val' field first. MPICH2 agrees.
|
|
*/
|
|
if (ty == MPI_2INT) {
|
|
typedef struct { int val; int loc; } Ty;
|
|
f(base + offsetof(Ty,val), sizeof(int));
|
|
f(base + offsetof(Ty,loc), sizeof(int));
|
|
return;
|
|
}
|
|
if (ty == MPI_LONG_INT) {
|
|
typedef struct { long val; int loc; } Ty;
|
|
f(base + offsetof(Ty,val), sizeof(long));
|
|
f(base + offsetof(Ty,loc), sizeof(int));
|
|
return;
|
|
}
|
|
if (ty == MPI_DOUBLE_INT) {
|
|
typedef struct { double val; int loc; } Ty;
|
|
f(base + offsetof(Ty,val), sizeof(double));
|
|
f(base + offsetof(Ty,loc), sizeof(int));
|
|
return;
|
|
}
|
|
if (ty == MPI_SHORT_INT) {
|
|
typedef struct { short val; int loc; } Ty;
|
|
f(base + offsetof(Ty,val), sizeof(short));
|
|
f(base + offsetof(Ty,loc), sizeof(int));
|
|
return;
|
|
}
|
|
if (ty == MPI_FLOAT_INT) {
|
|
typedef struct { float val; int loc; } Ty;
|
|
f(base + offsetof(Ty,val), sizeof(float));
|
|
f(base + offsetof(Ty,loc), sizeof(int));
|
|
return;
|
|
}
|
|
if (ty == MPI_LONG_DOUBLE_INT) {
|
|
typedef struct { long double val; int loc; } Ty;
|
|
f(base + offsetof(Ty,val), sizeof_long_double_image());
|
|
f(base + offsetof(Ty,loc), sizeof(int));
|
|
return;
|
|
}
|
|
if (ty == MPI_LB || ty == MPI_UB)
|
|
return; /* have zero size, so nothing needs to be done */
|
|
goto unhandled;
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
if (0) {
|
|
ex = extentOfTy(ty);
|
|
printf("tycon 0x%llx %d %d %d (ext %d)\n",
|
|
(unsigned long long int)tycon,
|
|
n_ints, n_addrs, n_dtys, (int)ex );
|
|
}
|
|
|
|
/* Now safe to do MPI_Type_get_contents */
|
|
assert(n_ints >= 0);
|
|
assert(n_addrs >= 0);
|
|
assert(n_dtys >= 0);
|
|
|
|
if (n_ints > 0) {
|
|
ints = malloc(n_ints * sizeof(int));
|
|
assert(ints);
|
|
}
|
|
if (n_addrs > 0) {
|
|
addrs = malloc(n_addrs * sizeof(MPI_Aint));
|
|
assert(addrs);
|
|
}
|
|
if (n_dtys > 0) {
|
|
dtys = malloc(n_dtys * sizeof(MPI_Datatype));
|
|
assert(dtys);
|
|
}
|
|
|
|
r = PMPI_Type_get_contents( ty, n_ints, n_addrs, n_dtys,
|
|
ints, addrs, dtys );
|
|
assert(r == MPI_SUCCESS);
|
|
|
|
switch (tycon) {
|
|
|
|
case MPI_COMBINER_CONTIGUOUS:
|
|
assert(n_ints == 1 && n_addrs == 0 && n_dtys == 1);
|
|
walk_type_array( f, base, dtys[0], ints[0] );
|
|
maybeFreeTy( &dtys[0] );
|
|
break;
|
|
|
|
case MPI_COMBINER_VECTOR:
|
|
assert(n_ints == 3 && n_addrs == 0 && n_dtys == 1);
|
|
ex = extentOfTy(dtys[0]);
|
|
if (0)
|
|
printf("vector count %d x (bl %d stride %d)\n",
|
|
(int)ints[0], (int)ints[1], (int)ints[2]);
|
|
for (i = 0; i < ints[0]; i++) {
|
|
walk_type_array( f, base + i * ints[2]/*stride*/ * ex,
|
|
dtys[0], ints[1]/*blocklength*/ );
|
|
}
|
|
maybeFreeTy( &dtys[0] );
|
|
break;
|
|
|
|
case MPI_COMBINER_HVECTOR:
|
|
assert(n_ints == 2 && n_addrs == 1 && n_dtys == 1);
|
|
ex = extentOfTy(dtys[0]);
|
|
if (0)
|
|
printf("hvector count %d x (bl %d hstride %d)\n",
|
|
(int)ints[0], (int)ints[1], (int)addrs[0]);
|
|
for (i = 0; i < ints[0]; i++) {
|
|
walk_type_array( f, base + i * addrs[0]/*hstride*/,
|
|
dtys[0], ints[1]/*blocklength*/ );
|
|
}
|
|
maybeFreeTy( &dtys[0] );
|
|
break;
|
|
|
|
case MPI_COMBINER_INDEXED:
|
|
assert(n_addrs == 0 && n_dtys == 1);
|
|
assert(n_ints > 0);
|
|
assert(n_ints == 2 * ints[0] + 1);
|
|
ex = extentOfTy(dtys[0]);
|
|
for (i = 0; i < ints[0]; i++) {
|
|
if (0)
|
|
printf("indexed (elem %d) off %d copies %d\n",
|
|
(int)i, ints[i+1+ints[0]], ints[i+1] );
|
|
walk_type_array( f, base + ex * ints[i+1+ints[0]],
|
|
dtys[0], ints[i+1] );
|
|
}
|
|
maybeFreeTy( &dtys[0] );
|
|
break;
|
|
|
|
case MPI_COMBINER_HINDEXED:
|
|
assert(n_ints > 0);
|
|
assert(n_ints == ints[0] + 1);
|
|
assert(n_addrs == ints[0] && n_dtys == 1);
|
|
ex = extentOfTy(dtys[0]);
|
|
for (i = 0; i < ints[0]; i++) {
|
|
if (0)
|
|
printf("hindexed (elem %d) hoff %d copies %d\n",
|
|
(int)i, (int)addrs[i], ints[i+1] );
|
|
walk_type_array( f, base + addrs[i],
|
|
dtys[0], ints[i+1] );
|
|
}
|
|
maybeFreeTy( &dtys[0] );
|
|
break;
|
|
|
|
case MPI_COMBINER_STRUCT:
|
|
assert(n_addrs == n_ints-1);
|
|
assert(n_dtys == n_ints-1);
|
|
assert(n_ints > 0);
|
|
assert(n_ints == ints[0] + 1);
|
|
for (i = 0; i < ints[0]; i++) {
|
|
if (0)
|
|
printf("struct (elem %d limit %d) hoff %d copies %d\n",
|
|
(int)i, (int)ints[0], (int)addrs[i], (int)ints[i+1]);
|
|
walk_type_array( f, base + addrs[i], dtys[i], (long)ints[i+1] );
|
|
maybeFreeTy( &dtys[i] );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
goto unhandled;
|
|
|
|
}
|
|
|
|
/* normal exit */
|
|
if (ints) free(ints);
|
|
if (addrs) free(addrs);
|
|
if (dtys) free(dtys);
|
|
return;
|
|
|
|
unhandled:
|
|
/* Complain, but limit the amount of complaining that can happen to
|
|
the first 3 different unhandled tycons that show up, so as to
|
|
avoid swamping users with thousands of duplicate messages. */
|
|
if (complaints > 0 && tycon != last_complained_about_tycon) {
|
|
complaints--;
|
|
last_complained_about_tycon = tycon;
|
|
if (tycon == MPI_COMBINER_NAMED) {
|
|
fprintf(stderr, "%s %5d: walk_type: unhandled base type 0x%lx ",
|
|
preamble, my_pid, (long)ty);
|
|
showTy(stderr, ty);
|
|
fprintf(stderr, "\n");
|
|
} else {
|
|
fprintf(stderr, "%s %5d: walk_type: unhandled combiner 0x%lx\n",
|
|
preamble, my_pid, (long)tycon);
|
|
}
|
|
}
|
|
if (ints) free(ints);
|
|
if (addrs) free(addrs);
|
|
if (dtys) free(dtys);
|
|
if (opt_missing >= 2)
|
|
barf("walk_type: unhandled combiner, strict checking selected");
|
|
}
|
|
|
|
|
|
/* Same as walk_type but apply 'f' to every element in an array of
|
|
'count' items starting at 'base'. The only purpose of pushing this
|
|
into a different routine is so it can attempt to optimise the case
|
|
where the array elements are contiguous and packed together without
|
|
holes. */
|
|
static __inline__
|
|
void walk_type_array ( void(*f)(void*,long), char* base,
|
|
MPI_Datatype elemTy, long count )
|
|
{
|
|
long i, ex;
|
|
|
|
assert(sizeof(unsigned long) == sizeof(char*));
|
|
|
|
/* First see if we can do this the fast way. */
|
|
ex = sizeofOneNamedTy(elemTy);
|
|
|
|
if ( /* ty is a primitive type with power-of-2 size */
|
|
(ex == 8 || ex == 4 || ex == 2 || ex == 1)
|
|
&& /* base is suitably aligned for ty */
|
|
( ((unsigned long)base) & (ex-1)) == 0) {
|
|
|
|
/* We're sure it's contiguous, so just paint/check it in one
|
|
go. */
|
|
if (0) printf("walk_type_array fast %ld of size %ld\n", count, ex );
|
|
f ( base, count * ex );
|
|
|
|
} else {
|
|
|
|
/* Bad news. We have to futz with each element individually.
|
|
This could be very expensive.
|
|
|
|
Note: subtle. If ty is LONG_DOUBLE then the extent will be
|
|
12, so the following loop will jump along in steps of 12, but
|
|
the size painted by walk_type will be 10 since it uses
|
|
sizeofOneNamedTy to establish the size of base types. Which
|
|
is what we need to happen. */
|
|
ex = extentOfTy(elemTy);
|
|
if (0) printf("walk_type_array SLOW %ld of size %ld\n", count, ex );
|
|
for (i = 0; i < count; i++)
|
|
walk_type( f, base + i * ex, elemTy );
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/* Hook so it's visible from outside (can be handy to dlopen/dlsym
|
|
it) */
|
|
void mpiwrap_walk_type_EXTERNALLY_VISIBLE
|
|
( void(*f)(void*,long), char* base, MPI_Datatype ty )
|
|
{
|
|
walk_type(f, base, ty);
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Address-range helpers ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* ----------------
|
|
Do corresponding checks on memory areas defined using a
|
|
straightforward (start, length) description.
|
|
----------------
|
|
*/
|
|
|
|
static __inline__
|
|
void check_mem_is_defined_untyped ( void* buffer, long nbytes )
|
|
{
|
|
if (nbytes > 0) {
|
|
VALGRIND_CHECK_MEM_IS_DEFINED(buffer, nbytes);
|
|
}
|
|
}
|
|
|
|
static __inline__
|
|
void check_mem_is_addressable_untyped ( void* buffer, long nbytes )
|
|
{
|
|
if (nbytes > 0) {
|
|
VALGRIND_CHECK_MEM_IS_ADDRESSABLE(buffer, nbytes);
|
|
}
|
|
}
|
|
|
|
static __inline__
|
|
void make_mem_defined_if_addressable_untyped ( void* buffer, long nbytes )
|
|
{
|
|
if (nbytes > 0) {
|
|
VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(buffer, nbytes);
|
|
}
|
|
}
|
|
|
|
static __inline__
|
|
void make_mem_defined_if_addressable_if_success_untyped ( int err,
|
|
void* buffer, long nbytes )
|
|
{
|
|
if (err == MPI_SUCCESS && nbytes > 0) {
|
|
VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(buffer, nbytes);
|
|
}
|
|
}
|
|
|
|
|
|
/* ----------------
|
|
Do checks on memory areas defined using the MPI (buffer, count,
|
|
type) convention.
|
|
----------------
|
|
*/
|
|
|
|
/* Check that the specified area is both addressible and contains
|
|
initialised data, and cause V to complain if not. */
|
|
|
|
static __inline__
|
|
void check_mem_is_defined ( char* buffer, long count, MPI_Datatype datatype )
|
|
{
|
|
walk_type_array( check_mem_is_defined_untyped, buffer, datatype, count );
|
|
}
|
|
|
|
|
|
/* Check that the specified area is addressible, and cause V to
|
|
complain if not. Doesn't matter whether the data there is
|
|
initialised or not. */
|
|
|
|
static __inline__
|
|
void check_mem_is_addressable ( void *buffer, long count, MPI_Datatype datatype )
|
|
{
|
|
walk_type_array( check_mem_is_addressable_untyped, buffer, datatype, count );
|
|
}
|
|
|
|
|
|
/* Set the specified area to 'defined for each byte which is
|
|
addressible' state. */
|
|
|
|
static __inline__
|
|
void make_mem_defined_if_addressable ( void *buffer, int count, MPI_Datatype datatype )
|
|
{
|
|
walk_type_array( make_mem_defined_if_addressable_untyped,
|
|
buffer, datatype, count );
|
|
}
|
|
|
|
static __inline__
|
|
void
|
|
make_mem_defined_if_addressable_if_success ( int err, void *buffer, int count,
|
|
MPI_Datatype datatype )
|
|
{
|
|
if (err == MPI_SUCCESS)
|
|
make_mem_defined_if_addressable(buffer, count, datatype);
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- The wrappers proper. They are listed in the order ---*/
|
|
/*--- in which they appear in "MPI: A Message-Passing ---*/
|
|
/*--- Interface Standard, MPIF, Nov 15 2003" (the MPI 1.1 ---*/
|
|
/*--- spec. All unimplemented wrappers are listed at the ---*/
|
|
/*--- end of the file. The list of function names is ---*/
|
|
/*--- taken from the headers of Open MPI svn r9191. ---*/
|
|
/*--- Hopefully it is a complete list of all the MPI 2 ---*/
|
|
/*--- functions. ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* Handy abbreviation */
|
|
#define WRAPPER_FOR(name) I_WRAP_FNNAME_U(name)
|
|
|
|
/* Generates (conceptually) a wrapper which does nothing. In
|
|
fact just generate no wrapper at all. */
|
|
#define HAS_NO_WRAPPER(basename) /* */
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 3.2, Blocking Send and Receive Operations ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* --- {,B,S,R}Send --- */
|
|
/* pre: rd: (buf,count,datatype) */
|
|
static
|
|
int generic_Send(void *buf, int count, MPI_Datatype datatype,
|
|
int dest, int tag, MPI_Comm comm)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("{,B,S,R}Send");
|
|
check_mem_is_defined(buf, count, datatype);
|
|
CALL_FN_W_6W(err, fn, buf,count,datatype,dest,tag,comm);
|
|
after("{,B,S,R}Send", err);
|
|
return err;
|
|
}
|
|
int WRAPPER_FOR(PMPI_Send)(void *buf, int count, MPI_Datatype datatype,
|
|
int dest, int tag, MPI_Comm comm) {
|
|
return generic_Send(buf,count,datatype, dest,tag,comm);
|
|
}
|
|
int WRAPPER_FOR(PMPI_Bsend)(void *buf, int count, MPI_Datatype datatype,
|
|
int dest, int tag, MPI_Comm comm) {
|
|
return generic_Send(buf,count,datatype, dest,tag,comm);
|
|
}
|
|
int WRAPPER_FOR(PMPI_Ssend)(void *buf, int count, MPI_Datatype datatype,
|
|
int dest, int tag, MPI_Comm comm) {
|
|
return generic_Send(buf,count,datatype, dest,tag,comm);
|
|
}
|
|
int WRAPPER_FOR(PMPI_Rsend)(void *buf, int count, MPI_Datatype datatype,
|
|
int dest, int tag, MPI_Comm comm) {
|
|
return generic_Send(buf,count,datatype, dest,tag,comm);
|
|
}
|
|
|
|
/* --- Recv --- */
|
|
/* pre: must be writable: (buf,count,datatype)
|
|
must be writable: status
|
|
post: make readable: (buf,recv_count,datatype)
|
|
where recv_count is determined from *status
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Recv)(void *buf, int count, MPI_Datatype datatype,
|
|
int source, int tag,
|
|
MPI_Comm comm, MPI_Status *status)
|
|
{
|
|
OrigFn fn;
|
|
int err, recv_count = 0;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Recv");
|
|
check_mem_is_addressable(buf, count, datatype);
|
|
check_mem_is_addressable_untyped(status, sizeof(*status));
|
|
CALL_FN_W_7W(err, fn, buf,count,datatype,source,tag,comm,status);
|
|
if (err == MPI_SUCCESS && count_from_Status(&recv_count,datatype,status)) {
|
|
make_mem_defined_if_addressable(buf, recv_count, datatype);
|
|
}
|
|
after("Recv", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Get_count --- */
|
|
/* pre: must be readable: *status
|
|
post: make defined: *count -- don't bother, libmpi will surely do this
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Get_count)(MPI_Status* status,
|
|
MPI_Datatype ty, int* count )
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Get_count");
|
|
# if defined(_AIX)
|
|
check_mem_is_addressable_untyped(status, sizeof(*status));
|
|
# else
|
|
check_mem_is_defined_untyped(status, sizeof(*status));
|
|
# endif
|
|
CALL_FN_W_WWW(err, fn, status,ty,count);
|
|
after("Get_count", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 3.7, Nonblocking communication ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* Maintain a table that makes it possible for the wrappers to
|
|
complete MPI_Irecv successfully.
|
|
|
|
The issue is that MPI_Irecv states the recv buffer and returns
|
|
immediately, giving a handle (MPI_Request) for the transaction.
|
|
Later the user will have to poll for completion with MPI_Wait etc,
|
|
and at that point these wrappers have to paint the recv buffer.
|
|
But the recv buffer details are not presented to MPI_Wait - only
|
|
the handle is. We therefore have to use a shadow table
|
|
(sReqs{,_size,_used,_lock}) which associates uncompleted
|
|
MPI_Requests with the corresponding buffer address/count/type.
|
|
|
|
Only read requests are placed in the table, since there is no need
|
|
to do any buffer painting following completion of an Isend - all
|
|
the checks for that are done at the time Isend is called.
|
|
|
|
Care has to be take to remove completed requests from the table.
|
|
|
|
Access to the table is guarded by sReqs_lock so as to make it
|
|
thread-safe.
|
|
*/
|
|
|
|
typedef
|
|
struct {
|
|
Bool inUse;
|
|
MPI_Request key;
|
|
void* buf;
|
|
int count;
|
|
MPI_Datatype datatype;
|
|
}
|
|
ShadowRequest;
|
|
|
|
static ShadowRequest* sReqs = NULL;
|
|
static int sReqs_size = 0;
|
|
static int sReqs_used = 0;
|
|
static pthread_mutex_t sReqs_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
#define LOCK_SREQS \
|
|
do { int pr = pthread_mutex_lock(&sReqs_lock); \
|
|
assert(pr == 0); \
|
|
} while (0)
|
|
|
|
#define UNLOCK_SREQS \
|
|
do { int pr = pthread_mutex_unlock(&sReqs_lock); \
|
|
assert(pr == 0); \
|
|
} while (0)
|
|
|
|
|
|
/* Ensure the sReqs expandable array has at least one free slot, by
|
|
copying it into a larger one if necessary. NOTE: sReqs_lock is
|
|
held throughout this procedure.*/
|
|
static void ensure_sReq_space ( void )
|
|
{
|
|
int i;
|
|
ShadowRequest* sReqs2;
|
|
if (sReqs_used == sReqs_size) {
|
|
sReqs_size = sReqs_size==0 ? 2 : 2*sReqs_size;
|
|
sReqs2 = malloc( sReqs_size * sizeof(ShadowRequest) );
|
|
if (sReqs2 == NULL) {
|
|
UNLOCK_SREQS;
|
|
barf("add_shadow_Request: malloc failed.\n");
|
|
}
|
|
for (i = 0; i < sReqs_used; i++)
|
|
sReqs2[i] = sReqs[i];
|
|
if (sReqs)
|
|
free(sReqs);
|
|
sReqs = sReqs2;
|
|
}
|
|
assert(sReqs_used < sReqs_size);
|
|
}
|
|
|
|
|
|
/* Find shadow info for 'request', or NULL if none. */
|
|
|
|
static
|
|
ShadowRequest* find_shadow_Request ( MPI_Request request )
|
|
{
|
|
ShadowRequest* ret = NULL;
|
|
int i;
|
|
LOCK_SREQS;
|
|
for (i = 0; i < sReqs_used; i++) {
|
|
if (sReqs[i].inUse && eq_MPI_Request(sReqs[i].key,request)) {
|
|
ret = &sReqs[i];
|
|
break;
|
|
}
|
|
}
|
|
UNLOCK_SREQS;
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Delete shadow info for 'request', if any. */
|
|
|
|
static void delete_shadow_Request ( MPI_Request request )
|
|
{
|
|
int i;
|
|
LOCK_SREQS;
|
|
for (i = 0; i < sReqs_used; i++) {
|
|
if (sReqs[i].inUse && eq_MPI_Request(sReqs[i].key,request)) {
|
|
sReqs[i].inUse = False;
|
|
break;
|
|
}
|
|
}
|
|
UNLOCK_SREQS;
|
|
}
|
|
|
|
|
|
/* Add a shadow for 'request', overwriting any old binding for it. */
|
|
|
|
static
|
|
void add_shadow_Request( MPI_Request request,
|
|
void* buf, int count,
|
|
MPI_Datatype datatype )
|
|
{
|
|
int i, ix = -1;
|
|
LOCK_SREQS;
|
|
assert(sReqs_used >= 0);
|
|
assert(sReqs_size >= 0);
|
|
assert(sReqs_used <= sReqs_size);
|
|
if (sReqs == NULL) assert(sReqs_size == 0);
|
|
|
|
/* First of all see if we already have a binding for this key; if
|
|
so just replace it, and have done. */
|
|
for (i = 0; i < sReqs_used; i++) {
|
|
if (sReqs[i].inUse && eq_MPI_Request(sReqs[i].key,request)) {
|
|
ix = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ix < 0) {
|
|
/* Ok, we don't have it, so will have to add it. First search
|
|
to see if there is an existing empty slot. */
|
|
for (i = 0; i < sReqs_used; i++) {
|
|
if (!sReqs[i].inUse) {
|
|
ix = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* No empty slots. Allocate a new one. */
|
|
if (ix < 0) {
|
|
ensure_sReq_space();
|
|
assert(sReqs_used < sReqs_size);
|
|
ix = sReqs_used;
|
|
sReqs_used++;
|
|
}
|
|
|
|
assert(ix >= 0 && ix < sReqs_used);
|
|
assert(sReqs_used <= sReqs_size);
|
|
|
|
sReqs[ix].inUse = True;
|
|
sReqs[ix].key = request;
|
|
sReqs[ix].buf = buf;
|
|
sReqs[ix].count = count;
|
|
sReqs[ix].datatype = datatype;
|
|
|
|
UNLOCK_SREQS;
|
|
if (opt_verbosity > 1)
|
|
fprintf(stderr, "%s %5d: sReq+ 0x%lx -> b/c/d %p/%d/0x%lx [slot %d]\n",
|
|
preamble, my_pid, (unsigned long)request,
|
|
buf, count, (long)datatype, ix);
|
|
}
|
|
|
|
static
|
|
MPI_Request* clone_Request_array ( int count, MPI_Request* orig )
|
|
{
|
|
MPI_Request* copy;
|
|
int i;
|
|
LOCK_SREQS;
|
|
if (count < 0)
|
|
count = 0; /* Hmm. Call Mulder and Scully. */
|
|
copy = malloc( count * sizeof(MPI_Request) );
|
|
if (copy == NULL && count > 0) {
|
|
UNLOCK_SREQS;
|
|
barf("clone_Request_array: malloc failed");
|
|
}
|
|
for (i = 0; i < count; i++)
|
|
copy[i] = orig[i];
|
|
UNLOCK_SREQS;
|
|
return copy;
|
|
}
|
|
|
|
#undef LOCK_SREQS
|
|
#undef UNLOCK_SREQS
|
|
|
|
|
|
static void maybe_complete ( Bool error_in_status,
|
|
MPI_Request request_before,
|
|
MPI_Request request_after,
|
|
MPI_Status* status )
|
|
{
|
|
int recv_count = 0;
|
|
ShadowRequest* shadow;
|
|
/* How do we know if this is an Irecv request that has now
|
|
finished successfully?
|
|
|
|
request_before isn't MPI_REQUEST_NULL
|
|
and request_before is found in the shadow table
|
|
and request_after *is* MPI_REQUEST_NULL
|
|
and (if error_in_status then status.MPI_ERROR is MPI_SUCCESS)
|
|
|
|
(when error_in_status == False, then we expect not to get
|
|
called at all if there was an error.)
|
|
*/
|
|
if (request_before != MPI_REQUEST_NULL
|
|
&& request_after == MPI_REQUEST_NULL
|
|
&& (error_in_status ? status->MPI_ERROR == MPI_SUCCESS : True)
|
|
&& ( (shadow=find_shadow_Request(request_before)) != NULL) ) {
|
|
/* The Irecv detailed in 'shadow' completed. Paint the result
|
|
buffer, and delete the entry. */
|
|
if (count_from_Status(&recv_count, shadow->datatype, status)) {
|
|
make_mem_defined_if_addressable(shadow->buf, recv_count, shadow->datatype);
|
|
if (opt_verbosity > 1)
|
|
fprintf(stderr, "%s %5d: sReq- %p (completed)\n",
|
|
preamble, my_pid, request_before);
|
|
}
|
|
delete_shadow_Request(request_before);
|
|
}
|
|
}
|
|
|
|
|
|
/* --- Isend --- */
|
|
/* rd: (buf,count,datatype) */
|
|
/* wr: *request */
|
|
static __inline__
|
|
int generic_Isend(void *buf, int count, MPI_Datatype datatype,
|
|
int dest, int tag, MPI_Comm comm,
|
|
MPI_Request* request)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("{,B,S,R}Isend");
|
|
check_mem_is_defined(buf, count, datatype);
|
|
check_mem_is_addressable_untyped(request, sizeof(*request));
|
|
CALL_FN_W_7W(err, fn, buf,count,datatype,dest,tag,comm,request);
|
|
make_mem_defined_if_addressable_if_success_untyped(err, request, sizeof(*request));
|
|
after("{,B,S,R}Isend", err);
|
|
return err;
|
|
}
|
|
int WRAPPER_FOR(PMPI_Isend)(void *buf, int count, MPI_Datatype datatype,
|
|
int dest, int tag, MPI_Comm comm,
|
|
MPI_Request* request) {
|
|
return generic_Isend(buf,count,datatype, dest,tag,comm, request);
|
|
}
|
|
int WRAPPER_FOR(PMPI_Ibsend)(void *buf, int count, MPI_Datatype datatype,
|
|
int dest, int tag, MPI_Comm comm,
|
|
MPI_Request* request) {
|
|
return generic_Isend(buf,count,datatype, dest,tag,comm, request);
|
|
}
|
|
int WRAPPER_FOR(PMPI_Issend)(void *buf, int count, MPI_Datatype datatype,
|
|
int dest, int tag, MPI_Comm comm,
|
|
MPI_Request* request) {
|
|
return generic_Isend(buf,count,datatype, dest,tag,comm, request);
|
|
}
|
|
int WRAPPER_FOR(PMPI_Irsend)(void *buf, int count, MPI_Datatype datatype,
|
|
int dest, int tag, MPI_Comm comm,
|
|
MPI_Request* request) {
|
|
return generic_Isend(buf,count,datatype, dest,tag,comm, request);
|
|
}
|
|
|
|
|
|
/* --- Irecv --- */
|
|
/* pre: must be writable: (buf,count,datatype), *request
|
|
post: make readable *request
|
|
add a request->(buf,count,ty) binding to the
|
|
shadow request table.
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Irecv)( void* buf, int count, MPI_Datatype datatype,
|
|
int source, int tag, MPI_Comm comm,
|
|
MPI_Request* request )
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Irecv");
|
|
check_mem_is_addressable(buf, count, datatype);
|
|
check_mem_is_addressable_untyped(request, sizeof(*request));
|
|
CALL_FN_W_7W(err, fn, buf,count,datatype,source,tag,comm,request);
|
|
if (err == MPI_SUCCESS) {
|
|
make_mem_defined_if_addressable_untyped(request, sizeof(*request));
|
|
add_shadow_Request( *request, buf,count,datatype );
|
|
}
|
|
after("Irecv", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Wait --- */
|
|
/* The MPI1 spec (imprecisely) defines 3 request states:
|
|
- "null" if the request is MPI_REQUEST_NULL
|
|
- "inactive" if not "null" and not associated with ongoing comms
|
|
- "active" if not "null" and is associated with ongoing comms
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Wait)( MPI_Request* request,
|
|
MPI_Status* status )
|
|
{
|
|
MPI_Request request_before;
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Wait");
|
|
check_mem_is_addressable_untyped(status, sizeof(MPI_Status));
|
|
check_mem_is_defined_untyped(request, sizeof(MPI_Request));
|
|
request_before = *request;
|
|
CALL_FN_W_WW(err, fn, request,status);
|
|
if (err == MPI_SUCCESS) {
|
|
maybe_complete(False/*err in status?*/,
|
|
request_before, *request, status);
|
|
make_mem_defined_if_addressable_untyped(status, sizeof(MPI_Status));
|
|
}
|
|
after("Wait", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Waitany --- */
|
|
int WRAPPER_FOR(PMPI_Waitany)( int count,
|
|
MPI_Request* requests,
|
|
int* index,
|
|
MPI_Status* status )
|
|
{
|
|
MPI_Request* requests_before = NULL;
|
|
OrigFn fn;
|
|
int err, i;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Waitany");
|
|
if (0) fprintf(stderr, "Waitany: %d\n", count);
|
|
check_mem_is_addressable_untyped(index, sizeof(int));
|
|
check_mem_is_addressable_untyped(status, sizeof(MPI_Status));
|
|
for (i = 0; i < count; i++) {
|
|
check_mem_is_defined_untyped(&requests[i], sizeof(MPI_Request));
|
|
}
|
|
requests_before = clone_Request_array( count, requests );
|
|
CALL_FN_W_WWWW(err, fn, count,requests,index,status);
|
|
if (err == MPI_SUCCESS && *index >= 0 && *index < count) {
|
|
maybe_complete(False/*err in status?*/,
|
|
requests_before[*index], requests[*index], status);
|
|
make_mem_defined_if_addressable_untyped(status, sizeof(MPI_Status));
|
|
}
|
|
if (requests_before)
|
|
free(requests_before);
|
|
after("Waitany", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Waitall --- */
|
|
int WRAPPER_FOR(PMPI_Waitall)( int count,
|
|
MPI_Request* requests,
|
|
MPI_Status* statuses )
|
|
{
|
|
MPI_Request* requests_before = NULL;
|
|
OrigFn fn;
|
|
int err, i;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Waitall");
|
|
if (0) fprintf(stderr, "Waitall: %d\n", count);
|
|
for (i = 0; i < count; i++) {
|
|
check_mem_is_addressable_untyped(&statuses[i], sizeof(MPI_Status));
|
|
check_mem_is_defined_untyped(&requests[i], sizeof(MPI_Request));
|
|
}
|
|
requests_before = clone_Request_array( count, requests );
|
|
CALL_FN_W_WWW(err, fn, count,requests,statuses);
|
|
if (err == MPI_SUCCESS /*complete success*/
|
|
|| err == MPI_ERR_IN_STATUS /* partial success */) {
|
|
Bool e_i_s = err == MPI_ERR_IN_STATUS;
|
|
for (i = 0; i < count; i++) {
|
|
maybe_complete(e_i_s, requests_before[i], requests[i],
|
|
&statuses[i]);
|
|
make_mem_defined_if_addressable_untyped(&statuses[i],
|
|
sizeof(MPI_Status));
|
|
}
|
|
}
|
|
if (requests_before)
|
|
free(requests_before);
|
|
after("Waitall", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Test --- */
|
|
/* nonblocking version of Wait */
|
|
int WRAPPER_FOR(PMPI_Test)( MPI_Request* request, int* flag,
|
|
MPI_Status* status )
|
|
{
|
|
MPI_Request request_before;
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Test");
|
|
check_mem_is_addressable_untyped(status, sizeof(MPI_Status));
|
|
check_mem_is_addressable_untyped(flag, sizeof(int));
|
|
check_mem_is_defined_untyped(request, sizeof(MPI_Request));
|
|
request_before = *request;
|
|
CALL_FN_W_WWW(err, fn, request,flag,status);
|
|
if (err == MPI_SUCCESS && *flag) {
|
|
maybe_complete(False/*err in status?*/,
|
|
request_before, *request, status);
|
|
make_mem_defined_if_addressable_untyped(status, sizeof(MPI_Status));
|
|
}
|
|
after("Test", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Testall --- */
|
|
/* nonblocking version of Waitall */
|
|
int WRAPPER_FOR(PMPI_Testall)( int count, MPI_Request* requests,
|
|
int* flag, MPI_Status* statuses )
|
|
{
|
|
MPI_Request* requests_before = NULL;
|
|
OrigFn fn;
|
|
int err, i;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Testall");
|
|
if (0) fprintf(stderr, "Testall: %d\n", count);
|
|
check_mem_is_addressable_untyped(flag, sizeof(int));
|
|
for (i = 0; i < count; i++) {
|
|
check_mem_is_addressable_untyped(&statuses[i], sizeof(MPI_Status));
|
|
check_mem_is_defined_untyped(&requests[i], sizeof(MPI_Request));
|
|
}
|
|
requests_before = clone_Request_array( count, requests );
|
|
CALL_FN_W_WWWW(err, fn, count,requests,flag,statuses);
|
|
/* Urk. Is the following "if (...)" really right? I don't know. */
|
|
if (*flag
|
|
&& (err == MPI_SUCCESS /*complete success*/
|
|
|| err == MPI_ERR_IN_STATUS /* partial success */)) {
|
|
Bool e_i_s = err == MPI_ERR_IN_STATUS;
|
|
for (i = 0; i < count; i++) {
|
|
maybe_complete(e_i_s, requests_before[i], requests[i],
|
|
&statuses[i]);
|
|
make_mem_defined_if_addressable_untyped(&statuses[i], sizeof(MPI_Status));
|
|
}
|
|
}
|
|
if (requests_before)
|
|
free(requests_before);
|
|
after("Testall", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Iprobe --- */
|
|
/* pre: must-be-writable: *flag, *status */
|
|
/* post: make-readable *flag
|
|
if *flag==True make-defined *status */
|
|
int WRAPPER_FOR(PMPI_Iprobe)(int source, int tag,
|
|
MPI_Comm comm,
|
|
int* flag, MPI_Status* status)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Iprobe");
|
|
check_mem_is_addressable_untyped(flag, sizeof(*flag));
|
|
check_mem_is_addressable_untyped(status, sizeof(*status));
|
|
CALL_FN_W_5W(err, fn, source,tag,comm,flag,status);
|
|
if (err == MPI_SUCCESS) {
|
|
make_mem_defined_if_addressable_untyped(flag, sizeof(*flag));
|
|
if (*flag)
|
|
make_mem_defined_if_addressable_untyped(status, sizeof(*status));
|
|
}
|
|
after("Iprobe", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Probe --- */
|
|
/* pre: must-be-writable *status */
|
|
/* post: make-defined *status */
|
|
int WRAPPER_FOR(PMPI_Probe)(int source, int tag,
|
|
MPI_Comm comm, MPI_Status* status)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Probe");
|
|
check_mem_is_addressable_untyped(status, sizeof(*status));
|
|
CALL_FN_W_WWWW(err, fn, source,tag,comm,status);
|
|
make_mem_defined_if_addressable_if_success_untyped(err, status, sizeof(*status));
|
|
after("Probe", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Cancel --- */
|
|
/* Wrapping PMPI_Cancel is interesting only to the extent that we need
|
|
to be able to detect when a request should be removed from our
|
|
shadow table due to cancellation. */
|
|
int WRAPPER_FOR(PMPI_Cancel)(MPI_Request* request)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
MPI_Request tmp;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Cancel");
|
|
check_mem_is_addressable_untyped(request, sizeof(*request));
|
|
tmp = *request;
|
|
CALL_FN_W_W(err, fn, request);
|
|
if (err == MPI_SUCCESS)
|
|
delete_shadow_Request(tmp);
|
|
after("Cancel", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 3.10, Send-receive ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* --- Sendrecv --- */
|
|
/* pre: must be readable: (sendbuf,sendcount,sendtype)
|
|
must be writable: (recvbuf,recvcount,recvtype)
|
|
post: make readable: (recvbuf,recvcount_actual,datatype)
|
|
where recvcount_actual is determined from *status
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Sendrecv)(
|
|
void *sendbuf, int sendcount, MPI_Datatype sendtype,
|
|
int dest, int sendtag,
|
|
void *recvbuf, int recvcount, MPI_Datatype recvtype,
|
|
int source, int recvtag,
|
|
MPI_Comm comm, MPI_Status *status)
|
|
{
|
|
OrigFn fn;
|
|
int err, recvcount_actual = 0;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Sendrecv");
|
|
check_mem_is_defined(sendbuf, sendcount, sendtype);
|
|
check_mem_is_addressable(recvbuf, recvcount, recvtype);
|
|
CALL_FN_W_12W(err, fn, sendbuf,sendcount,sendtype,dest,sendtag,
|
|
recvbuf,recvcount,recvtype,source,recvtag,
|
|
comm,status);
|
|
if (err == MPI_SUCCESS
|
|
&& count_from_Status(&recvcount_actual,recvtype,status)) {
|
|
make_mem_defined_if_addressable(recvbuf, recvcount_actual, recvtype);
|
|
}
|
|
after("Sendrecv", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 3.12, Derived datatypes ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* --- Address --- */
|
|
/* Does this have anything worth checking? */
|
|
HAS_NO_WRAPPER(Address)
|
|
|
|
/* --- MPI 2 stuff --- */
|
|
/* Type_extent, Type_get_contents and Type_get_envelope sometimes get
|
|
used intensively by the type walker (walk_type). There's no reason
|
|
why they couldn't be properly wrapped if needed, but doing so slows
|
|
everything down, so don't bother until needed. */
|
|
HAS_NO_WRAPPER(Type_extent)
|
|
HAS_NO_WRAPPER(Type_get_contents)
|
|
HAS_NO_WRAPPER(Type_get_envelope)
|
|
|
|
/* --- Type_commit --- */
|
|
int WRAPPER_FOR(PMPI_Type_commit)( MPI_Datatype* ty )
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Type_commit");
|
|
check_mem_is_defined_untyped(ty, sizeof(*ty));
|
|
CALL_FN_W_W(err, fn, ty);
|
|
after("Type_commit", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Type_free --- */
|
|
int WRAPPER_FOR(PMPI_Type_free)( MPI_Datatype* ty )
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Type_free");
|
|
check_mem_is_defined_untyped(ty, sizeof(*ty));
|
|
CALL_FN_W_W(err, fn, ty);
|
|
after("Type_free", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 3.13, Pack and unpack ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* --- Pack --- */
|
|
/* pre: must be readable: position
|
|
must be readable: (inbuf,incount,datatype)
|
|
must be writable: outbuf[0 .. outsize-1]
|
|
must be writable: outbuf[*position ..
|
|
*position - 1
|
|
+ however much space PMPI_Pack_size
|
|
says we will need]
|
|
post: make readable: outbuf[old *position .. new *position]
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Pack)( void* inbuf, int incount, MPI_Datatype datatype,
|
|
void* outbuf, int outsize,
|
|
int* position, MPI_Comm comm )
|
|
{
|
|
OrigFn fn;
|
|
int err, szB = 0;
|
|
int position_ORIG = *position;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Pack");
|
|
/* stay sane */
|
|
check_mem_is_defined_untyped(position, sizeof(*position));
|
|
/* check input */
|
|
check_mem_is_defined(inbuf, incount, datatype);
|
|
/* check output area's stated bounds make sense */
|
|
check_mem_is_addressable_untyped(outbuf, outsize);
|
|
/* check output area's actual used size properly */
|
|
err = PMPI_Pack_size( incount, datatype, comm, &szB );
|
|
if (err == MPI_SUCCESS && szB > 0) {
|
|
check_mem_is_addressable_untyped(
|
|
((char*)outbuf) + position_ORIG, szB
|
|
);
|
|
}
|
|
|
|
CALL_FN_W_7W(err, fn, inbuf,incount,datatype, outbuf,outsize,position, comm);
|
|
|
|
if (err == MPI_SUCCESS && (*position) > position_ORIG) {
|
|
/* paint output */
|
|
make_mem_defined_if_addressable_untyped(
|
|
((char*)outbuf) + position_ORIG, *position - position_ORIG
|
|
);
|
|
}
|
|
after("Pack", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Unpack --- */
|
|
/* pre: must be readable: position
|
|
must be writable: (outbuf,outcount,datatype)
|
|
must be writable: outbuf[0 .. outsize-1]
|
|
must be writable: outbuf[*position ..
|
|
*position - 1
|
|
+ however much space PMPI_Pack_size
|
|
says we will need]
|
|
post: make readable: (outbuf,outcount,datatype)
|
|
and also do a readability check of
|
|
inbuf[old *position .. new *position]
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Unpack)( void* inbuf, int insize, int* position,
|
|
void* outbuf, int outcount, MPI_Datatype datatype,
|
|
MPI_Comm comm )
|
|
{
|
|
OrigFn fn;
|
|
int err, szB = 0;
|
|
int position_ORIG = *position;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Unpack");
|
|
/* stay sane */
|
|
check_mem_is_defined_untyped(position, sizeof(*position));
|
|
/* check output area is accessible */
|
|
check_mem_is_addressable(outbuf, outcount, datatype);
|
|
/* check input area's stated bounds make sense */
|
|
check_mem_is_addressable_untyped(inbuf, insize);
|
|
/* check input area's actual used size properly */
|
|
err = PMPI_Pack_size( outcount, datatype, comm, &szB );
|
|
if (err == MPI_SUCCESS && szB > 0) {
|
|
check_mem_is_addressable_untyped(
|
|
((char*)inbuf) + position_ORIG, szB
|
|
);
|
|
}
|
|
|
|
CALL_FN_W_7W(err, fn, inbuf,insize,position, outbuf,outcount,datatype, comm);
|
|
|
|
if (err == MPI_SUCCESS && (*position) > position_ORIG) {
|
|
/* recheck input more carefully */
|
|
check_mem_is_defined_untyped(
|
|
((char*)inbuf) + position_ORIG, *position - position_ORIG
|
|
);
|
|
/* paint output */
|
|
make_mem_defined_if_addressable( outbuf, outcount, datatype );
|
|
}
|
|
after("Unpack", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 4.4, Broadcast ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* --- Bcast --- */
|
|
/* pre: must-be-readable (buffer,count,datatype) for rank==root
|
|
must-be-writable (buffer,count,datatype) for rank!=root
|
|
post: make-readable (buffer,count,datatype) for all
|
|
|
|
Resulting behaviour is: if root sends uninitialised stuff, then
|
|
V complains, but then all ranks, including itself, see the buffer
|
|
as initialised after that.
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Bcast)(void *buffer, int count,
|
|
MPI_Datatype datatype,
|
|
int root, MPI_Comm comm)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
Bool i_am_sender;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Bcast");
|
|
i_am_sender = root == comm_rank(comm);
|
|
if (i_am_sender) {
|
|
check_mem_is_defined(buffer, count, datatype);
|
|
} else {
|
|
check_mem_is_addressable(buffer, count, datatype);
|
|
}
|
|
CALL_FN_W_5W(err, fn, buffer,count,datatype,root,comm);
|
|
make_mem_defined_if_addressable_if_success(err, buffer, count, datatype);
|
|
after("Bcast", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 4.5, Gather ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* --- Gather --- */
|
|
/* JRS 20060217: I don't really understand this. Each process is
|
|
going to send sendcount items of type sendtype to the root. So
|
|
the root is going to receive comm_size*sendcount items of type
|
|
sendtype (right?) So why specify recvcount and recvtype?
|
|
|
|
Anyway, assuming the MPI Spec is correct (seems likely :-) we have:
|
|
|
|
pre: (all) must be readable: (sendbuf,sendcount,sendtype)
|
|
(root only): must be writable: (recvbuf,recvcount * comm_size,recvtype)
|
|
post: (root only): make readable: (recvbuf,recvcount * comm_size,recvtype)
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Gather)(
|
|
void *sendbuf, int sendcount, MPI_Datatype sendtype,
|
|
void *recvbuf, int recvcount, MPI_Datatype recvtype,
|
|
int root, MPI_Comm comm)
|
|
{
|
|
OrigFn fn;
|
|
int err, me, sz;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Gather");
|
|
me = comm_rank(comm);
|
|
sz = comm_size(comm);
|
|
check_mem_is_defined(sendbuf, sendcount, sendtype);
|
|
if (me == root)
|
|
check_mem_is_addressable(recvbuf, recvcount * sz, recvtype);
|
|
CALL_FN_W_8W(err, fn, sendbuf,sendcount,sendtype,
|
|
recvbuf,recvcount,recvtype,
|
|
root,comm);
|
|
if (me == root)
|
|
make_mem_defined_if_addressable_if_success(err, recvbuf, recvcount * sz, recvtype);
|
|
after("Gather", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 4.6, Scatter ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* pre: (root only): must be readable: (sendbuf,sendcount * comm_size,sendtype)
|
|
(all): must be writable: (recvbuf,recvbuf,recvtype)
|
|
post: (all): make defined: (recvbuf,recvbuf,recvtype)
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Scatter)(
|
|
void* sendbuf, int sendcount, MPI_Datatype sendtype,
|
|
void* recvbuf, int recvcount, MPI_Datatype recvtype,
|
|
int root, MPI_Comm comm)
|
|
{
|
|
OrigFn fn;
|
|
int err, me, sz;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Scatter");
|
|
me = comm_rank(comm);
|
|
sz = comm_size(comm);
|
|
check_mem_is_addressable(recvbuf, recvcount, recvtype);
|
|
if (me == root)
|
|
check_mem_is_defined(sendbuf, sendcount * sz, sendtype);
|
|
CALL_FN_W_8W(err, fn, sendbuf,sendcount,sendtype,
|
|
recvbuf,recvcount,recvtype,
|
|
root,comm);
|
|
make_mem_defined_if_addressable_if_success(err, recvbuf, recvcount, recvtype);
|
|
after("Scatter", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 4.8, All-to-All Scatter/Gather ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* pre: (all) must be readable: (sendbuf,sendcount * comm_size,sendtype)
|
|
(all) must be writable: (recvbuf,recvcount * comm_size,recvtype)
|
|
post: (all) make defined: (recvbuf,recvcount * comm_size,recvtype)
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Alltoall)(
|
|
void* sendbuf, int sendcount, MPI_Datatype sendtype,
|
|
void* recvbuf, int recvcount, MPI_Datatype recvtype,
|
|
MPI_Comm comm)
|
|
{
|
|
OrigFn fn;
|
|
int err, sz;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Alltoall");
|
|
sz = comm_size(comm);
|
|
check_mem_is_defined(sendbuf, sendcount * sz, sendtype);
|
|
check_mem_is_addressable(recvbuf, recvcount * sz, recvtype);
|
|
CALL_FN_W_7W(err, fn, sendbuf,sendcount,sendtype,
|
|
recvbuf,recvcount,recvtype,
|
|
comm);
|
|
make_mem_defined_if_addressable_if_success(err, recvbuf, recvcount * sz, recvtype);
|
|
after("Alltoall", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 4.9, Global Reduction Operations ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* --- Reduce --- */
|
|
/* rd: (sendbuf,count,datatype) for all
|
|
wr: (recvbuf,count,datatype) but only for rank == root
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Reduce)(void *sendbuf, void *recvbuf,
|
|
int count,
|
|
MPI_Datatype datatype, MPI_Op op,
|
|
int root, MPI_Comm comm)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
Bool i_am_root;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Reduce");
|
|
i_am_root = root == comm_rank(comm);
|
|
check_mem_is_defined(sendbuf, count, datatype);
|
|
if (i_am_root)
|
|
check_mem_is_addressable(recvbuf, count, datatype);
|
|
CALL_FN_W_7W(err, fn, sendbuf,recvbuf,count,datatype,op,root,comm);
|
|
if (i_am_root)
|
|
make_mem_defined_if_addressable_if_success(err, recvbuf, count, datatype);
|
|
after("Reduce", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/* --- Allreduce --- */
|
|
/* rd: (sendbuf,count,datatype) for all
|
|
wr: (recvbuf,count,datatype) for all
|
|
*/
|
|
int WRAPPER_FOR(PMPI_Allreduce)(void *sendbuf, void *recvbuf,
|
|
int count,
|
|
MPI_Datatype datatype, MPI_Op op,
|
|
MPI_Comm comm)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Allreduce");
|
|
check_mem_is_defined(sendbuf, count, datatype);
|
|
check_mem_is_addressable(recvbuf, count, datatype);
|
|
CALL_FN_W_6W(err, fn, sendbuf,recvbuf,count,datatype,op,comm);
|
|
make_mem_defined_if_addressable_if_success(err, recvbuf, count, datatype);
|
|
after("Allreduce", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/* --- Op_create --- */
|
|
/* This is a bit dubious. I suppose it takes 'function' and
|
|
writes something at *op, but who knows what an MPI_Op is?
|
|
Can we safely do 'sizeof' on it? */
|
|
int WRAPPER_FOR(PMPI_Op_create)( MPI_User_function* function,
|
|
int commute,
|
|
MPI_Op* op )
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Op_create");
|
|
check_mem_is_addressable_untyped(op, sizeof(*op));
|
|
CALL_FN_W_WWW(err, fn, function,commute,op);
|
|
make_mem_defined_if_addressable_if_success_untyped(err, op, sizeof(*op));
|
|
after("Op_create", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 5.4, Communicator management ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* Hardly seems worth wrapping Comm_rank and Comm_size, but
|
|
since it's done now .. */
|
|
|
|
/* --- Comm_create --- */
|
|
/* Let normal memcheck tracking handle this. */
|
|
int WRAPPER_FOR(PMPI_Comm_create)(MPI_Comm comm, MPI_Group group,
|
|
MPI_Comm* newcomm)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Comm_create");
|
|
CALL_FN_W_WWW(err, fn, comm,group,newcomm);
|
|
after("Comm_create", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Comm_dup --- */
|
|
/* Let normal memcheck tracking handle this. */
|
|
int WRAPPER_FOR(PMPI_Comm_dup)(MPI_Comm comm, MPI_Comm* newcomm)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Comm_dup");
|
|
CALL_FN_W_WW(err, fn, comm,newcomm);
|
|
after("Comm_dup", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Comm_free --- */
|
|
/* Let normal memcheck tracking handle this. */
|
|
int WRAPPER_FOR(PMPI_Comm_free)(MPI_Comm* comm)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Comm_free");
|
|
CALL_FN_W_W(err, fn, comm);
|
|
after("Comm_free", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Comm_rank --- */
|
|
/* wr: (rank, sizeof(*rank)) */
|
|
int WRAPPER_FOR(PMPI_Comm_rank)(MPI_Comm comm, int *rank)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Comm_rank");
|
|
check_mem_is_addressable_untyped(rank, sizeof(*rank));
|
|
CALL_FN_W_WW(err, fn, comm,rank);
|
|
make_mem_defined_if_addressable_if_success_untyped(err, rank, sizeof(*rank));
|
|
after("Comm_rank", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Comm_size --- */
|
|
/* wr: (size, sizeof(*size)) */
|
|
int WRAPPER_FOR(PMPI_Comm_size)(MPI_Comm comm, int *size)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Comm_size");
|
|
check_mem_is_addressable_untyped(size, sizeof(*size));
|
|
CALL_FN_W_WW(err, fn, comm,size);
|
|
make_mem_defined_if_addressable_if_success_untyped(err, size, sizeof(*size));
|
|
after("Comm_size", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 5.7, Caching ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 7.3, Error codes and classes ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* --- Error_string --- */
|
|
int WRAPPER_FOR(PMPI_Error_string)( int errorcode, char* string,
|
|
int* resultlen )
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Error_string");
|
|
check_mem_is_addressable_untyped(resultlen, sizeof(int));
|
|
check_mem_is_addressable_untyped(string, MPI_MAX_ERROR_STRING);
|
|
CALL_FN_W_WWW(err, fn, errorcode,string,resultlen);
|
|
/* Don't bother to paint the result; we assume the real function
|
|
will have filled it with defined characters :-) */
|
|
after("Error_string", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Sec 7.5, Startup ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* --- Init --- */
|
|
/* rd: *argc, *argv[0 .. *argc-1] */
|
|
long WRAPPER_FOR(PMPI_Init)(int *argc, char ***argv)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Init");
|
|
if (argc) {
|
|
check_mem_is_defined_untyped(argc, sizeof(int));
|
|
}
|
|
if (argc && argv) {
|
|
check_mem_is_defined_untyped(*argv, *argc * sizeof(char**));
|
|
}
|
|
CALL_FN_W_WW(err, fn, argc,argv);
|
|
after("Init", err);
|
|
if (opt_initkludge)
|
|
return (long)(void*)&mpiwrap_walk_type_EXTERNALLY_VISIBLE;
|
|
else
|
|
return (long)err;
|
|
}
|
|
|
|
/* --- Initialized --- */
|
|
int WRAPPER_FOR(PMPI_Initialized)(int* flag)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Initialized");
|
|
check_mem_is_addressable_untyped(flag, sizeof(int));
|
|
CALL_FN_W_W(err, fn, flag);
|
|
make_mem_defined_if_addressable_if_success_untyped(err, flag, sizeof(int));
|
|
after("Initialized", err);
|
|
return err;
|
|
}
|
|
|
|
/* --- Finalize --- */
|
|
int WRAPPER_FOR(PMPI_Finalize)(void)
|
|
{
|
|
OrigFn fn;
|
|
int err;
|
|
VALGRIND_GET_ORIG_FN(fn);
|
|
before("Finalize");
|
|
CALL_FN_W_v(err, fn);
|
|
after("Finalize", err);
|
|
return err;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- Default wrappers for all remaining functions ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* Boilerplate for default wrappers. */
|
|
#define DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
OrigFn fn; \
|
|
UWord res; \
|
|
static int complaints = 1; \
|
|
VALGRIND_GET_ORIG_FN(fn); \
|
|
before(#basename); \
|
|
if (opt_missing >= 2) { \
|
|
barf("no wrapper for PMPI_" #basename \
|
|
",\n\t\t\t and you have " \
|
|
"requested strict checking"); \
|
|
} \
|
|
if (opt_missing == 1 && complaints > 0) { \
|
|
fprintf(stderr, "%s %5d: warning: no wrapper " \
|
|
"for PMPI_" #basename "\n", \
|
|
preamble, my_pid); \
|
|
complaints--; \
|
|
} \
|
|
|
|
#define DEFAULT_WRAPPER_W_0W(basename) \
|
|
UWord WRAPPER_FOR(PMPI_##basename)( void ) \
|
|
{ \
|
|
DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
CALL_FN_W_v(res, fn); \
|
|
return res; \
|
|
}
|
|
|
|
#define DEFAULT_WRAPPER_W_1W(basename) \
|
|
UWord WRAPPER_FOR(PMPI_##basename)( UWord a1 ) \
|
|
{ \
|
|
DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
CALL_FN_W_W(res, fn, a1); \
|
|
return res; \
|
|
}
|
|
|
|
#define DEFAULT_WRAPPER_W_2W(basename) \
|
|
UWord WRAPPER_FOR(PMPI_##basename)( UWord a1, UWord a2 ) \
|
|
{ \
|
|
DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
CALL_FN_W_WW(res, fn, a1,a2); \
|
|
return res; \
|
|
}
|
|
|
|
#define DEFAULT_WRAPPER_W_3W(basename) \
|
|
UWord WRAPPER_FOR(PMPI_##basename) \
|
|
( UWord a1, UWord a2, UWord a3 ) \
|
|
{ \
|
|
DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
CALL_FN_W_WWW(res, fn, a1,a2,a3); \
|
|
return res; \
|
|
}
|
|
|
|
#define DEFAULT_WRAPPER_W_4W(basename) \
|
|
UWord WRAPPER_FOR(PMPI_##basename) \
|
|
( UWord a1, UWord a2, UWord a3, UWord a4 ) \
|
|
{ \
|
|
DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
CALL_FN_W_WWWW(res, fn, a1,a2,a3,a4); \
|
|
return res; \
|
|
}
|
|
|
|
#define DEFAULT_WRAPPER_W_5W(basename) \
|
|
UWord WRAPPER_FOR(PMPI_##basename) \
|
|
( UWord a1, UWord a2, UWord a3, UWord a4, UWord a5 ) \
|
|
{ \
|
|
DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
CALL_FN_W_5W(res, fn, a1,a2,a3,a4,a5); \
|
|
return res; \
|
|
}
|
|
|
|
#define DEFAULT_WRAPPER_W_6W(basename) \
|
|
UWord WRAPPER_FOR(PMPI_##basename) \
|
|
( UWord a1, UWord a2, UWord a3, UWord a4, UWord a5, \
|
|
UWord a6 ) \
|
|
{ \
|
|
DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
CALL_FN_W_6W(res, fn, a1,a2,a3,a4,a5,a6); \
|
|
return res; \
|
|
}
|
|
|
|
#define DEFAULT_WRAPPER_W_7W(basename) \
|
|
UWord WRAPPER_FOR(PMPI_##basename) \
|
|
( UWord a1, UWord a2, UWord a3, UWord a4, UWord a5, \
|
|
UWord a6, UWord a7 ) \
|
|
{ \
|
|
DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
CALL_FN_W_7W(res, fn, a1,a2,a3,a4,a5,a6,a7); \
|
|
return res; \
|
|
}
|
|
|
|
#define DEFAULT_WRAPPER_W_8W(basename) \
|
|
UWord WRAPPER_FOR(PMPI_##basename) \
|
|
( UWord a1, UWord a2, UWord a3, UWord a4, UWord a5, \
|
|
UWord a6, UWord a7, UWord a8 ) \
|
|
{ \
|
|
DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
CALL_FN_W_8W(res, fn, a1,a2,a3,a4,a5,a6,a7,a8); \
|
|
return res; \
|
|
}
|
|
|
|
#define DEFAULT_WRAPPER_W_9W(basename) \
|
|
UWord WRAPPER_FOR(PMPI_##basename) \
|
|
( UWord a1, UWord a2, UWord a3, UWord a4, UWord a5, \
|
|
UWord a6, UWord a7, UWord a8, UWord a9 ) \
|
|
{ \
|
|
DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
CALL_FN_W_9W(res, fn, a1,a2,a3,a4,a5,a6,a7,a8,a9); \
|
|
return res; \
|
|
}
|
|
|
|
#define DEFAULT_WRAPPER_W_10W(basename) \
|
|
UWord WRAPPER_FOR(PMPI_##basename) \
|
|
( UWord a1, UWord a2, UWord a3, UWord a4, UWord a5, \
|
|
UWord a6, UWord a7, UWord a8, UWord a9, UWord a10 ) \
|
|
{ \
|
|
DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
CALL_FN_W_10W(res, fn, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); \
|
|
return res; \
|
|
}
|
|
|
|
#define DEFAULT_WRAPPER_W_12W(basename) \
|
|
UWord WRAPPER_FOR(PMPI_##basename) \
|
|
( UWord a1, UWord a2, UWord a3, UWord a4, UWord a5, \
|
|
UWord a6, UWord a7, UWord a8, UWord a9, UWord a10, \
|
|
UWord a11, UWord a12 ) \
|
|
{ \
|
|
DEFAULT_WRAPPER_PREAMBLE(basename) \
|
|
CALL_FN_W_12W(res, fn, a1,a2,a3,a4,a5,a6, \
|
|
a7,a8,a9,a10,a11,a12); \
|
|
return res; \
|
|
}
|
|
|
|
|
|
/* Canned summary of MPI-1.1/MPI-2 entry points, as derived from mpi.h
|
|
from Open MPI svn rev 9191 (somewhere between Open MPI versions
|
|
1.0.1 and 1.1.0). */
|
|
|
|
/* If a function is commented out in this list, it's because it has a
|
|
proper wrapper written elsewhere (above here). */
|
|
|
|
DEFAULT_WRAPPER_W_2W(Abort)
|
|
DEFAULT_WRAPPER_W_9W(Accumulate)
|
|
DEFAULT_WRAPPER_W_1W(Add_error_class)
|
|
DEFAULT_WRAPPER_W_2W(Add_error_code)
|
|
DEFAULT_WRAPPER_W_2W(Add_error_string)
|
|
/* DEFAULT_WRAPPER_W_2W(Address) */
|
|
DEFAULT_WRAPPER_W_7W(Allgather)
|
|
DEFAULT_WRAPPER_W_8W(Allgatherv)
|
|
DEFAULT_WRAPPER_W_3W(Alloc_mem)
|
|
/* DEFAULT_WRAPPER_W_6W(Allreduce) */
|
|
/* DEFAULT_WRAPPER_W_7W(Alltoall) */
|
|
DEFAULT_WRAPPER_W_9W(Alltoallv)
|
|
DEFAULT_WRAPPER_W_9W(Alltoallw)
|
|
DEFAULT_WRAPPER_W_2W(Attr_delete)
|
|
DEFAULT_WRAPPER_W_4W(Attr_get)
|
|
DEFAULT_WRAPPER_W_3W(Attr_put)
|
|
DEFAULT_WRAPPER_W_1W(Barrier)
|
|
/* DEFAULT_WRAPPER_W_5W(Bcast) */
|
|
/* DEFAULT_WRAPPER_W_6W(Bsend) */
|
|
DEFAULT_WRAPPER_W_7W(Bsend_init)
|
|
DEFAULT_WRAPPER_W_2W(Buffer_attach)
|
|
DEFAULT_WRAPPER_W_2W(Buffer_detach)
|
|
/* DEFAULT_WRAPPER_W_1W(Cancel) */
|
|
DEFAULT_WRAPPER_W_4W(Cart_coords)
|
|
DEFAULT_WRAPPER_W_6W(Cart_create)
|
|
DEFAULT_WRAPPER_W_5W(Cart_get)
|
|
DEFAULT_WRAPPER_W_5W(Cart_map)
|
|
DEFAULT_WRAPPER_W_3W(Cart_rank)
|
|
DEFAULT_WRAPPER_W_5W(Cart_shift)
|
|
DEFAULT_WRAPPER_W_3W(Cart_sub)
|
|
DEFAULT_WRAPPER_W_2W(Cartdim_get)
|
|
DEFAULT_WRAPPER_W_1W(Close_port)
|
|
DEFAULT_WRAPPER_W_5W(Comm_accept)
|
|
DEFAULT_WRAPPER_W_1W(Comm_c2f)
|
|
DEFAULT_WRAPPER_W_2W(Comm_call_errhandler)
|
|
DEFAULT_WRAPPER_W_3W(Comm_compare)
|
|
DEFAULT_WRAPPER_W_5W(Comm_connect)
|
|
DEFAULT_WRAPPER_W_2W(Comm_create_errhandler)
|
|
DEFAULT_WRAPPER_W_4W(Comm_create_keyval)
|
|
/* DEFAULT_WRAPPER_W_3W(Comm_create) */
|
|
DEFAULT_WRAPPER_W_2W(Comm_delete_attr)
|
|
DEFAULT_WRAPPER_W_1W(Comm_disconnect)
|
|
/* DEFAULT_WRAPPER_W_2W(Comm_dup) */
|
|
DEFAULT_WRAPPER_W_1W(Comm_f2c)
|
|
DEFAULT_WRAPPER_W_1W(Comm_free_keyval)
|
|
/* DEFAULT_WRAPPER_W_1W(Comm_free) */
|
|
DEFAULT_WRAPPER_W_4W(Comm_get_attr)
|
|
DEFAULT_WRAPPER_W_2W(Comm_get_errhandler)
|
|
DEFAULT_WRAPPER_W_3W(Comm_get_name)
|
|
DEFAULT_WRAPPER_W_1W(Comm_get_parent)
|
|
DEFAULT_WRAPPER_W_2W(Comm_group)
|
|
DEFAULT_WRAPPER_W_2W(Comm_join)
|
|
/* DEFAULT_WRAPPER_W_2W(Comm_rank) */
|
|
DEFAULT_WRAPPER_W_2W(Comm_remote_group)
|
|
DEFAULT_WRAPPER_W_2W(Comm_remote_size)
|
|
DEFAULT_WRAPPER_W_3W(Comm_set_attr)
|
|
DEFAULT_WRAPPER_W_2W(Comm_set_errhandler)
|
|
DEFAULT_WRAPPER_W_2W(Comm_set_name)
|
|
/* DEFAULT_WRAPPER_W_2W(Comm_size) */
|
|
DEFAULT_WRAPPER_W_8W(Comm_spawn)
|
|
DEFAULT_WRAPPER_W_9W(Comm_spawn_multiple)
|
|
DEFAULT_WRAPPER_W_4W(Comm_split)
|
|
DEFAULT_WRAPPER_W_2W(Comm_test_inter)
|
|
DEFAULT_WRAPPER_W_3W(Dims_create)
|
|
DEFAULT_WRAPPER_W_1W(Errhandler_c2f)
|
|
DEFAULT_WRAPPER_W_2W(Errhandler_create)
|
|
DEFAULT_WRAPPER_W_1W(Errhandler_f2c)
|
|
DEFAULT_WRAPPER_W_1W(Errhandler_free)
|
|
DEFAULT_WRAPPER_W_2W(Errhandler_get)
|
|
DEFAULT_WRAPPER_W_2W(Errhandler_set)
|
|
DEFAULT_WRAPPER_W_2W(Error_class)
|
|
/* DEFAULT_WRAPPER_W_3W(Error_string) */
|
|
DEFAULT_WRAPPER_W_6W(Exscan)
|
|
DEFAULT_WRAPPER_W_1W(File_c2f)
|
|
DEFAULT_WRAPPER_W_1W(File_f2c)
|
|
DEFAULT_WRAPPER_W_2W(File_call_errhandler)
|
|
DEFAULT_WRAPPER_W_2W(File_create_errhandler)
|
|
DEFAULT_WRAPPER_W_2W(File_set_errhandler)
|
|
DEFAULT_WRAPPER_W_2W(File_get_errhandler)
|
|
DEFAULT_WRAPPER_W_5W(File_open)
|
|
DEFAULT_WRAPPER_W_1W(File_close)
|
|
DEFAULT_WRAPPER_W_2W(File_delete)
|
|
DEFAULT_WRAPPER_W_2W(File_set_size)
|
|
DEFAULT_WRAPPER_W_2W(File_preallocate)
|
|
DEFAULT_WRAPPER_W_2W(File_get_size)
|
|
DEFAULT_WRAPPER_W_2W(File_get_group)
|
|
DEFAULT_WRAPPER_W_2W(File_get_amode)
|
|
DEFAULT_WRAPPER_W_2W(File_set_info)
|
|
DEFAULT_WRAPPER_W_2W(File_get_info)
|
|
DEFAULT_WRAPPER_W_6W(File_set_view)
|
|
DEFAULT_WRAPPER_W_5W(File_get_view)
|
|
DEFAULT_WRAPPER_W_6W(File_read_at)
|
|
DEFAULT_WRAPPER_W_6W(File_read_at_all)
|
|
DEFAULT_WRAPPER_W_6W(File_write_at)
|
|
DEFAULT_WRAPPER_W_6W(File_write_at_all)
|
|
DEFAULT_WRAPPER_W_6W(File_iread_at)
|
|
DEFAULT_WRAPPER_W_6W(File_iwrite_at)
|
|
DEFAULT_WRAPPER_W_5W(File_read)
|
|
DEFAULT_WRAPPER_W_5W(File_read_all)
|
|
DEFAULT_WRAPPER_W_5W(File_write)
|
|
DEFAULT_WRAPPER_W_5W(File_write_all)
|
|
DEFAULT_WRAPPER_W_5W(File_iread)
|
|
DEFAULT_WRAPPER_W_5W(File_iwrite)
|
|
DEFAULT_WRAPPER_W_3W(File_seek)
|
|
DEFAULT_WRAPPER_W_2W(File_get_position)
|
|
DEFAULT_WRAPPER_W_3W(File_get_byte_offset)
|
|
DEFAULT_WRAPPER_W_5W(File_read_shared)
|
|
DEFAULT_WRAPPER_W_5W(File_write_shared)
|
|
DEFAULT_WRAPPER_W_5W(File_iread_shared)
|
|
DEFAULT_WRAPPER_W_5W(File_iwrite_shared)
|
|
DEFAULT_WRAPPER_W_5W(File_read_ordered)
|
|
DEFAULT_WRAPPER_W_5W(File_write_ordered)
|
|
DEFAULT_WRAPPER_W_3W(File_seek_shared)
|
|
DEFAULT_WRAPPER_W_2W(File_get_position_shared)
|
|
DEFAULT_WRAPPER_W_5W(File_read_at_all_begin)
|
|
DEFAULT_WRAPPER_W_3W(File_read_at_all_end)
|
|
DEFAULT_WRAPPER_W_5W(File_write_at_all_begin)
|
|
DEFAULT_WRAPPER_W_3W(File_write_at_all_end)
|
|
DEFAULT_WRAPPER_W_4W(File_read_all_begin)
|
|
DEFAULT_WRAPPER_W_3W(File_read_all_end)
|
|
DEFAULT_WRAPPER_W_4W(File_write_all_begin)
|
|
DEFAULT_WRAPPER_W_3W(File_write_all_end)
|
|
DEFAULT_WRAPPER_W_4W(File_read_ordered_begin)
|
|
DEFAULT_WRAPPER_W_3W(File_read_ordered_end)
|
|
DEFAULT_WRAPPER_W_4W(File_write_ordered_begin)
|
|
DEFAULT_WRAPPER_W_3W(File_write_ordered_end)
|
|
DEFAULT_WRAPPER_W_3W(File_get_type_extent)
|
|
DEFAULT_WRAPPER_W_2W(File_set_atomicity)
|
|
DEFAULT_WRAPPER_W_2W(File_get_atomicity)
|
|
DEFAULT_WRAPPER_W_1W(File_sync)
|
|
/* DEFAULT_WRAPPER_W_0W(Finalize) */
|
|
DEFAULT_WRAPPER_W_1W(Finalized)
|
|
DEFAULT_WRAPPER_W_1W(Free_mem)
|
|
/* DEFAULT_WRAPPER_W_8W(Gather) */
|
|
DEFAULT_WRAPPER_W_9W(Gatherv)
|
|
DEFAULT_WRAPPER_W_2W(Get_address)
|
|
/* DEFAULT_WRAPPER_W_3W(Get_count) */
|
|
DEFAULT_WRAPPER_W_3W(Get_elements)
|
|
DEFAULT_WRAPPER_W_8W(Get)
|
|
DEFAULT_WRAPPER_W_2W(Get_processor_name)
|
|
DEFAULT_WRAPPER_W_2W(Get_version)
|
|
DEFAULT_WRAPPER_W_6W(Graph_create)
|
|
DEFAULT_WRAPPER_W_5W(Graph_get)
|
|
DEFAULT_WRAPPER_W_5W(Graph_map)
|
|
DEFAULT_WRAPPER_W_3W(Graph_neighbors_count)
|
|
DEFAULT_WRAPPER_W_4W(Graph_neighbors)
|
|
DEFAULT_WRAPPER_W_3W(Graphdims_get)
|
|
DEFAULT_WRAPPER_W_1W(Grequest_complete)
|
|
DEFAULT_WRAPPER_W_5W(Grequest_start)
|
|
DEFAULT_WRAPPER_W_1W(Group_c2f)
|
|
DEFAULT_WRAPPER_W_3W(Group_compare)
|
|
DEFAULT_WRAPPER_W_3W(Group_difference)
|
|
DEFAULT_WRAPPER_W_4W(Group_excl)
|
|
DEFAULT_WRAPPER_W_1W(Group_f2c)
|
|
DEFAULT_WRAPPER_W_1W(Group_free)
|
|
DEFAULT_WRAPPER_W_4W(Group_incl)
|
|
DEFAULT_WRAPPER_W_3W(Group_intersection)
|
|
DEFAULT_WRAPPER_W_4W(Group_range_excl)
|
|
DEFAULT_WRAPPER_W_4W(Group_range_incl)
|
|
DEFAULT_WRAPPER_W_2W(Group_rank)
|
|
DEFAULT_WRAPPER_W_2W(Group_size)
|
|
DEFAULT_WRAPPER_W_5W(Group_translate_ranks)
|
|
DEFAULT_WRAPPER_W_3W(Group_union)
|
|
/* DEFAULT_WRAPPER_W_7W(Ibsend) */
|
|
DEFAULT_WRAPPER_W_1W(Info_c2f)
|
|
DEFAULT_WRAPPER_W_1W(Info_create)
|
|
DEFAULT_WRAPPER_W_2W(Info_delete)
|
|
DEFAULT_WRAPPER_W_2W(Info_dup)
|
|
DEFAULT_WRAPPER_W_1W(Info_f2c)
|
|
DEFAULT_WRAPPER_W_1W(Info_free)
|
|
DEFAULT_WRAPPER_W_5W(Info_get)
|
|
DEFAULT_WRAPPER_W_2W(Info_get_nkeys)
|
|
DEFAULT_WRAPPER_W_3W(Info_get_nthkey)
|
|
DEFAULT_WRAPPER_W_4W(Info_get_valuelen)
|
|
DEFAULT_WRAPPER_W_3W(Info_set)
|
|
/* DEFAULT_WRAPPER_W_2W(Init) */
|
|
/* DEFAULT_WRAPPER_W_1W(Initialized) */
|
|
DEFAULT_WRAPPER_W_4W(Init_thread)
|
|
DEFAULT_WRAPPER_W_6W(Intercomm_create)
|
|
DEFAULT_WRAPPER_W_3W(Intercomm_merge)
|
|
/* DEFAULT_WRAPPER_W_5W(Iprobe) */
|
|
/* DEFAULT_WRAPPER_W_7W(Irecv) */
|
|
/* DEFAULT_WRAPPER_W_7W(Irsend) */
|
|
/* DEFAULT_WRAPPER_W_7W(Isend) */
|
|
/* DEFAULT_WRAPPER_W_7W(Issend) */
|
|
DEFAULT_WRAPPER_W_1W(Is_thread_main)
|
|
DEFAULT_WRAPPER_W_4W(Keyval_create)
|
|
DEFAULT_WRAPPER_W_1W(Keyval_free)
|
|
DEFAULT_WRAPPER_W_3W(Lookup_name)
|
|
DEFAULT_WRAPPER_W_1W(Op_c2f)
|
|
/* DEFAULT_WRAPPER_W_3W(Op_create) */
|
|
DEFAULT_WRAPPER_W_2W(Open_port)
|
|
DEFAULT_WRAPPER_W_1W(Op_f2c)
|
|
DEFAULT_WRAPPER_W_1W(Op_free)
|
|
DEFAULT_WRAPPER_W_7W(Pack_external)
|
|
DEFAULT_WRAPPER_W_4W(Pack_external_size)
|
|
/* DEFAULT_WRAPPER_W_7W(Pack) */
|
|
DEFAULT_WRAPPER_W_4W(Pack_size)
|
|
/* int MPI_Pcontrol(const int level, ...) */
|
|
/* DEFAULT_WRAPPER_W_4W(Probe) */
|
|
DEFAULT_WRAPPER_W_3W(Publish_name)
|
|
DEFAULT_WRAPPER_W_8W(Put)
|
|
DEFAULT_WRAPPER_W_1W(Query_thread)
|
|
DEFAULT_WRAPPER_W_7W(Recv_init)
|
|
/* DEFAULT_WRAPPER_W_7W(Recv) */
|
|
/* DEFAULT_WRAPPER_W_7W(Reduce) */
|
|
DEFAULT_WRAPPER_W_6W(Reduce_scatter)
|
|
DEFAULT_WRAPPER_W_5W(Register_datarep)
|
|
DEFAULT_WRAPPER_W_1W(Request_c2f)
|
|
DEFAULT_WRAPPER_W_1W(Request_f2c)
|
|
DEFAULT_WRAPPER_W_1W(Request_free)
|
|
DEFAULT_WRAPPER_W_3W(Request_get_status)
|
|
/* DEFAULT_WRAPPER_W_6W(Rsend) */
|
|
DEFAULT_WRAPPER_W_7W(Rsend_init)
|
|
DEFAULT_WRAPPER_W_6W(Scan)
|
|
/* DEFAULT_WRAPPER_W_8W(Scatter) */
|
|
DEFAULT_WRAPPER_W_9W(Scatterv)
|
|
DEFAULT_WRAPPER_W_7W(Send_init)
|
|
/* DEFAULT_WRAPPER_W_6W(Send) */
|
|
/* DEFAULT_WRAPPER_W_12W(Sendrecv) */
|
|
DEFAULT_WRAPPER_W_9W(Sendrecv_replace)
|
|
DEFAULT_WRAPPER_W_7W(Ssend_init)
|
|
/* DEFAULT_WRAPPER_W_6W(Ssend) */
|
|
DEFAULT_WRAPPER_W_1W(Start)
|
|
DEFAULT_WRAPPER_W_2W(Startall)
|
|
DEFAULT_WRAPPER_W_2W(Status_c2f)
|
|
DEFAULT_WRAPPER_W_2W(Status_f2c)
|
|
DEFAULT_WRAPPER_W_2W(Status_set_cancelled)
|
|
DEFAULT_WRAPPER_W_3W(Status_set_elements)
|
|
/* DEFAULT_WRAPPER_W_4W(Testall) */
|
|
DEFAULT_WRAPPER_W_5W(Testany)
|
|
/* DEFAULT_WRAPPER_W_3W(Test) */
|
|
DEFAULT_WRAPPER_W_2W(Test_cancelled)
|
|
DEFAULT_WRAPPER_W_5W(Testsome)
|
|
DEFAULT_WRAPPER_W_2W(Topo_test)
|
|
DEFAULT_WRAPPER_W_1W(Type_c2f)
|
|
/* DEFAULT_WRAPPER_W_1W(Type_commit) */
|
|
DEFAULT_WRAPPER_W_3W(Type_contiguous)
|
|
DEFAULT_WRAPPER_W_10W(Type_create_darray)
|
|
DEFAULT_WRAPPER_W_3W(Type_create_f90_complex)
|
|
DEFAULT_WRAPPER_W_2W(Type_create_f90_integer)
|
|
DEFAULT_WRAPPER_W_3W(Type_create_f90_real)
|
|
DEFAULT_WRAPPER_W_5W(Type_create_hindexed)
|
|
DEFAULT_WRAPPER_W_5W(Type_create_hvector)
|
|
DEFAULT_WRAPPER_W_4W(Type_create_keyval)
|
|
DEFAULT_WRAPPER_W_5W(Type_create_indexed_block)
|
|
DEFAULT_WRAPPER_W_5W(Type_create_struct)
|
|
DEFAULT_WRAPPER_W_7W(Type_create_subarray)
|
|
DEFAULT_WRAPPER_W_4W(Type_create_resized)
|
|
DEFAULT_WRAPPER_W_2W(Type_delete_attr)
|
|
DEFAULT_WRAPPER_W_2W(Type_dup)
|
|
/* DEFAULT_WRAPPER_W_2W(Type_extent) */
|
|
/* DEFAULT_WRAPPER_W_1W(Type_free) */
|
|
DEFAULT_WRAPPER_W_1W(Type_free_keyval)
|
|
DEFAULT_WRAPPER_W_1W(Type_f2c)
|
|
DEFAULT_WRAPPER_W_4W(Type_get_attr)
|
|
/* DEFAULT_WRAPPER_W_7W(Type_get_contents) */
|
|
/* DEFAULT_WRAPPER_W_5W(Type_get_envelope) */
|
|
DEFAULT_WRAPPER_W_3W(Type_get_extent)
|
|
DEFAULT_WRAPPER_W_3W(Type_get_name)
|
|
DEFAULT_WRAPPER_W_3W(Type_get_true_extent)
|
|
DEFAULT_WRAPPER_W_5W(Type_hindexed)
|
|
DEFAULT_WRAPPER_W_5W(Type_hvector)
|
|
DEFAULT_WRAPPER_W_5W(Type_indexed)
|
|
DEFAULT_WRAPPER_W_2W(Type_lb)
|
|
DEFAULT_WRAPPER_W_3W(Type_match_size)
|
|
DEFAULT_WRAPPER_W_3W(Type_set_attr)
|
|
DEFAULT_WRAPPER_W_2W(Type_set_name)
|
|
DEFAULT_WRAPPER_W_2W(Type_size)
|
|
DEFAULT_WRAPPER_W_5W(Type_struct)
|
|
DEFAULT_WRAPPER_W_2W(Type_ub)
|
|
DEFAULT_WRAPPER_W_5W(Type_vector)
|
|
/* DEFAULT_WRAPPER_W_7W(Unpack) */
|
|
DEFAULT_WRAPPER_W_3W(Unpublish_name)
|
|
DEFAULT_WRAPPER_W_7W(Unpack_external)
|
|
/* DEFAULT_WRAPPER_W_3W(Waitall) */
|
|
/* DEFAULT_WRAPPER_W_4W(Waitany) */
|
|
/* DEFAULT_WRAPPER_W_2W(Wait) */
|
|
DEFAULT_WRAPPER_W_5W(Waitsome)
|
|
DEFAULT_WRAPPER_W_1W(Win_c2f)
|
|
DEFAULT_WRAPPER_W_2W(Win_call_errhandler)
|
|
DEFAULT_WRAPPER_W_1W(Win_complete)
|
|
DEFAULT_WRAPPER_W_6W(Win_create)
|
|
DEFAULT_WRAPPER_W_2W(Win_create_errhandler)
|
|
DEFAULT_WRAPPER_W_4W(Win_create_keyval)
|
|
DEFAULT_WRAPPER_W_2W(Win_delete_attr)
|
|
DEFAULT_WRAPPER_W_1W(Win_f2c)
|
|
DEFAULT_WRAPPER_W_2W(Win_fence)
|
|
DEFAULT_WRAPPER_W_1W(Win_free)
|
|
DEFAULT_WRAPPER_W_1W(Win_free_keyval)
|
|
DEFAULT_WRAPPER_W_4W(Win_get_attr)
|
|
DEFAULT_WRAPPER_W_2W(Win_get_errhandler)
|
|
DEFAULT_WRAPPER_W_2W(Win_get_group)
|
|
DEFAULT_WRAPPER_W_3W(Win_get_name)
|
|
DEFAULT_WRAPPER_W_4W(Win_lock)
|
|
DEFAULT_WRAPPER_W_3W(Win_post)
|
|
DEFAULT_WRAPPER_W_3W(Win_set_attr)
|
|
DEFAULT_WRAPPER_W_2W(Win_set_errhandler)
|
|
DEFAULT_WRAPPER_W_2W(Win_set_name)
|
|
DEFAULT_WRAPPER_W_3W(Win_start)
|
|
DEFAULT_WRAPPER_W_2W(Win_test)
|
|
DEFAULT_WRAPPER_W_2W(Win_unlock)
|
|
DEFAULT_WRAPPER_W_1W(Win_wait)
|
|
/* double MPI_Wtick(void) */
|
|
/* double MPI_Wtime(void) */
|
|
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- ---*/
|
|
/*--- ---*/
|
|
/*--- ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------*/
|
|
/*--- end mpiwrap.c ---*/
|
|
/*---------------------------------------------------------------*/
|