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:
2022-01-12 15:51:07 +01:00
parent 3dbb089dcb
commit 5c0b08246e
6 changed files with 114 additions and 4 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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(&notifier->getStateTransitionEvent(idleUntil));
}
}
}
remainingTransactions = totalTransactions;
numberOfTrafficInitiators = players.size();
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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)