From 5c0b08246e93f4ebd6b739ee2a819f0790504e3d Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Wed, 12 Jan 2022 15:51:07 +0100 Subject: [PATCH] Introduce a event-based system to start statemachines State machines can now optionally be started by other state machines when they transition into a certain state. The field "notify" was added to send a event with the specified name when the transition happens. The other state machine can listen to those events by adding the "idleUntil" field to the definition. --- .../src/common/configuration/TraceSetup.cpp | 9 ++++ .../src/common/configuration/TraceSetup.h | 2 + DRAMSys/simulator/TraceSetup.cpp | 42 ++++++++++++++++++- DRAMSys/simulator/TrafficGenerator.cpp | 42 +++++++++++++++++++ DRAMSys/simulator/TrafficGenerator.h | 21 +++++++++- DRAMSys/simulator/TrafficInitiator.cpp | 2 +- 6 files changed, 114 insertions(+), 4 deletions(-) diff --git a/DRAMSys/library/src/common/configuration/TraceSetup.cpp b/DRAMSys/library/src/common/configuration/TraceSetup.cpp index fd509ee2..c5bb2492 100644 --- a/DRAMSys/library/src/common/configuration/TraceSetup.cpp +++ b/DRAMSys/library/src/common/configuration/TraceSetup.cpp @@ -65,6 +65,7 @@ void to_json(json &j, const TraceSetup &c) initiator_j["type"] = "generator"; initiator_j["seed"] = generator->seed; initiator_j["maxTransactions"] = generator->maxTransactions; + initiator_j["idleUntil"] = generator->idleUntil; // When there are less than 2 states, flatten out the json. if (generator->states.size() == 1) @@ -80,6 +81,7 @@ void to_json(json &j, const TraceSetup &c) initiator_j["minAddress"] = trafficState->minAddress; initiator_j["maxAddress"] = trafficState->maxAddress; initiator_j["clksPerRequest"] = trafficState->clksPerRequest; + initiator_j["notify"] = trafficState->notify; } else if (const auto idleState = dynamic_cast(state.get())) { @@ -104,6 +106,7 @@ void to_json(json &j, const TraceSetup &c) state_j["minAddress"] = trafficState->minAddress; state_j["maxAddress"] = trafficState->maxAddress; state_j["clksPerRequest"] = trafficState->clksPerRequest; + state_j["notify"] = trafficState->notify; } else if (const auto idleState = dynamic_cast(state.second.get())) { @@ -193,6 +196,9 @@ void from_json(const json &j, TraceSetup &c) if (state_j.contains("clksPerRequest")) state_j.at("clksPerRequest").get_to(trafficState->clksPerRequest); + if (state_j.contains("notify")) + state_j.at("notify").get_to(trafficState->notify); + state = std::unique_ptr(trafficState); } @@ -234,6 +240,9 @@ void from_json(const json &j, TraceSetup &c) if (initiator_j.contains("maxTransactions")) initiator_j.at("maxTransactions").get_to(generator->maxTransactions); + if (initiator_j.contains("idleUntil")) + initiator_j.at("idleUntil").get_to(generator->idleUntil); + initiator = std::unique_ptr(generator); } else if (type == TrafficInitiatorType::Hammer) diff --git a/DRAMSys/library/src/common/configuration/TraceSetup.h b/DRAMSys/library/src/common/configuration/TraceSetup.h index d128dc36..5b61fef0 100644 --- a/DRAMSys/library/src/common/configuration/TraceSetup.h +++ b/DRAMSys/library/src/common/configuration/TraceSetup.h @@ -97,6 +97,7 @@ struct TraceGeneratorTrafficState : public TraceGeneratorState Optional minAddress; Optional maxAddress; Optional clksPerRequest; + Optional notify; }; struct TraceGeneratorIdleState : public TraceGeneratorState @@ -116,6 +117,7 @@ struct TraceGenerator : public TrafficInitiator Optional maxTransactions; std::map> states; std::multimap transitions; + Optional idleUntil; }; struct TraceHammer : public TrafficInitiator diff --git a/DRAMSys/simulator/TraceSetup.cpp b/DRAMSys/simulator/TraceSetup.cpp index 966fff87..08373c62 100644 --- a/DRAMSys/simulator/TraceSetup.cpp +++ b/DRAMSys/simulator/TraceSetup.cpp @@ -35,10 +35,12 @@ * Derek Christ */ -#include #include "TraceSetup.h" #include "StlPlayer.h" #include "TrafficGenerator.h" +#include +#include +#include using namespace sc_core; using namespace tlm; @@ -119,6 +121,44 @@ TraceSetup::TraceSetup(const DRAMSysConfiguration::TraceSetup &traceSetup, } } + for (const auto &inititatorConf : traceSetup.initiators) + { + if (auto generatorConf = std::dynamic_pointer_cast(inititatorConf)) + { + if (generatorConf->idleUntil.isValid()) + { + auto idleUntil = generatorConf->idleUntil.getValue(); + + const std::string name = generatorConf->name; + auto listenerIt = + std::find_if(players.begin(), players.end(), + [&name](const TrafficInitiator *initiator) { return initiator->name() == name; }); + + // Should be found + auto listener = dynamic_cast(*listenerIt); + + auto notifierIt = + std::find_if(players.begin(), players.end(), + [&idleUntil](const TrafficInitiator *initiator) + { + if (auto generator = dynamic_cast(initiator)) + { + if (generator->hasStateTransitionEvent(idleUntil)) + return true; + } + + return false; + }); + + if (notifierIt == players.end()) + SC_REPORT_FATAL("TraceSetup", "Event to listen on not found."); + + auto notifier = dynamic_cast(*notifierIt); + listener->waitUntil(¬ifier->getStateTransitionEvent(idleUntil)); + } + } + } + remainingTransactions = totalTransactions; numberOfTrafficInitiators = players.size(); } diff --git a/DRAMSys/simulator/TrafficGenerator.cpp b/DRAMSys/simulator/TrafficGenerator.cpp index ad56dc47..539b0f6f 100644 --- a/DRAMSys/simulator/TrafficGenerator.cpp +++ b/DRAMSys/simulator/TrafficGenerator.cpp @@ -120,6 +120,13 @@ TrafficGenerator::TrafficGenerator(const sc_module_name &name, const DRAMSysConf if (rwRatio < 0 || rwRatio > 1) SC_REPORT_FATAL("TraceSetup", "Read/Write ratio is not a number between 0 and 1."); + + if (trafficState->notify.isValid()) + { + auto eventName = trafficState->notify.getValue(); + stateTranstitionEvents.emplace(std::piecewise_construct, std::forward_as_tuple(eventName), + std::forward_as_tuple(eventName.c_str(), state.first)); + } } } @@ -189,6 +196,26 @@ void TrafficGenerator::calculateTransitions() stateIt = stateSequence.cbegin(); } +bool TrafficGenerator::hasStateTransitionEvent(const std::string &eventName) const +{ + auto it = stateTranstitionEvents.find(eventName); + + if (it == stateTranstitionEvents.end()) + return false; + + return true; +} + +const sc_core::sc_event &TrafficGenerator::getStateTransitionEvent(const std::string &eventName) const +{ + auto it = stateTranstitionEvents.find(eventName); + + if (it == stateTranstitionEvents.end()) + SC_REPORT_FATAL("TraceSetup", "StateTransitionEvent not found."); + + return it->second.event; +} + uint64_t TrafficGenerator::getTotalTransactions() const { uint64_t totalTransactions = 0; @@ -205,6 +232,11 @@ uint64_t TrafficGenerator::getTotalTransactions() const return totalTransactions; } +void TrafficGenerator::waitUntil(const sc_core::sc_event *ev) +{ + startEvent = ev; +} + void TrafficGenerator::transitionToNextState() { ++stateIt; @@ -218,6 +250,13 @@ void TrafficGenerator::transitionToNextState() currentState = *stateIt; + // Notify + for (auto &it : stateTranstitionEvents) + { + if (it.second.stateId == currentState) + it.second.event.notify(); + } + if (auto idleState = dynamic_cast(conf.states.at(currentState).get())) { currentClksToIdle += idleState->idleClks; @@ -238,6 +277,9 @@ void TrafficGenerator::transitionToNextState() void TrafficGenerator::prepareNextPayload() { + if (startEvent && transactionsSent == 0) + wait(*startEvent); + if (auto trafficState = dynamic_cast(conf.states.at(currentState).get())) { if (transactionsSentInCurrentState >= trafficState->numRequests) diff --git a/DRAMSys/simulator/TrafficGenerator.h b/DRAMSys/simulator/TrafficGenerator.h index f27c7bba..16e957ea 100644 --- a/DRAMSys/simulator/TrafficGenerator.h +++ b/DRAMSys/simulator/TrafficGenerator.h @@ -39,11 +39,12 @@ #ifndef TRAFFICGENERATOR_H #define TRAFFICGENERATOR_H -#include - #include "TrafficInitiator.h" #include "TraceSetup.h" +#include +#include + class TrafficGeneratorIf : public TrafficInitiator { public: @@ -68,6 +69,9 @@ public: TraceSetup *setup); uint64_t getTotalTransactions() const; + void waitUntil(const sc_core::sc_event *ev); + bool hasStateTransitionEvent(const std::string &eventName) const; + const sc_core::sc_event &getStateTransitionEvent(const std::string &eventName) const; private: static uint64_t evaluateSeed(const DRAMSysConfiguration::TraceGenerator &conf); @@ -103,6 +107,19 @@ private: std::vector stateSequence; std::vector::const_iterator stateIt; + struct EventPair + { + EventPair(const std::string &name, unsigned int id) : event(name.c_str()), stateId(id) + { + } + sc_core::sc_event event; + unsigned int stateId; + }; + std::map stateTranstitionEvents; + + bool idleAtStart = false; + const sc_core::sc_event *startEvent = nullptr; + std::default_random_engine randomGenerator; std::uniform_real_distribution randomDistribution = std::uniform_real_distribution(0.0f, 1.0f); std::uniform_int_distribution randomAddressDistribution; diff --git a/DRAMSys/simulator/TrafficInitiator.cpp b/DRAMSys/simulator/TrafficInitiator.cpp index 644f1235..8783fcc9 100644 --- a/DRAMSys/simulator/TrafficInitiator.cpp +++ b/DRAMSys/simulator/TrafficInitiator.cpp @@ -49,7 +49,7 @@ TrafficInitiator::TrafficInitiator(const sc_module_name &name, TraceSetup *setup setup(setup), maxPendingReadRequests(maxPendingReadRequests), maxPendingWriteRequests(maxPendingWriteRequests) { - SC_METHOD(sendNextPayload); + SC_THREAD(sendNextPayload); iSocket.register_nb_transport_bw(this, &TrafficInitiator::nb_transport_bw); if (Configuration::getInstance().storeMode == Configuration::StoreMode::NoStorage)