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.
This commit is contained in:
@@ -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<TraceGeneratorIdleState *>(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<TraceGeneratorIdleState *>(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<TraceGeneratorTrafficState>(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<TraceGenerator>(generator);
|
||||
}
|
||||
else if (type == TrafficInitiatorType::Hammer)
|
||||
|
||||
@@ -97,6 +97,7 @@ struct TraceGeneratorTrafficState : public TraceGeneratorState
|
||||
Optional<uint64_t> minAddress;
|
||||
Optional<uint64_t> maxAddress;
|
||||
Optional<uint64_t> clksPerRequest;
|
||||
Optional<std::string> notify;
|
||||
};
|
||||
|
||||
struct TraceGeneratorIdleState : public TraceGeneratorState
|
||||
@@ -116,6 +117,7 @@ struct TraceGenerator : public TrafficInitiator
|
||||
Optional<uint64_t> maxTransactions;
|
||||
std::map<unsigned int, std::unique_ptr<TraceGeneratorState>> states;
|
||||
std::multimap<unsigned int, TraceGeneratorStateTransition> transitions;
|
||||
Optional<std::string> idleUntil;
|
||||
};
|
||||
|
||||
struct TraceHammer : public TrafficInitiator
|
||||
|
||||
@@ -35,10 +35,12 @@
|
||||
* Derek Christ
|
||||
*/
|
||||
|
||||
#include <iomanip>
|
||||
#include "TraceSetup.h"
|
||||
#include "StlPlayer.h"
|
||||
#include "TrafficGenerator.h"
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
|
||||
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<DRAMSysConfiguration::TraceGenerator>(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<TrafficGenerator *>(*listenerIt);
|
||||
|
||||
auto notifierIt =
|
||||
std::find_if(players.begin(), players.end(),
|
||||
[&idleUntil](const TrafficInitiator *initiator)
|
||||
{
|
||||
if (auto generator = dynamic_cast<const TrafficGenerator *>(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<TrafficGenerator *>(*notifierIt);
|
||||
listener->waitUntil(¬ifier->getStateTransitionEvent(idleUntil));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remainingTransactions = totalTransactions;
|
||||
numberOfTrafficInitiators = players.size();
|
||||
}
|
||||
|
||||
@@ -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<DRAMSysConfiguration::TraceGeneratorIdleState *>(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<DRAMSysConfiguration::TraceGeneratorTrafficState *>(conf.states.at(currentState).get()))
|
||||
{
|
||||
if (transactionsSentInCurrentState >= trafficState->numRequests)
|
||||
|
||||
@@ -39,11 +39,12 @@
|
||||
#ifndef TRAFFICGENERATOR_H
|
||||
#define TRAFFICGENERATOR_H
|
||||
|
||||
#include <random>
|
||||
|
||||
#include "TrafficInitiator.h"
|
||||
#include "TraceSetup.h"
|
||||
|
||||
#include <map>
|
||||
#include <random>
|
||||
|
||||
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<unsigned int> stateSequence;
|
||||
std::vector<unsigned int>::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<std::string, EventPair> stateTranstitionEvents;
|
||||
|
||||
bool idleAtStart = false;
|
||||
const sc_core::sc_event *startEvent = nullptr;
|
||||
|
||||
std::default_random_engine randomGenerator;
|
||||
std::uniform_real_distribution<float> randomDistribution = std::uniform_real_distribution<float>(0.0f, 1.0f);
|
||||
std::uniform_int_distribution<uint64_t> randomAddressDistribution;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user