This section specifies the requirements of a C++ profiling interface to MPI-/.
Native C++ MPI-/ implementations that do not have access to other profiling interfaces must implement an interface that meets the requirements outlined in this section.
High quality implementations can implement the interface outlined in this section in order to promote portable C++ profiling libraries. Implementors may wish to provide an option whether to build the C++ profiling interface or not; C++ implementations that are already layered on top of bindings in another language or another profiling interface will have to insert a third layer to implement the C++ profiling interface.(End of advice to implementors.)
To meet the requirements of the C++ MPI-/ profiling interface, an implementation of the MPI-/ functions must:
This is necessary to allow a separate profiling library to be correctly implemented, since (at least with Unix linker semantics) the profiling library must contain these wrapper functions if it is to perform as expected. This requirement allows the author of the profiling library to extract these functions from the original MPI-/ library and add them into the profiling library without bringing along any other unnecessary code.
The ``real'' entry points to each routine can be provided within a namespace PMPI. The non-profiling version can then be provided within a namespace MPI.
Caching instances of PMPI objects in the MPI handles provides the ``has a'' relationship that is necessary to implement the profiling scheme.
Each instance of an MPI object simply ``wraps up'' an instance of a PMPI object. MPI objects can then perform profiling actions before invoking the corresponding function in their internal PMPI object.
The key to making the profiling work by simply re-linking programs is by having a header file that declares all the MPI-/ functions. The functions must be defined elsewhere, and compiled into a library. MPI-/ constants should be declared extern in the MPI namespace. For example, the following is an excerpt from a sample mpi.h file:
namespace PMPI { class Comm { public: int Get_size() const; }; // etc. }; namespace MPI { public: class Comm { public: int Get_size() const; private: PMPI::Comm pmpi_comm; }; };
Note that all constructors, the assignment operator, and the destructor in the MPI class will need to initialize/destroy the internal PMPI object as appropriate.
The definitions of the functions must be in separate object files; the PMPI class member functions and the non-profiling versions of the MPI class member functions can be compiled into libmpi.a, while the profiling versions can be compiled into libpmpi.a. Note that the PMPI class member functions and the MPI constants must be in different object files than the non-profiling MPI class member functions in the libmpi.a library to prevent multiple definitions of MPI class member function names when linking both libmpi.a and libpmpi.a. For example:
int PMPI::Comm::Get_size() const { // Implementation of MPI_COMM_SIZE }
const MPI::Intracomm MPI::COMM_WORLD;
int MPI::Comm::Get_size() const { return pmpi_comm.Get_size(); }
int MPI::Comm::Get_size() const { // Do profiling stuff int ret = pmpi_comm.Get_size(); // More profiling stuff return ret; }
(End of advice to implementors.)
MPI-Standard for MARMOT