using simgrid::s4u::Actor;
+#include <tuple>
+// From https://stackoverflow.com/questions/7110301/generic-hash-for-tuples-in-unordered-map-unordered-set
+// This is all just to make std::unordered_map work with std::tuple. If we need this in other places,
+// this could go into a header file.
+namespace hash_tuple{
+ template <typename TT>
+ struct hash
+ {
+ size_t
+ operator()(TT const& tt) const
+ {
+ return std::hash<TT>()(tt);
+ }
+ };
+
+ template <class T>
+ inline void hash_combine(std::size_t& seed, T const& v)
+ {
+ seed ^= hash_tuple::hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
+ }
+
+ // Recursive template code derived from Matthieu M.
+ template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
+ struct HashValueImpl
+ {
+ static void apply(size_t& seed, Tuple const& tuple)
+ {
+ HashValueImpl<Tuple, Index-1>::apply(seed, tuple);
+ hash_combine(seed, std::get<Index>(tuple));
+ }
+ };
+
+ template <class Tuple>
+ struct HashValueImpl<Tuple,0>
+ {
+ static void apply(size_t& seed, Tuple const& tuple)
+ {
+ hash_combine(seed, std::get<0>(tuple));
+ }
+ };
+
+ template <typename ... TT>
+ struct hash<std::tuple<TT...>>
+ {
+ size_t
+ operator()(std::tuple<TT...> const& tt) const
+ {
+ size_t seed = 0;
+ HashValueImpl<std::tuple<TT...> >::apply(seed, tt);
+ return seed;
+ }
+ };
+}
+
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_replay,smpi,"Trace Replay with SMPI");
static std::unordered_map<int, std::vector<MPI_Request>*> reqq;
namespace smpi {
namespace replay {
+
+class RequestStorage {
+private:
+ req_storage_t store;
+
+public:
+ RequestStorage() {}
+ int size()
+ {
+ return store.size();
+ }
+
+ req_storage_t& get_store()
+ {
+ return store;
+ }
+
+ void get_requests(std::vector<MPI_Request>& vec)
+ {
+ for (auto& pair : store) {
+ auto& req = pair.second;
+ auto my_proc_id = simgrid::s4u::this_actor::getPid();
+ if (req != MPI_REQUEST_NULL && (req->src() == my_proc_id || req->dst() == my_proc_id)) {
+ vec.push_back(pair.second);
+ pair.second->print_request("MM");
+ }
+ }
+ }
+
+ MPI_Request find(int src, int dst, int tag)
+ {
+ req_storage_t::iterator it = store.find(req_key_t(src, dst, tag));
+ return (it == store.end()) ? MPI_REQUEST_NULL : it->second;
+ }
+
+ void remove(MPI_Request req)
+ {
+ if (req == MPI_REQUEST_NULL) return;
+
+ store.erase(req_key_t(req->src()-1, req->dst()-1, req->tag()));
+ }
+
+ void add(MPI_Request req)
+ {
+ if (req != MPI_REQUEST_NULL) // Can and does happen in the case of TestAction
+ store.insert({req_key_t(req->src()-1, req->dst()-1, req->tag()), req});
+ }
+
+ /* Sometimes we need to re-insert MPI_REQUEST_NULL but we still need src,dst and tag */
+ void addNullRequest(int src, int dst, int tag)
+ {
+ store.insert({req_key_t(src, dst, tag), MPI_REQUEST_NULL});
+ }
+};
+
class ActionArgParser {
public:
virtual ~ActionArgParser() = default;
virtual void parse(simgrid::xbt::ReplayAction& action, std::string name) { CHECK_ACTION_PARAMS(action, 0, 0) }
};
+class WaitTestParser : public ActionArgParser {
+public:
+ int src;
+ int dst;
+ int tag;
+
+ void parse(simgrid::xbt::ReplayAction& action, std::string name) override
+ {
+ CHECK_ACTION_PARAMS(action, 3, 0)
+ src = std::stoi(action[2]);
+ dst = std::stoi(action[3]);
+ tag = std::stoi(action[4]);
+ }
+};
+
class SendRecvParser : public ActionArgParser {
public:
/* communication partner; if we send, this is the receiver and vice versa */
}
};
-class WaitAction : public ReplayAction<ActionArgParser> {
+class WaitAction : public ReplayAction<WaitTestParser> {
public:
WaitAction() : ReplayAction("Wait") {}
void kernel(simgrid::xbt::ReplayAction& action) override
MPI_Request request = get_reqq_self()->back();
get_reqq_self()->pop_back();
- if (request == nullptr) {
+ if (request == MPI_REQUEST_NULL) {
/* Assume that the trace is well formed, meaning the comm might have been caught by a MPI_test. Then just
* return.*/
return;
// Must be taken before Request::wait() since the request may be set to
// MPI_REQUEST_NULL by Request::wait!
- int src = request->comm()->group()->rank(request->src());
- int dst = request->comm()->group()->rank(request->dst());
- int tag = request->tag();
bool is_wait_for_receive = (request->flags() & RECV);
// TODO: Here we take the rank while we normally take the process id (look for my_proc_id)
TRACE_smpi_comm_in(rank, __func__, new simgrid::instr::NoOpTIData("wait"));
TRACE_smpi_comm_out(rank);
if (is_wait_for_receive)
- TRACE_smpi_recv(src, dst, tag);
+ TRACE_smpi_recv(args.src, args.dst, args.tag);
}
};
}
};
-class TestAction : public ReplayAction<ActionArgParser> {
+class TestAction : public ReplayAction<WaitTestParser> {
public:
TestAction() : ReplayAction("Test") {}
void kernel(simgrid::xbt::ReplayAction& action) override
} // Replay Namespace
}} // namespace simgrid::smpi
+std::vector<simgrid::smpi::replay::RequestStorage> storage;
/** @brief Only initialize the replay, don't do it for real */
void smpi_replay_init(int* argc, char*** argv)
{