Merge pull request #78 from Alessandro624/fix-mpi-ale

fix(MPI): resolved cyclic inclusion and MPI issue
This commit is contained in:
Johann Dreo 2025-03-21 09:05:54 +01:00 committed by GitHub
commit 3dc2058400
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -22,7 +22,7 @@ Authors:
#ifndef __EO_IMPL_MPI_HPP__ #ifndef __EO_IMPL_MPI_HPP__
#define __EO_IMPL_MPI_HPP__ #define __EO_IMPL_MPI_HPP__
#include "eoMpi.h" #include <mpi.h>
#include "../serial/eoSerial.h" #include "../serial/eoSerial.h"
/** /**
@ -43,290 +43,288 @@ Authors:
*/ */
namespace eo namespace eo
{ {
namespace mpi namespace mpi
{
/**
* @ingroup Parallel
* @{
*/
/**
* @brief Constant indicating that a message can come from any process.
*/
extern const int any_source;
/**
* @brief Constant indicating that a message can come from any tag (channel).
*/
extern const int any_tag;
/**
* @brief Wrapper class to have a MPI environment.
*
* Instead of calling MPI_Init and MPI_Finalize, it is only necessary to instantiate
* this class once, in the global context.
*/
class environment
{ {
public: /**
* @ingroup Parallel
* @{
*/
/** /**
* @brief Inits MPI context. * @brief Constant indicating that a message can come from any process.
*/
extern const int any_source;
/**
* @brief Constant indicating that a message can come from any tag (channel).
*/
extern const int any_tag;
/**
* @brief Wrapper class to have a MPI environment.
* *
* @param argc Number of params in command line (same as one in main) * Instead of calling MPI_Init and MPI_Finalize, it is only necessary to instantiate
* @param argv Strings containing params (same as one in main) * this class once, in the global context.
*/ */
environment(int argc, char**argv); class environment
{
/**
* @brief Closes MPI context.
*/
~environment();
};
struct MPI_Status {
int count;
int cancelled;
int MPI_SOURCE;
int MPI_TAG;
int MPI_ERROR;
};
/**
* @brief Wrapper class for MPI_Status
*
* Consists only in a C++ wrapper class, giving getters on status attributes.
*/
class status
{
public: public:
/**
* @brief Inits MPI context.
*
* @param argc Number of params in command line (same as one in main)
* @param argv Strings containing params (same as one in main)
*/
environment(int argc, char **argv);
/**
* @brief Closes MPI context.
*/
~environment();
};
/* struct MPI_Status
{
int count;
int cancelled;
int MPI_SOURCE;
int MPI_TAG;
int MPI_ERROR;
}; */
/** /**
* @brief Converts a MPI_Status into a status. * @brief Wrapper class for MPI_Status
*
* Consists only in a C++ wrapper class, giving getters on status attributes.
*/ */
status( const MPI_Status & s ); class status
{
public:
/**
* @brief Converts a MPI_Status into a status.
*/
status(const MPI_Status &s);
/** /**
* @brief Returns the tag of the associated communication. * @brief Returns the tag of the associated communication.
*/ */
int tag() { return _tag; } int tag() { return _tag; }
/** /**
* @brief Indicates which error number we obtained in the associated communication. * @brief Indicates which error number we obtained in the associated communication.
*/ */
int error() { return _error; } int error() { return _error; }
/** /**
* @brief Returns the MPI rank of the source of the associated communication. * @brief Returns the MPI rank of the source of the associated communication.
*/ */
int source() { return _source; } int source() { return _source; }
private: private:
int _source; int _source;
int _tag; int _tag;
int _error; int _error;
}; };
/** /**
* @brief Main object, used to send / receive messages, get informations about the rank and the size of the world, * @brief Main object, used to send / receive messages, get informations about the rank and the size of the world,
* etc. * etc.
*/ */
class communicator class communicator
{ {
public: public:
/**
* Creates the communicator, using the whole world as a MPI_Comm.
*
* @todo Allow the user to precise which MPI_Comm to use
*/
communicator();
/** ~communicator();
* Creates the communicator, using the whole world as a MPI_Comm.
*
* @todo Allow the user to precise which MPI_Comm to use
*/
communicator( );
~communicator(); /**
* @brief Returns the MPI rank of the current process.
*/
int rank();
/** /**
* @brief Returns the MPI rank of the current process. * @brief Returns the size of the MPI cluster.
*/ */
int rank(); int size();
/** /*
* @brief Returns the size of the MPI cluster. * SEND / RECV INT
*/ */
int size();
/* /**
* SEND / RECV INT * @brief Sends an integer to dest on channel "tag".
*/ *
* @param dest MPI rank of the receiver
* @param tag MPI tag of message
* @param n The integer to send
*/
void send(int dest, int tag, int n);
/** /*
* @brief Sends an integer to dest on channel "tag". * @brief Receives an integer from src on channel "tag".
* *
* @param dest MPI rank of the receiver * @param src MPI rank of the sender
* @param tag MPI tag of message * @param tag MPI tag of message
* @param n The integer to send * @param n Where to save the received integer
*/ */
void send( int dest, int tag, int n ); void recv(int src, int tag, int &n);
/* /*
* @brief Receives an integer from src on channel "tag". * SEND / RECV STRING
* */
* @param src MPI rank of the sender
* @param tag MPI tag of message
* @param n Where to save the received integer
*/
void recv( int src, int tag, int& n );
/* /**
* SEND / RECV STRING * @brief Sends a string to dest on channel "tag".
*/ *
* @param dest MPI rank of the receiver
* @param tag MPI tag of message
* @param str The std::string to send
*/
void send(int dest, int tag, const std::string &str);
/** /*
* @brief Sends a string to dest on channel "tag". * @brief Receives a string from src on channel "tag".
* *
* @param dest MPI rank of the receiver * @param src MPI rank of the sender
* @param tag MPI tag of message * @param tag MPI tag of message
* @param str The std::string to send * @param std::string Where to save the received string
*/ */
void send( int dest, int tag, const std::string& str ); void recv(int src, int tag, std::string &str);
/* /*
* @brief Receives a string from src on channel "tag". * SEND / RECV Objects
* */
* @param src MPI rank of the sender
* @param tag MPI tag of message
* @param std::string Where to save the received string
*/
void recv( int src, int tag, std::string& str );
/* /**
* SEND / RECV Objects * @brief Sends an eoserial::Persistent to dest on channel "tag".
*/ *
* @param dest MPI rank of the receiver
* @param tag MPI tag of message
* @param persistent The object to send (it must absolutely implement eoserial::Persistent)
*/
void send(int dest, int tag, const eoserial::Persistent &persistent);
/** /**
* @brief Sends an eoserial::Persistent to dest on channel "tag". * @brief Sends an array of eoserial::Persistent to dest on channel "tag".
* *
* @param dest MPI rank of the receiver * @param dest MPI rank of the receiver
* @param tag MPI tag of message * @param tag MPI tag of message
* @param persistent The object to send (it must absolutely implement eoserial::Persistent) * @param table The array of eoserial::Persistent objects
*/ * @param size The number of elements to send (no check is done, the user has to be sure that the size won't
void send( int dest, int tag, const eoserial::Persistent & persistent ); * overflow!)
*/
/** template <class T>
* @brief Sends an array of eoserial::Persistent to dest on channel "tag". void send(int dest, int tag, T *table, int size)
*
* @param dest MPI rank of the receiver
* @param tag MPI tag of message
* @param table The array of eoserial::Persistent objects
* @param size The number of elements to send (no check is done, the user has to be sure that the size won't
* overflow!)
*/
template< class T >
void send( int dest, int tag, T* table, int size )
{
// Puts all the values into an array
eoserial::Array* array = new eoserial::Array;
for( int i = 0; i < size; ++i )
{ {
array->push_back( table[i].pack() ); // Puts all the values into an array
eoserial::Array *array = new eoserial::Array;
for (int i = 0; i < size; ++i)
{
array->push_back(table[i].pack());
}
// Encapsulates the array into an object
eoserial::Object *obj = new eoserial::Object;
obj->add("array", array);
std::stringstream ss;
obj->print(ss);
delete obj;
// Sends the object as a string
send(dest, tag, ss.str());
} }
// Encapsulates the array into an object /*
eoserial::Object* obj = new eoserial::Object; * @brief Receives an eoserial::Persistent object from src on channel "tag".
obj->add( "array", array ); *
std::stringstream ss; * @param src MPI rank of the sender
obj->print( ss ); * @param tag MPI tag of message
delete obj; * @param persistent Where to unpack the serialized object?
*/
void recv(int src, int tag, eoserial::Persistent &persistent);
// Sends the object as a string /*
send( dest, tag, ss.str() ); * @brief Receives an array of eoserial::Persistent from src on channel "tag".
} *
* @param src MPI rank of the sender
/* * @param tag MPI tag of message
* @brief Receives an eoserial::Persistent object from src on channel "tag". * @param table The table in which we're saving the received objects. It must have been allocated by the user,
* * as no allocation is performed here.
* @param src MPI rank of the sender * @param size The number of elements to receive (no check is done, the user has to be sure that the size won't
* @param tag MPI tag of message * overflow!)
* @param persistent Where to unpack the serialized object? */
*/ template <class T>
void recv( int src, int tag, eoserial::Persistent & persistent ); void recv(int src, int tag, T *table, int size)
/*
* @brief Receives an array of eoserial::Persistent from src on channel "tag".
*
* @param src MPI rank of the sender
* @param tag MPI tag of message
* @param table The table in which we're saving the received objects. It must have been allocated by the user,
* as no allocation is performed here.
* @param size The number of elements to receive (no check is done, the user has to be sure that the size won't
* overflow!)
*/
template< class T >
void recv( int src, int tag, T* table, int size )
{
// Receives the string which contains the object
std::string asText;
recv( src, tag, asText );
// Parses the object and retrieves the table
eoserial::Object* obj = eoserial::Parser::parse( asText );
eoserial::Array* array = static_cast<eoserial::Array*>( (*obj)["array"] );
// Retrieves all the values from the array
for( int i = 0; i < size; ++i )
{ {
eoserial::unpackObject( *array, i, table[i] ); // Receives the string which contains the object
std::string asText;
recv(src, tag, asText);
// Parses the object and retrieves the table
eoserial::Object *obj = eoserial::Parser::parse(asText);
eoserial::Array *array = static_cast<eoserial::Array *>((*obj)["array"]);
// Retrieves all the values from the array
for (int i = 0; i < size; ++i)
{
eoserial::unpackObject(*array, i, table[i]);
}
delete obj;
} }
delete obj;
}
/* /*
* Other methods * Other methods
*/ */
/** /**
* @brief Wrapper for MPI_Probe * @brief Wrapper for MPI_Probe
* *
* Waits for a message to come from process having rank src, on the channel * Waits for a message to come from process having rank src, on the channel
* tag. * tag.
* *
* @param src MPI rank of the sender (any_source if it can be any sender) * @param src MPI rank of the sender (any_source if it can be any sender)
* @param tag MPI tag of the expected message (any_tag if it can be any tag) * @param tag MPI tag of the expected message (any_tag if it can be any tag)
*/ */
status probe( int src = any_source, int tag = any_tag ); status probe(int src = any_source, int tag = any_tag);
/** /**
* @brief Wrapper for MPI_Barrier * @brief Wrapper for MPI_Barrier
* *
* *
*/ */
void barrier(); void barrier();
private: private:
int _rank; int _rank;
int _size; int _size;
char* _buf; // temporary buffer for sending and receiving strings. Avoids reallocations char *_buf; // temporary buffer for sending and receiving strings. Avoids reallocations
int _bufsize; // size of the above temporary buffer int _bufsize; // size of the above temporary buffer
}; };
/** /**
* @brief Wrapper for MPI_Bcast * @brief Wrapper for MPI_Bcast
* *
* Broadcasts an integer value on the communicator comm, from the process having the MPI rank root. * Broadcasts an integer value on the communicator comm, from the process having the MPI rank root.
* *
* @param comm The communicator on which to broadcast * @param comm The communicator on which to broadcast
* @param value The integer value to send * @param value The integer value to send
* @param root The MPI rank of the broadcaster * @param root The MPI rank of the broadcaster
* *
* @todo Actually comm isn't used and broadcast is performed on the whole MPI_COMM_WORLD. TODO: Use comm instead * @todo Actually comm isn't used and broadcast is performed on the whole MPI_COMM_WORLD. TODO: Use comm instead
*/ */
void broadcast( communicator & comm, int value, int root ); void broadcast(communicator &comm, int value, int root);
/** /**
* @} * @}
*/ */
} // namespace mpi } // namespace mpi
} // namespace eo } // namespace eo
# endif //__EO_IMPL_MPI_HPP__ #endif //__EO_IMPL_MPI_HPP__