#pragma once #include #include #include "Configuration.hpp" #include "MpiEnvironment.hpp" #include "State.hpp" #include "Util.hpp" // creates the graph topology and does the communication class Communicator { constexpr static std::size_t NoNeighbors{8}; // for very small container with known max size, this is a performance // improvement template using Vector = boost::container::static_vector; public: // Life cycle handling for MPI_Requests class MpiRequest { // TODO: unnest public: template using DoubleVector = boost::container::static_vector; private: DoubleVector _reqs; bool finished{}; public: MpiRequest(DoubleVector reqs); MpiRequest(const MpiRequest&) = default; MpiRequest(MpiRequest&&) = default; MpiRequest& operator=(const MpiRequest&) = default; MpiRequest& operator=(MpiRequest&&) = default; void Wait(); ~MpiRequest(); }; protected: CommunicationMode _commMode; // data members for graph topology Vector _neighbors; Vector _sizes; Vector _sendTypes; const Vector& _recvTypes{_sendTypes}; Vector _sendDisplacements; Vector _recvDisplacements; MPI_Comm _commDistGraph{MPI_COMM_NULL}; // data types MPI_Datatype _haloRowType{}; MPI_Datatype _haloColumnType{}; MPI_Datatype _haloCornerType{MPI_CHAR}; public: Communicator() = default; Communicator(const MpiEnvironment& env, CommunicationMode commMode, const Size& gridSize, const Size& tileSize); virtual ~Communicator(); void swap(Communicator& first, Communicator& second); Communicator(Communicator&) = delete; Communicator& operator=(Communicator&) = delete; Communicator(Communicator&& other) noexcept; Communicator& operator=(Communicator&& other) noexcept; virtual void Communicate(State* model) = 0; virtual MpiRequest AsyncCommunicate(State* model) = 0; };