|
From: <sv...@va...> - 2006-02-18 23:13:40
|
Author: sewardj
Date: 2006-02-18 23:13:33 +0000 (Sat, 18 Feb 2006)
New Revision: 5657
Log:
First try at an MPI wrappers library. Currently the build system
ignores it - it must be built by hand.
Added:
trunk/mpiwrap.c
Modified:
trunk/auxprogs/Makefile.am
Modified: trunk/auxprogs/Makefile.am
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/auxprogs/Makefile.am 2006-02-18 21:13:29 UTC (rev 5656)
+++ trunk/auxprogs/Makefile.am 2006-02-18 23:13:33 UTC (rev 5657)
@@ -5,7 +5,7 @@
=20
noinst_SCRIPTS =3D gen-mdg DotToScc.hs primes.c \
gsl16test gsl16-badfree.patch gsl16-wavelet.patch \
- ppcfround.c ppc64shifts.c
+ ppcfround.c ppc64shifts.c mpiwrap.c
=20
EXTRA_DIST =3D $(noinst_SCRIPTS)
=20
Added: trunk/mpiwrap.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/mpiwrap.c (rev 0)
+++ trunk/mpiwrap.c 2006-02-18 23:13:33 UTC (rev 5657)
@@ -0,0 +1,1274 @@
+
+/*---------------------------------------------------------------*/
+/*--- ---*/
+/*--- A library of wrappers for MPI 1.1 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 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 "valgrind.h"
+#include "memcheck.h"
+
+
+/*------------------------------------------------------------*/
+/*--- Connect to MPI library ---*/
+/*------------------------------------------------------------*/
+
+/* Include headers for whatever MPI implementation the wrappers are to
+ be used with. */
+#include "mpi.h"
+
+/* Where are API symbols?
+ OpenPMPI lib/libmpi.so, soname =3D libmpi.so.0
+*/
+/* ifdef OpenMPI ... */
+#define I_WRAP_FNNAME_U(_name) I_WRAP_SONAME_FNNAME_ZU(libmpiZdsoZa,_nam=
e)
+
+
+/*------------------------------------------------------------*/
+/*--- Decls ---*/
+/*------------------------------------------------------------*/
+
+typedef unsigned char Bool;
+#define False ((Bool)0)
+#define True ((Bool)1)
+
+
+/*------------------------------------------------------------*/
+/*--- Simple helpers ---*/
+/*------------------------------------------------------------*/
+
+/* ------ Helpers for debug printing ------ */
+
+/* constant */
+static const char* preamble =3D "valgrind MPI wrappers";
+
+/* established at startup */
+static pid_t my_pid =3D -1;
+static char* options_str =3D NULL;
+static Bool opt_verbose =3D False;
+static Bool opt_strict =3D False;
+static Bool opt_help =3D False;
+
+static inline void before ( char* fnname )
+{
+ /* This isn't thread-safe wrt 'done' (no locking). It's not
+ critical. */
+ static int done =3D 0;
+ if (done =3D=3D 0) {
+ done =3D 1;
+ my_pid =3D getpid();
+ options_str =3D getenv("MPIWRAP_DEBUG");
+ if (options_str)=20
+ opt_help =3D NULL !=3D strstr(options_str, "help");
+ if (options_str)=20
+ opt_verbose =3D NULL !=3D strstr(options_str, "verbose");
+ if (options_str)=20
+ opt_strict =3D NULL !=3D strstr(options_str, "strict");
+ fprintf(stderr, "%s %5d: active for pid %d\n",=20
+ preamble, my_pid, my_pid);
+ if (opt_help) {
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Valid options for the MPIWRAP_DEBUG environmen=
t"
+ " variable are:\n");
+ fprintf(stderr, "\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, " help display this message, then exit\=
n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Multiple options are allowed, eg"
+ " MPIWRAP_DEBUG=3Dstrict,verbose\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "%s %5d: exiting now\n", preamble, my_pid );
+ exit(1);
+ }
+ fprintf(stderr, "%s %5d: try MPIWRAP_DEBUG=3Dhelp for possible opt=
ions\n",=20
+ preamble, my_pid);
+ fprintf(stderr, "%s %5d: selected options: %s %s\n",=20
+ preamble, my_pid, opt_verbose ? "verbose" : "",
+ opt_strict ? "strict" : "");
+
+ }
+ if (opt_verbose)
+ fprintf(stderr, "%s %5d: enter PMPI_%s\n", preamble, my_pid, fnna=
me );
+}
+
+static inline void after ( char* fnname, int err )
+{
+ if (opt_verbose)
+ fprintf(stderr, "%s %5d: exit PMPI_%s (err =3D %d)\n",=20
+ 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);
+}
+
+/* ------ Get useful bits of info ------ */
+
+/* Note, PMPI_Comm_rank/size are themselves wrapped. Should work
+ fine. */
+
+static inline int comm_rank ( MPI_Comm comm )=20
+{
+ int err, r;
+ err =3D PMPI_Comm_rank(comm, &r);
+ return err ? 0/*arbitrary*/ : r;
+}
+
+static inline int comm_size ( MPI_Comm comm )=20
+{
+ int err, r;
+ err =3D PMPI_Comm_size(comm, &r);
+ return err ? 0/*arbitrary*/ : r;
+}
+
+static inline Bool count_from_Status( /*OUT*/int* recv_count,=20
+ MPI_Datatype datatype,=20
+ MPI_Status* status)
+{
+ int n;
+ int err =3D PMPI_Get_count(status, datatype, &n);
+ if (err =3D=3D MPI_SUCCESS) {
+ *recv_count =3D 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=20
+Bool eq_MPI_Request ( MPI_Request r1, MPI_Request r2 )
+{
+ return r1 =3D=3D r2;
+}
+
+
+/*------------------------------------------------------------*/
+/*--- Address-range helpers ---*/
+/*------------------------------------------------------------*/
+
+/* ----------------
+ Do checks on memory areas defined using the MPI (buffer, count,
+ type) convention.
+ ----------------
+*/
+
+static inline long datasize ( MPI_Datatype datatype )
+{
+ if (datatype =3D=3D MPI_INT) return sizeof(signed int);
+ if (datatype =3D=3D MPI_DOUBLE) return sizeof(double);
+ if (datatype =3D=3D MPI_CHAR) return sizeof(signed char);
+ if (datatype =3D=3D MPI_UNSIGNED) return sizeof(unsigned int);
+ fprintf(stderr, "%s %5d: datasize: unhandled PMPI_Datatype %d\n",
+ preamble, my_pid, (int)datatype);
+ return 0;
+}
+
+
+/* Check that the specified area is both addressible and contains
+ initialised data, and cause V to complain if not. */
+
+static
+void check_readable ( void *buffer, long count, MPI_Datatype datatype )
+{
+ long nbytes =3D count * datasize(datatype);
+ if (nbytes > 0) {
+ VALGRIND_CHECK_READABLE(buffer, nbytes);
+ }
+}
+
+
+/* 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
+void check_writable ( void *buffer, long count, MPI_Datatype datatype )
+{
+ long nbytes =3D count * datasize(datatype);
+ if (nbytes > 0) {
+ VALGRIND_CHECK_WRITABLE(buffer, nbytes);
+ }
+}
+
+
+/* Set the specified area to 'addressible and defined' (safe-to-read)
+ state. */
+
+static
+void make_readable ( void *buffer, int count, MPI_Datatype datatype )
+{
+ long nbytes =3D count * datasize(datatype);
+ if (nbytes > 0) {
+ VALGRIND_MAKE_READABLE(buffer, nbytes);
+ }
+}
+
+static
+void=20
+make_readable_if_success ( int err, void *buffer, int count,=20
+ MPI_Datatype datatype )
+{
+ if (err =3D=3D MPI_SUCCESS) {
+ long nbytes =3D count * datasize(datatype);
+ if (nbytes > 0) {
+ VALGRIND_MAKE_READABLE(buffer, nbytes);
+ }
+ }
+}
+
+
+/* ----------------
+ Do corresponding checks on memory areas defined using a=20
+ straightforward (start, length) description.
+ ----------------
+*/
+
+static inline
+void check_readable_untyped ( void* buffer, long nbytes )
+{
+ if (nbytes > 0) {
+ VALGRIND_CHECK_READABLE(buffer, nbytes);
+ }
+}
+
+static inline
+void check_writable_untyped ( void* buffer, long nbytes )
+{
+ if (nbytes > 0) {
+ VALGRIND_CHECK_WRITABLE(buffer, nbytes);
+ }
+}
+
+static inline
+void make_readable_untyped ( void* buffer, long nbytes )
+{
+ if (nbytes > 0) {
+ VALGRIND_MAKE_READABLE(buffer, nbytes);
+ }
+}
+
+static inline
+void make_readable_if_success_untyped ( int err,=20
+ void* buffer, long nbytes )
+{
+ if (err =3D=3D MPI_SUCCESS && nbytes > 0) {
+ VALGRIND_MAKE_READABLE(buffer, nbytes);
+ }
+}
+
+/* Set the specified area to 'addressible but undefined'
+ (safe-to-write) state. */
+
+static inline
+void make_writable_untyped ( void* buffer, long nbytes )
+{
+ if (nbytes > 0) {
+ VALGRIND_MAKE_WRITABLE(buffer, nbytes);
+ }
+}
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- 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 lampi-1.5.12. Hopefully ---*/
+/*--- it is a complete list of all the MPI 1.1 functions. ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/* Handy abbreviation */
+#define WRAPPER_FOR(name) I_WRAP_FNNAME_U(name)
+
+/* Generates a wrapper which aborts when called. */
+#define UNIMPLEMENTED_WRAPPER(name) \
+ void I_WRAP_FNNAME_U(PMPI_##name) ( void ) \
+ { \
+ fprintf(stderr, "%s %5d: UNIMPLEMENTED wrapper: " \
+ "PMPI_%s\n", \
+ preamble, my_pid, #name); \
+ fprintf(stderr, "%s %5d: exiting now.\n", \
+ preamble, my_pid); \
+ exit(1); \
+ }
+
+/* Generates (conceptually) a wrapper which does nothing. In
+ fact just generate no wrapper at all. */
+#define NO_OP_WRAPPER(name) /* */
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Sec 3.2, Blocking Send and Receive Operations ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/* --- Send --- */
+/* pre: rd: (buf,count,datatype) */
+int WRAPPER_FOR(PMPI_Send)(void *buf, int count, MPI_Datatype datatype,=20
+ int dest, int tag, MPI_Comm comm)
+{
+ OrigFn fn;
+ int err;
+ VALGRIND_GET_ORIG_FN(fn);
+ before("Send");
+ check_readable(buf, count, datatype);
+ CALL_FN_W_6W(err, fn, buf,count,datatype,dest,tag,comm);
+ after("Send", err);
+ return err;
+}
+
+UNIMPLEMENTED_WRAPPER(Bsend)
+UNIMPLEMENTED_WRAPPER(Ssend)
+UNIMPLEMENTED_WRAPPER(Rsend)
+
+/* --- 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,=20
+ int source, int tag,=20
+ MPI_Comm comm, MPI_Status *status)
+{
+ OrigFn fn;
+ int err, recv_count =3D 0;
+ VALGRIND_GET_ORIG_FN(fn);
+ before("Recv");
+ check_writable(buf, count, datatype);
+ check_writable_untyped(status, sizeof(*status));
+ CALL_FN_W_7W(err, fn, buf,count,datatype,source,tag,comm,status);
+ if (err =3D=3D MPI_SUCCESS && count_from_Status(&recv_count,datatype,=
status)) {
+ make_readable(buf, recv_count, datatype);
+ }
+ after("Recv", err);
+ return err;
+}
+
+/* PMPI_Get_count is used by this library (no matter, we just need to
+ supply a wrapper). Since there's nothing much to wrap, supply a
+ no-op wrapper. */
+NO_OP_WRAPPER(Get_count)
+
+UNIMPLEMENTED_WRAPPER(Buffer_attach)
+UNIMPLEMENTED_WRAPPER(Buffer_detach)
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Sec 3.7, Nonblocking communication ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+typedef
+ struct {
+ Bool inUse;
+ MPI_Request key;
+ void* buf;
+ int count;
+ MPI_Datatype datatype;
+ }
+ ShadowRequest;
+
+static ShadowRequest* sReqs =3D NULL;
+static int sReqs_size =3D 0;
+static int sReqs_used =3D 0;
+//static pthread_mutex_t sReqs_lock =3D PTHREAD_MUTEX_INITIALIZER;
+
+
+/* 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 =3D=3D sReqs_size) {
+ sReqs_size =3D sReqs_size=3D=3D0 ? 2 : 2*sReqs_size;
+ sReqs2 =3D malloc( sReqs_size * sizeof(ShadowRequest) );
+ if (sReqs2 =3D=3D NULL) {
+ /* UNLOCK */
+ barf("add_shadow_Request: malloc failed.\n");
+ }
+ for (i =3D 0; i < sReqs_used; i++)
+ sReqs2[i] =3D sReqs[i];
+ if (sReqs)
+ free(sReqs);
+ sReqs =3D sReqs2;
+ }
+ assert(sReqs_used < sReqs_size);
+}
+
+
+/* Find shadow info for 'request', or NULL if none. */
+
+static=20
+ShadowRequest* find_shadow_Request ( MPI_Request request )
+{
+ ShadowRequest* ret =3D NULL;
+ int i;
+ /* LOCK */
+ for (i =3D 0; i < sReqs_used; i++) {
+ if (sReqs[i].inUse && eq_MPI_Request(sReqs[i].key,request)) {
+ ret =3D &sReqs[i];
+ break;
+ }
+ }
+ /* UNLOCK */
+ return ret;
+}
+
+
+/* Delete shadow info for 'request', if any. */
+
+static void delete_shadow_Request ( MPI_Request request )
+{
+ int i;
+ /* LOCK */
+ for (i =3D 0; i < sReqs_used; i++) {
+ if (sReqs[i].inUse && eq_MPI_Request(sReqs[i].key,request)) {
+ sReqs[i].inUse =3D False;
+ break;
+ }
+ }
+ /* UNLOCK */
+}
+
+
+/* Add a shadow for 'request', overwriting any old binding for it. */
+
+static=20
+void add_shadow_Request( MPI_Request request,=20
+ void* buf, int count,=20
+ MPI_Datatype datatype )
+{
+ int i, ix =3D -1;
+ /* LOCK */
+ assert(sReqs_used >=3D 0);
+ assert(sReqs_size >=3D 0);
+ assert(sReqs_used <=3D sReqs_size);
+ if (sReqs =3D=3D NULL) assert(sReqs_size =3D=3D 0);
+
+ /* First of all see if we already have a binding for this key; if
+ so just replace it, and have done. */
+ for (i =3D 0; i < sReqs_used; i++) {
+ if (sReqs[i].inUse && eq_MPI_Request(sReqs[i].key,request)) {
+ ix =3D 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 =3D 0; i < sReqs_used; i++) {
+ if (!sReqs[i].inUse) {
+ ix =3D i;
+ break;
+ }
+ }
+ }
+
+ /* No empty slots. Allocate a new one. */
+ if (ix < 0) {
+ ensure_sReq_space();
+ assert(sReqs_used < sReqs_size);
+ ix =3D sReqs_used;
+ sReqs_used++;
+ }
+
+ assert(ix >=3D 0 && ix < sReqs_used);
+ assert(sReqs_used <=3D sReqs_size);
+
+ sReqs[ix].inUse =3D True;
+ sReqs[ix].key =3D request;
+ sReqs[ix].buf =3D buf;
+ sReqs[ix].count =3D count;
+ sReqs[ix].datatype =3D datatype;
+
+ /* UNLOCK */
+ if (opt_verbose)
+ fprintf(stderr, "%s %5d: sReq+ 0x%lx -> b/c/d %p/%d/0x%lx [slot %d=
]\n",
+ preamble, my_pid, (unsigned long)request,=20
+ buf, count, (long)datatype, ix);
+}
+
+
+static void maybe_complete ( Bool error_in_status,
+ MPI_Request request_before,
+ MPI_Request request_after,
+ MPI_Status* status )
+{
+ int recv_count =3D 0;
+ ShadowRequest* shadow;
+ /* How do we know if this is an Irecv request that has now
+ finished successfully?=20
+ =20
+ 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 =3D=3D False, then we expect not to get
+ called at all if there was an error.)
+ */
+ if (request_before !=3D MPI_REQUEST_NULL
+ && request_after =3D=3D MPI_REQUEST_NULL
+ && (error_in_status ? status->MPI_ERROR =3D=3D MPI_SUCCESS : True=
)
+ && ( (shadow=3Dfind_shadow_Request(request_before)) !=3D NULL) ) =
{
+ /* The Irecv detailed in 'shadow' completed. Make the result
+ buffer, and delete the entry. */
+ if (count_from_Status(&recv_count, shadow->datatype, status)) {
+ make_readable(shadow->buf, recv_count, shadow->datatype);
+ if (opt_verbose)
+ fprintf(stderr, "%s %5d: sReq- %p (completed)\n",=20
+ preamble, my_pid, request_before);
+ }
+ delete_shadow_Request(request_before);
+ }
+}
+
+
+static=20
+MPI_Request* clone_Request_array ( int count, MPI_Request* orig )
+{
+ MPI_Request* copy;
+ int i;
+ if (count < 0)=20
+ count =3D 0; /* Hmm. Call Mulder and Scully. */
+ copy =3D malloc( count * sizeof(MPI_Request) );
+ if (copy =3D=3D NULL)
+ barf("clone_Request_array: malloc failed");
+ for (i =3D 0; i < count; i++)
+ copy[i] =3D orig[i];
+ return copy;
+}
+
+
+/* --- Isend --- */
+/* rd: (buf,count,datatype) */
+/* wr: *request */
+int WRAPPER_FOR(PMPI_Isend)(void *buf, int count, MPI_Datatype datatype,=
=20
+ int dest, int tag, MPI_Comm comm,=20
+ MPI_Request* request)
+{
+ OrigFn fn;
+ int err;
+ VALGRIND_GET_ORIG_FN(fn);
+ before("Isend");
+ check_readable(buf, count, datatype);
+ check_writable_untyped(request, sizeof(*request));
+ CALL_FN_W_7W(err, fn, buf,count,datatype,dest,tag,comm,request);
+ make_readable_if_success_untyped(err, request, sizeof(*request));
+ after("Isend", err);
+ return err;
+}
+
+UNIMPLEMENTED_WRAPPER(Ibsend)
+UNIMPLEMENTED_WRAPPER(Issend)
+UNIMPLEMENTED_WRAPPER(Irsend)
+
+/* --- Irecv --- */
+/* pre: must be writable: (buf,count,datatype), *request
+ post: make readable *request
+ add a request->(buf,count,ty) binding to the=20
+ shadow request table.=20
+*/
+int WRAPPER_FOR(PMPI_Irecv)( void* buf, int count, MPI_Datatype datatype=
,=20
+ int source, int tag, MPI_Comm comm,=20
+ MPI_Request* request )
+{
+ OrigFn fn;
+ int err;
+ VALGRIND_GET_ORIG_FN(fn);
+ before("Irecv");
+ check_writable(buf, count, datatype);
+ check_writable_untyped(request, sizeof(*request));
+ CALL_FN_W_7W(err, fn, buf,count,datatype,source,tag,comm,request);
+ if (err =3D=3D MPI_SUCCESS) {
+ make_readable_untyped(request, sizeof(*request));
+ add_shadow_Request( *request, buf,count,datatype );
+ }
+ after("Irecv", err);
+ return err;
+}
+
+UNIMPLEMENTED_WRAPPER(Request_free)
+
+/* --- Wait --- */
+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_writable_untyped(status, sizeof(MPI_Status));
+ if (*request !=3D MPI_REQUEST_NULL)
+ check_readable_untyped(request, sizeof(MPI_Request));
+ request_before =3D *request;
+ CALL_FN_W_WW(err, fn, request,status);
+ if (err =3D=3D MPI_SUCCESS) {
+ maybe_complete(False/*err in status?*/,=20
+ request_before, *request, status);
+ make_readable_untyped(status, sizeof(MPI_Status));
+ }
+ after("Wait", err);
+ return err;
+}
+
+UNIMPLEMENTED_WRAPPER(Test)
+
+UNIMPLEMENTED_WRAPPER(Waitany)
+UNIMPLEMENTED_WRAPPER(Testany)
+
+/* --- Waitall --- */
+int WRAPPER_FOR(PMPI_Waitall)( int count,=20
+ MPI_Request* requests,
+ MPI_Status* statuses )
+{
+ MPI_Request* requests_before =3D NULL;
+ OrigFn fn;
+ int err, i;
+ VALGRIND_GET_ORIG_FN(fn);
+ before("Waitall");
+ if (0) fprintf(stderr, "Waitall: %d\n", count);
+ for (i =3D 0; i < count; i++) {
+ check_writable_untyped(&statuses[i], sizeof(MPI_Status));
+ if (requests[i] !=3D MPI_REQUEST_NULL)
+ check_readable_untyped(&requests[i], sizeof(MPI_Request));
+ }
+ requests_before =3D clone_Request_array( count, requests );
+ CALL_FN_W_WWW(err, fn, count,requests,statuses);
+ if (err =3D=3D MPI_SUCCESS /*complete success*/
+ || err =3D=3D MPI_ERR_IN_STATUS /* partial success */) {
+ Bool e_i_s =3D err =3D=3D MPI_ERR_IN_STATUS;
+ for (i =3D 0; i < count; i++) {
+ maybe_complete(e_i_s, requests_before[i], requests[i],=20
+ &statuses[i]);
+ make_readable_untyped(&statuses[i], sizeof(MPI_Status));
+ }
+ }
+ if (requests_before)
+ free(requests_before);
+ after("Waitall", err);
+ return err;
+}
+
+UNIMPLEMENTED_WRAPPER(Testall)
+
+UNIMPLEMENTED_WRAPPER(Waitsome)
+UNIMPLEMENTED_WRAPPER(Testsome)
+
+UNIMPLEMENTED_WRAPPER(Probe)
+
+/* --- Iprobe --- */
+/* very unclear about this */
+/* pre: must-be-writable: *flag, *status */
+/* post: make-readable *flag
+ if *flag=3D=3DTrue make-readable *status
+ if *flag=3D=3DFalse make-uninitialised *status */
+int WRAPPER_FOR(PMPI_Iprobe)(int source, int tag,=20
+ MPI_Comm comm,=20
+ int* flag, MPI_Status* status)
+{
+ OrigFn fn;
+ int err;
+ VALGRIND_GET_ORIG_FN(fn);
+ before("Iprobe");
+ check_writable_untyped(flag, sizeof(*flag));
+ check_writable_untyped(status, sizeof(*status));
+ CALL_FN_W_5W(err, fn, source,tag,comm,flag,status);
+ if (err =3D=3D MPI_SUCCESS) {
+ make_readable_untyped(flag, sizeof(*flag));
+ if (*flag)
+ make_readable_untyped(status, sizeof(*status));
+ else
+ make_writable_untyped(status, sizeof(*status));
+ }
+ after("Iprobe", err);
+ return err;
+}
+
+UNIMPLEMENTED_WRAPPER(Cancel)
+UNIMPLEMENTED_WRAPPER(Test_cancelled)
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- 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,=20
+ void *recvbuf, int recvcount, MPI_Datatype recvtype,=20
+ int source, int recvtag,
+ MPI_Comm comm, MPI_Status *status)
+{
+ OrigFn fn;
+ int err, recvcount_actual =3D 0;
+ VALGRIND_GET_ORIG_FN(fn);
+ before("Sendrecv");
+ check_readable(sendbuf, sendcount, sendtype);
+ check_writable(recvbuf, recvcount, recvtype);
+ CALL_FN_W_12W(err, fn, sendbuf,sendcount,sendtype,dest,sendtag,
+ recvbuf,recvcount,recvtype,source,recvtag,
+ comm,status);
+ if (err =3D=3D MPI_SUCCESS=20
+ && count_from_Status(&recvcount_actual,recvtype,status)) {
+ make_readable(recvbuf, recvcount_actual, recvtype);
+ }
+ after("Sendrecv", err);
+ return err;
+}
+
+UNIMPLEMENTED_WRAPPER(Sendrecv_replace)
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Sec 3.12, Derived datatypes ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/* --- Address --- */
+/* Does this have anything worth checking? */
+NO_OP_WRAPPER(PMPI_Address)
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Sec 4.4, Broadcast ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/* --- Bcast --- */
+/* pre: must-be-readable (buffer,count,datatype) for rank=3D=3Droot
+ must-be-writable (buffer,count,datatype) for rank!=3Droot
+ 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,=20
+ 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 =3D root =3D=3D comm_rank(comm);
+ if (i_am_sender) {
+ check_readable(buffer, count, datatype);
+ } else {
+ check_writable(buffer, count, datatype);
+ }
+ CALL_FN_W_5W(err, fn, buffer,count,datatype,root,comm);
+ make_readable_if_success(err, buffer, count, datatype);
+ after("Bcast", err);
+ return err;=20
+}
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- 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,r=
ecvtype)
+ post: (root only): make readable: (recvbuf,recvcount * comm_size,recv=
type)
+*/
+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 =3D comm_rank(comm);
+ sz =3D comm_size(comm);
+ check_readable(sendbuf, sendcount, sendtype);
+ if (me =3D=3D root)
+ check_writable(recvbuf, recvcount * sz, recvtype);
+ CALL_FN_W_8W(err, fn, sendbuf,sendcount,sendtype,
+ recvbuf,recvcount,recvtype,
+ root,comm);
+ make_readable_if_success(err, recvbuf, recvcount * sz, recvtype);
+ after("Gather", err);
+ return err;
+}
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Sec 4.9, Global Reduction Operations ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/* --- Reduce --- */
+/* rd: (sendbuf,count,datatype) for all
+ wr: (recvbuf,count,datatype) but only for rank =3D=3D root
+*/
+int WRAPPER_FOR(PMPI_Reduce)(void *sendbuf, void *recvbuf,=20
+ int count,
+ MPI_Datatype datatype, MPI_Op op,=20
+ int root, MPI_Comm comm)
+{
+ OrigFn fn;
+ int err;
+ Bool i_am_root;
+ VALGRIND_GET_ORIG_FN(fn);
+ before("Reduce");
+ i_am_root =3D root =3D=3D comm_rank(comm);
+ check_readable(sendbuf, count, datatype);
+ if (i_am_root)
+ check_writable(recvbuf, count, datatype);
+ CALL_FN_W_7W(err, fn, sendbuf,recvbuf,count,datatype,op,root,comm);
+ if (i_am_root)
+ make_readable_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,=20
+ int count,
+ MPI_Datatype datatype, MPI_Op op,=20
+ MPI_Comm comm)
+{
+ OrigFn fn;
+ int err;
+ VALGRIND_GET_ORIG_FN(fn);
+ before("Allreduce");
+ check_readable(sendbuf, count, datatype);
+ check_writable(recvbuf, count, datatype);
+ CALL_FN_W_6W(err, fn, sendbuf,recvbuf,count,datatype,op,comm);
+ make_readable_if_success(err, recvbuf, count, datatype);
+ after("Allreduce", err);
+ return err;
+}
+
+
+/* --- Op_create --- */
+/* This is a bit dubious. I suppose it takes 'function' and=20
+ writes something at *op, but who knows what an MPI_Op is?=20
+ Can we safely do 'sizeof' on it? */
+int WRAPPER_FOR(PMPI_Op_create)( MPI_User_function* function,
+ int commute,=20
+ MPI_Op* op )
+{
+ OrigFn fn;
+ int err;
+ VALGRIND_GET_ORIG_FN(fn);
+ before("Op_create");
+ check_writable_untyped(op, sizeof(*op));
+ CALL_FN_W_WWW(err, fn, function,commute,op);
+ make_readable_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_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_writable_untyped(rank, sizeof(*rank));
+ CALL_FN_W_WW(err, fn, comm,rank);
+ make_readable_if_success_untyped(err, rank, sizeof(*rank));
+ after("Comm_rank", err);
+ return err;
+}
+
+UNIMPLEMENTED_WRAPPER(Comm_remote_group)
+UNIMPLEMENTED_WRAPPER(Comm_remote_size)
+UNIMPLEMENTED_WRAPPER(Comm_set_errhandler)
+
+/* The MPI 1.1 doc doesn't appear to mention this. */
+NO_OP_WRAPPER(Comm_set_name)
+
+/* --- 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_writable_untyped(size, sizeof(*size));
+ CALL_FN_W_WW(err, fn, comm,size);
+ make_readable_if_success_untyped(err, size, sizeof(*size));
+ after("Comm_size", err);
+ return err;
+}
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Sec 5.7, Caching ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/* This messes with a couple of function pointers, an int* and an
+ "extra state" area of indeterminate size. I don't think there's
+ much we can check here. Hence: */
+NO_OP_WRAPPER(Keyval_create)
+
+/* Similar comment to Keyval_create */
+NO_OP_WRAPPER(Keyval_free)
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Sec 7.5, Startup ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/* --- Init --- */
+/* rd: *argc, *argv[0 .. *argc-1] */
+int WRAPPER_FOR(PMPI_Init)(int *argc, char ***argv)
+{
+ OrigFn fn;
+ int err;
+ VALGRIND_GET_ORIG_FN(fn);
+ before("Init");
+ check_readable_untyped(argc, sizeof(int));
+ check_readable_untyped(*argv, *argc * sizeof(char**));
+ CALL_FN_W_WW(err, fn, argc,argv);
+ after("Init", err);
+ return err;
+}
+
+/* --- Initialized --- */
+int WRAPPER_FOR(PMPI_Initialized)(int* flag)
+{
+ OrigFn fn;
+ int err;
+ VALGRIND_GET_ORIG_FN(fn);
+ before("Initialized");
+ check_writable_untyped(flag, sizeof(int));
+ CALL_FN_W_W(err, fn, flag);
+ make_readable_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;
+}
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+
+
+/* Here are the wrappers themselves. */
+UNIMPLEMENTED_WRAPPER(Abort)
+
+
+
+UNIMPLEMENTED_WRAPPER(Allgather)
+UNIMPLEMENTED_WRAPPER(Allgatherv)
+
+
+UNIMPLEMENTED_WRAPPER(Alltoall)
+UNIMPLEMENTED_WRAPPER(Alltoallv)
+UNIMPLEMENTED_WRAPPER(Alltoallw)
+UNIMPLEMENTED_WRAPPER(Attr_delete)
+NO_OP_WRAPPER(Attr_get)
+NO_OP_WRAPPER(Attr_put)
+NO_OP_WRAPPER(Barrier)
+
+
+UNIMPLEMENTED_WRAPPER(Bsend_init)
+UNIMPLEMENTED_WRAPPER(Cart_coords)
+UNIMPLEMENTED_WRAPPER(Cart_create)
+UNIMPLEMENTED_WRAPPER(Cart_get)
+UNIMPLEMENTED_WRAPPER(Cart_map)
+UNIMPLEMENTED_WRAPPER(Cart_rank)
+UNIMPLEMENTED_WRAPPER(Cart_shift)
+UNIMPLEMENTED_WRAPPER(Cart_sub)
+UNIMPLEMENTED_WRAPPER(Cartdim_get)
+UNIMPLEMENTED_WRAPPER(Comm_compare)
+NO_OP_WRAPPER(Comm_create)
+UNIMPLEMENTED_WRAPPER(Comm_create_errhandler)
+UNIMPLEMENTED_WRAPPER(Comm_dup)
+NO_OP_WRAPPER(Comm_free)
+UNIMPLEMENTED_WRAPPER(Comm_free_errhandler)
+UNIMPLEMENTED_WRAPPER(Comm_get_errhandler)
+UNIMPLEMENTED_WRAPPER(Comm_get_name)
+NO_OP_WRAPPER(Comm_group)
+
+
+UNIMPLEMENTED_WRAPPER(Comm_split)
+UNIMPLEMENTED_WRAPPER(Comm_test_inter)
+UNIMPLEMENTED_WRAPPER(Dims_create)
+UNIMPLEMENTED_WRAPPER(Errhandler_create)
+
+//UNIMPLEMENTED_WRAPPER(Errhandler_free)
+NO_OP_WRAPPER(Errhandler_free)
+
+UNIMPLEMENTED_WRAPPER(Errhandler_get)
+
+//UNIMPLEMENTED_WRAPPER(Errhandler_set)
+NO_OP_WRAPPER(Errhandler_set)
+
+UNIMPLEMENTED_WRAPPER(Error_class)
+UNIMPLEMENTED_WRAPPER(Error_string)
+
+UNIMPLEMENTED_WRAPPER(Finalized)
+
+
+UNIMPLEMENTED_WRAPPER(Gatherv)
+UNIMPLEMENTED_WRAPPER(Get_address)
+
+
+UNIMPLEMENTED_WRAPPER(Get_elements)
+NO_OP_WRAPPER(Get_processor_name)
+UNIMPLEMENTED_WRAPPER(Get_version)
+UNIMPLEMENTED_WRAPPER(Graph_create)
+UNIMPLEMENTED_WRAPPER(Graph_get)
+UNIMPLEMENTED_WRAPPER(Graph_map)
+UNIMPLEMENTED_WRAPPER(Graph_neighbors)
+UNIMPLEMENTED_WRAPPER(Graph_neighbors_count)
+UNIMPLEMENTED_WRAPPER(Graphdims_get)
+UNIMPLEMENTED_WRAPPER(Group_compare)
+UNIMPLEMENTED_WRAPPER(Group_difference)
+NO_OP_WRAPPER(Group_excl)
+NO_OP_WRAPPER(Group_free)
+NO_OP_WRAPPER(Group_incl)
+UNIMPLEMENTED_WRAPPER(Group_intersection)
+UNIMPLEMENTED_WRAPPER(Group_range_excl)
+UNIMPLEMENTED_WRAPPER(Group_range_incl)
+UNIMPLEMENTED_WRAPPER(Group_rank)
+UNIMPLEMENTED_WRAPPER(Group_size)
+UNIMPLEMENTED_WRAPPER(Group_translate_ranks)
+UNIMPLEMENTED_WRAPPER(Group_union)
+
+
+UNIMPLEMENTED_WRAPPER(Init_thread)
+
+
+UNIMPLEMENTED_WRAPPER(Intercomm_create)
+UNIMPLEMENTED_WRAPPER(Intercomm_merge)
+
+
+
+NO_OP_WRAPPER(Op_free)
+UNIMPLEMENTED_WRAPPER(Pack)
+UNIMPLEMENTED_WRAPPER(Pack_size)
+UNIMPLEMENTED_WRAPPER(Pcontrol)
+UNIMPLEMENTED_WRAPPER(Query_thread)
+
+
+UNIMPLEMENTED_WRAPPER(Recv_init)
+
+
+UNIMPLEMENTED_WRAPPER(Reduce_scatter)
+UNIMPLEMENTED_WRAPPER(Rsend_init)
+UNIMPLEMENTED_WRAPPER(Scan)
+UNIMPLEMENTED_WRAPPER(Scatter)
+UNIMPLEMENTED_WRAPPER(Scatterv)
+
+
+UNIMPLEMENTED_WRAPPER(Send_init)
+
+
+UNIMPLEMENTED_WRAPPER(Ssend_init)
+UNIMPLEMENTED_WRAPPER(Start)
+UNIMPLEMENTED_WRAPPER(Startall)
+UNIMPLEMENTED_WRAPPER(Status_set_cancelled)
+UNIMPLEMENTED_WRAPPER(Status_set_elements)
+UNIMPLEMENTED_WRAPPER(Topo_test)
+
+//UNIMPLEMENTED_WRAPPER(Type_commit)
+NO_OP_WRAPPER(Type_commit)
+
+//UNIMPLEMENTED_WRAPPER(Type_contiguous)
+NO_OP_WRAPPER(Type_contiguous)
+
+UNIMPLEMENTED_WRAPPER(Type_count)
+UNIMPLEMENTED_WRAPPER(Type_create_darray)
+UNIMPLEMENTED_WRAPPER(Type_create_subarray)
+UNIMPLEMENTED_WRAPPER(Type_extent)
+UNIMPLEMENTED_WRAPPER(Type_free)
+UNIMPLEMENTED_WRAPPER(Type_get_contents)
+UNIMPLEMENTED_WRAPPER(Type_get_envelope)
+UNIMPLEMENTED_WRAPPER(Type_get_name)
+UNIMPLEMENTED_WRAPPER(Type_create_hindexed)
+UNIMPLEMENTED_WRAPPER(Type_create_hvector)
+
+//UNIMPLEMENTED_WRAPPER(Type_create_struct)
+NO_OP_WRAPPER(Type_create_struct)
+
+UNIMPLEMENTED_WRAPPER(Type_hindexed)
+UNIMPLEMENTED_WRAPPER(Type_hvector)
+UNIMPLEMENTED_WRAPPER(Type_indexed)
+UNIMPLEMENTED_WRAPPER(Type_lb)
+UNIMPLEMENTED_WRAPPER(Type_set_name)
+UNIMPLEMENTED_WRAPPER(Type_size)
+
+//UNIMPLEMENTED_WRAPPER(Type_struct)
+NO_OP_WRAPPER(Type_struct)
+
+UNIMPLEMENTED_WRAPPER(Type_ub)
+UNIMPLEMENTED_WRAPPER(Type_vector)
+UNIMPLEMENTED_WRAPPER(Unpack)
+
+
+UNIMPLEMENTED_WRAPPER(Win_create_errhandler)
+UNIMPLEMENTED_WRAPPER(Win_free_errhandler)
+UNIMPLEMENTED_WRAPPER(Win_get_errhandler)
+UNIMPLEMENTED_WRAPPER(Win_set_errhandler)
+NO_OP_WRAPPER(Wtick)
+NO_OP_WRAPPER(Wtime)
+
+
+/*---------------------------------------------------------------*/
+/*--- end mpiwrap.c ---*/
+/*---------------------------------------------------------------*/
|
|
From: Ashley P. <as...@qu...> - 2006-02-20 10:42:40
|
On Sat, 2006-02-18 at 23:13 +0000, sv...@va... wrote: > Log: > First try at an MPI wrappers library. Currently the build system > ignores it - it must be built by hand. Looks interesting, Having read through it I've got a couple of questions for you though (I'll try and keep this short). Why did you use the PMPI functions? I'd have expected the MPI ones to be ok although I guess wrapping weak symbols is different to wrapping normal ones? How is this intended to be used on a practical level?, my understanding is that that function wrappers are executed in the client address space, are you assuming a LD_PRELOAD trick to load this file with the application or is there another way these get loaded? What does the stack trace look like when one of the client checks reports an error, does it include the MPI function name the check is targeted at? The before function could be called from a (P)MPI_Init wrapper, the standard says this is the only function that's safe to call at startup, likewise MPI_Finalize could (should?) do assertion checks that all shadowrequests are free. The standard itself mandates this and some implementations check it but I'm not sure you have wrapped all places these are allocated/destroyed so it's possible you've got a leak here. It's hard to see what the wrappers for Wait/Waitall are going to catch that valgrind wouldn't pick up anyway, they only handle metadata describing comms so should be tracked already by valgrind like any other data in a program. Likewise for Iprobe and OP_create. I'd say MPI_Waitsome, MPI_Alltoall and MPI_Allgather would warrant wrappers as they tend to get used fairly often. The converse is true for MPI_Op_create. I should get a chance to give this code a spin later so I'll be able to give you more feedback then. Ashley, |