7#include "ExampleSimulation.hpp"
9#include "CPUFactory.hpp"
12#include "sparta/utils/TimeManager.hpp"
15#include "sparta/trigger/ContextCounterTrigger.hpp"
25#include "Dispatch.hpp"
29#include "FlushManager.hpp"
30#include "Preloader.hpp"
31#include "CustomHistogramStats.hpp"
45 "baz", 0,
"Example parameter set to reproduce bug"))
50 uint32_t read()
const {
51 return int_param_->getValue();
55 std::unique_ptr<Parameter<uint32_t>> int_param_;
63 const std::string & desc) :
64 TreeNode(parent,
"baz_node",
"BazGroup", 0, desc)
71 <<
"' has parameter 'baz' with a value set to "
72 << baz_->read() << std::endl;
75 std::cout <<
"That's the ticket: "
76 << ext->getParameters()->getParameterValueAs<std::string>(
"ticket_") << std::endl;
81 std::unique_ptr<IntParameterSet> baz_;
92 void doSomethingElse()
const {
93 std::cout <<
"Invoking a method that is unknown to the sparta::TreeNode object, "
94 "even though 'this' object was created by, and currently owned by, "
95 "a specific tree node.";
104 std::unique_ptr<sparta::Parameter<double>> degrees_;
109 virtual void postCreate()
override {
112 "degrees_", 360.0,
"Number of degrees in a circle", ps));
116double calculateAverageOfInternalCounters(
117 const std::vector<const sparta::CounterBase*> & counters)
120 for (
const auto & ctr : counters) {
123 return agg / counters.size();
129 uint64_t instruction_limit,
130 bool show_factories) :
131 sparta::app::Simulation(
"sparta_core_example", &scheduler),
132 cpu_topology_(topology),
133 num_cores_(num_cores),
134 instruction_limit_(instruction_limit),
135 show_factories_(show_factories)
147 controller_.reset(
new ExampleSimulator::ExampleController(
this));
154 sparta::trigger::ContextCounterTrigger::registerContextCounterCalcFunction(
155 "avg", &calculateAverageOfInternalCounters);
158void ExampleSimulator::registerStatCalculationFcns_()
176ExampleSimulator::~ExampleSimulator()
179 if (on_triggered_notifier_registered_) {
180 getRoot()->DEREGISTER_FOR_NOTIFICATION(
181 onTriggered_, std::string,
"sparta_expression_trigger_fired");
187 auto sparta_res_factory = getResourceSet()->getResourceFactory(
"cpu");
192void ExampleSimulator::buildTree_()
196 registerStatCalculationFcns_();
198 auto cpu_factory = getCPUFactory_();
201 cpu_factory->setTopology(cpu_topology_, num_cores_);
213 cpu_factory->buildTree(
getRoot());
217 std::cout <<
"Registered factories: \n";
218 for(
const auto& f : getCPUFactory_()->getResourceNames()){
219 std::cout <<
"\t" << f << std::endl;
224 for(uint32_t i = 0; i < num_cores_; ++i){
225 const std::string dispatch_loc =
"cpu.core" + std::to_string(i) +
".dispatch";
226 const std::string alu0_loc =
"cpu.core" + std::to_string(i) +
".alu0";
227 const std::string alu1_loc =
"cpu.core" + std::to_string(i) +
".alu1";
228 const std::string fpu_loc =
"cpu.core" + std::to_string(i) +
".fpu";
231 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(dispatch_loc),
"when_",
"user_data")) {
232 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
233 return val ==
"buildTree_";
234 },
"Parameter 'when_' should be 'buildTree_'");
238 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(dispatch_loc),
"why_",
"user_data")) {
239 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
240 return val ==
"checkAvailability";
241 },
"Parameter 'why_' should be 'checkAvailability'");
245 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(dispatch_loc),
"edges_",
"square")) {
246 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
248 },
"Parameter 'edges_' should be '4'");
252 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(alu0_loc),
"color_",
"difficulty")) {
253 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
254 return val ==
"black";
255 },
"Parameter 'color_' should be 'black'");
259 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(alu0_loc),
"shape_",
"difficulty")) {
260 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
261 return val ==
"diamond";
262 },
"Parameter 'shape_' should be 'diamond'");
266 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(alu1_loc),
"color_",
"difficulty")) {
267 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
268 return val ==
"green";
269 },
"Parameter 'color_' should be 'green'");
273 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(alu1_loc),
"shape_",
"difficulty")) {
274 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
275 return val ==
"circle";
276 },
"Parameter 'shape_' should be 'circle'");
280 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(fpu_loc),
"color_",
"circle")) {
281 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
282 return val ==
"green";
283 },
"Parameter 'color_' should be 'green'");
287 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(fpu_loc),
"shape_",
"circle")) {
288 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
289 return val ==
"round";
290 },
"Parameter 'shape_' should be 'round'");
294 if (
auto prm = getExtensionParameter_<double>(
getRoot()->getChild(fpu_loc),
"degrees_",
"circle")) {
295 prm->addDependentValidationCallback([](
double & val,
const sparta::TreeNode*) ->
bool {
297 },
"Parameter 'degrees_' should be 360.0");
301 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(fpu_loc),
"edges_",
"circle")) {
302 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
304 },
"Parameter 'edges_' should be '0'");
308 getExtension_<CircleExtensions>(
getRoot()->getChild(fpu_loc),
"circle")->doSomethingElse();
331 dispatch,
"Dummy node under top.cpu.core0.dispatch (to reproduce a SPARTA bug)"));
334 fpu,
"Dummy node under top.cpu.core0.fpu (to reproduce a SPARTA bug)"));
337void ExampleSimulator::configureTree_()
339 validateTreeNodeExtensions_();
347 dispatch_baz_->readParams();
348 fpu_baz_->readParams();
355 if(instruction_limit_ != 0){
360 this->
getRoot()->getSearchScope()->getChild(
"top.cpu.core0.rob"),
361 "testing_notif_channel",
362 "Notification channel for testing purposes only",
363 "testing_notif_channel"));
366 getRoot()->getSearchScope()->getChild(
"top.cpu.core0.rob"),
368 "Notification channel for testing report toggling on/off (statistics profiling)",
373 "all_threads_warmup_instruction_count_retired_re4",
374 "Legacy notificiation channel for testing purposes only",
375 "all_threads_warmup_instruction_count_retired_re4"));
377 getRoot()->REGISTER_FOR_NOTIFICATION(
378 onTriggered_, std::string,
"sparta_expression_trigger_fired");
379 on_triggered_notifier_registered_ =
true;
382void ExampleSimulator::bindTree_()
389 auto cpu_factory = getCPUFactory_();
390 cpu_factory->bindTree(
getRoot());
392 sparta::SpartaHandler cb = sparta::SpartaHandler::from_member<
394 this,
"ExampleSimulator::postRandomNumber_");
396 random_number_trigger_.reset(
new sparta::trigger::ExpressionCounterTrigger(
397 "RandomNumber", cb,
"cpu.core0.rob.stats.total_number_retired 7500",
false, this->
getRoot()));
399 toggle_notif_trigger_.reset(
new sparta::trigger::ExpressionTimeTrigger(
405 static const uint32_t warmup_multiplier = 1000;
406 auto gen_expression = [](
const uint32_t core_idx) {
407 std::ostringstream oss;
408 oss <<
"cpu.core" << core_idx <<
".rob.stats.total_number_retired >= "
409 << ((core_idx+1) * warmup_multiplier);
413 num_cores_still_warming_up_ = num_cores_;
414 core_warmup_listeners_.reserve(num_cores_);
416 for (uint32_t core_idx = 0; core_idx < num_cores_; ++core_idx) {
417 core_warmup_listeners_.emplace_back(
418 new sparta::trigger::ExpressionTrigger(
419 "LegacyWarmupNotifications",
421 gen_expression(core_idx),
427void ExampleSimulator::onLegacyWarmupNotification_()
430 --num_cores_still_warming_up_;
431 if (num_cores_still_warming_up_ == 0) {
432 legacy_warmup_report_starter_->postNotification(1);
436const sparta::CounterBase* ExampleSimulator::findSemanticCounter_(CounterSemantic sem)
const {
446void ExampleSimulator::postRandomNumber_()
448 const size_t random = rand() % 25;
449 testing_notification_source_->postNotification(random);
450 random_number_trigger_->reschedule();
453void ExampleSimulator::postToToggleTrigger_()
455 typedef std::pair<uint64_t,uint64_t> ValueCount;
456 static std::queue<ValueCount> values;
458 if (values.empty()) {
465 ValueCount tmp = values.front();
469 if (values.front().second == 0) {
471 ValueCount tmp = values.front();
474 --values.front().second;
477 const ValueCount & current_value = values.front();
478 const uint64_t value_to_post = current_value.first;
479 toggle_trigger_notification_source_->postNotification(value_to_post);
480 toggle_notif_trigger_->reschedule();
483void ExampleSimulator::onTriggered_(
const std::string & msg)
485 std::cout <<
" [trigger] " << msg << std::endl;
488template <
typename ParamT>
491 const std::string& param_name,
492 const std::string& ext_name)
518template <
typename ExtensionT>
519ExtensionT* ExampleSimulator::getExtension_(
521 const std::string& ext_name)
523 static_assert(std::is_base_of<sparta::TreeNode::ExtensionsBase, ExtensionT>::value,
524 "ExtensionT must be derived from sparta::TreeNode::ExtensionsBase");
530 return ext_name.empty() ?
532 dynamic_cast<ExtensionT*
>(node->
getExtension(ext_name));
535void ExampleSimulator::validateTreeNodeExtensions_()
538 if (
auto prm = getExtensionParameter_<std::string>(
539 getRoot()->getChild(
"cpu.core0.lsu"),
"name_",
"cat"))
541 prm->addDependentValidationCallback(
544 },
"Parameter 'name_' should be 'Tom'");
548 if (
auto prm = getExtensionParameter_<std::string>(
549 getRoot()->getChild(
"cpu.core0.lsu"),
"language_",
"cat"))
551 prm->addDependentValidationCallback(
553 return val ==
"meow" || val ==
"grrr";
554 },
"Parameter 'language_' should be 'meow' or 'grrr'");
558 if (
auto prm = getExtensionParameter_<std::string>(
559 getRoot()->getChild(
"cpu.core0.lsu"),
"name_",
"mouse"))
561 prm->addDependentValidationCallback(
563 return val ==
"Jerry";
564 },
"Parameter 'name_' should be 'Jerry'");
568 if (
auto prm = getExtensionParameter_<std::string>(
569 getRoot()->getChild(
"cpu.core0.lsu"),
"language_",
"mouse"))
571 prm->addDependentValidationCallback(
573 return val ==
"squeak";
574 },
"Parameter 'language_' should be 'squeak'");
578 if (
auto prm = getExtensionParameter_<std::string>(
579 getRoot()->getChild(
"cpu.core0.fpu"),
"color_",
"circle"))
581 prm->addDependentValidationCallback(
583 return val ==
"green";
584 },
"Parameter 'color_' should be 'green'");
588 if (
auto prm = getExtensionParameter_<std::string>(
589 getRoot()->getChild(
"cpu.core0.fpu"),
"shape_",
"circle"))
591 prm->addDependentValidationCallback(
593 return val ==
"round";
594 },
"Parameter 'shape_' should be 'round'");
598 if (
auto prm = getExtensionParameter_<double>(
599 getRoot()->getChild(
"cpu.core0.fpu"),
"degrees_",
"circle"))
601 prm->addDependentValidationCallback(
604 },
"Parameter 'degrees_' should be 360.0");
608 getExtension_<CircleExtensions>(
getRoot()->getChild(
"cpu.core0.fpu"),
"circle")->doSomethingElse();
611 if (
auto prm = getExtensionParameter_<std::string>(
614 prm->addDependentValidationCallback(
617 },
"Parameter 'color_' should be 'red'");
627 if (core0_lsu->getNumExtensions() > 1) {
630 getExtension_<>(core0_lsu);
637 "call to TreeNode::getExtension()");
642 if (
auto prm = getExtensionParameter_<std::string>(
643 getRoot()->getChild(
"cpu.core0.fpu"),
"color_"))
645 prm->addDependentValidationCallback(
647 return val ==
"green";
648 },
"Parameter 'color_' should be 'green'");
652 if (
auto prm = getExtensionParameter_<std::string>(
653 getRoot()->getChild(
"cpu.core0.fpu"),
"shape_"))
655 prm->addDependentValidationCallback(
657 return val ==
"round";
658 },
"Parameter 'shape_' should be 'round'");
662 if (
auto prm = getExtensionParameter_<double>(
663 getRoot()->getChild(
"cpu.core0.fpu"),
"degrees_"))
665 prm->addDependentValidationCallback(
668 },
"Parameter 'degrees_' should be 360.0");
672 if (
auto prm = getExtensionParameter_<std::string>(
673 getRoot()->getChild(
"cpu.core0.fpu"),
"edges_"))
675 prm->addDependentValidationCallback(
678 },
"Parameter 'edges_' should be '0'");
682 if (
auto prm = getExtensionParameter_<std::string>(
683 getRoot()->getChild(
"cpu.core0.dispatch.baz_node",
false),
"ticket_",
"baz_ext"))
685 prm->addDependentValidationCallback(
688 },
"Parameter 'ticket_' should be '663'");
692ExampleSimulator::ExampleController::ExampleController(
694 sparta::app::Simulation::SimulationController(sim)
696 sparta::app::Simulation::SimulationController::addNamedCallback_(
699 sparta::app::Simulation::SimulationController::addNamedCallback_(
705 std::cout <<
" [control] Controller PAUSE method has been called for simulation '"
711 std::cout <<
" [control] Controller RESUME method has been called for simulation '"
717 std::cout <<
" [control] Controller TERMINATE method has been called for simulation '"
722void ExampleSimulator::ExampleController::customEatCallback_()
724 std::cout <<
" [control] Controller CUSTOM method has been called ('eat')" << std::endl;
727void ExampleSimulator::ExampleController::customSleepCallback_()
729 std::cout <<
" [control] Controller CUSTOM method has been called ('sleep')" << std::endl;
File that defines the Clock class.
CycleHistogram implementation using sparta CycleCounter.
Definition of the CoreModel Fetch unit.
#define REGISTER_HISTOGRAM_STAT_CALC_FCN(histogram_type, fcn_name)
Function Registration Macro for Histogram/CycleHistogram. This macro is called by the users in their ...
Histogram implementation using sparta Counters.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
#define CREATE_SPARTA_HANDLER(clname, meth)
File that defines the SpartaTester class and testing Macros.
Basic Node framework in sparta device tree composite pattern.
ExampleSimulator which builds the model and configures it.
ExampleSimulator(const std::string &topology, sparta::Scheduler &scheduler, uint32_t num_cores=1, uint64_t instruction_limit=0, bool show_factories=false)
Construct ExampleSimulator.
The base class for all Counters.
Helper class used to trivially extend TreeNode parameter sets (but not any additional functionality b...
A TreeNode that generates a specific type of notification which propagates up a tree of TreeNodes (us...
Non-templated base class for generic parameter access and iteration.
void setValueFromString(const std::string &str, bool poke=false)
Attempts to assign a value to this non-vector Parameter from a string.
Generic container of Parameters.
ParameterSet()=delete
Default constructor disabled.
void addParameter_(sparta::ParameterBase *p)
Add a parameter to the parameter set. \temp This will be removed.
bool hasParameter(const std::string &name) const
Determines whether this ParameterSet has the parameter with the given name.
const Parameter< ContentT > & getParameterAs(const std::string &name) const
Retrieves a sparta::Parameter<ContentT> reference from this parameter set.
Parameter instance, templated to contain only a specific type.
void addResourceFactory()
Add a resource factory by its template type.
TreeNode subclass representing a node in the device tree which contains a single ResourceFactory and ...
void enterTeardown()
Places this tree into TREE_TEARDOWN phase so that nodes may be deleted without errors.
A class that lets you schedule events now and in the future.
void stopRunning()
Tell the scheduler to stop running.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
Base class used to extend TreeNode parameter sets.
Node in a composite tree representing a sparta Tree item.
static const group_idx_type GROUP_IDX_NONE
GroupIndex indicating that a node has no group index because it belongs to no group.
std::string getLocation() const override final
static constexpr char GROUP_NAME_NONE[]
Group name indicating that a node belongs to no group.
TreeNode()=delete
Not default-constructable.
ExtensionsBase * getExtension()
Get an extension without needing to specify any particular type string. If no extensions exist,...
ExtensionsBase * getExtension(const std::string &extension_name)
Get an extension object by type string. Returns nullptr if not found (unrecognized).
const ConstT getChildAs(const std::string &name, bool must_exist=true) const
Retrieves a child that is castable to T with the given dotted path.
TreeNode * getChild(const std::string &name, bool must_exist=true)
Retrieves a child with this dotted path name.
Simulator which builds a sparta DeviceTree.
std::vector< std::unique_ptr< sparta::TreeNode > > to_delete_
Vector of TreeNodes to delete automatically at destruction. Add any nodes allocated to this list to a...
@ CSEM_INSTRUCTIONS
Instruction count semantic (usually core0)
std::shared_ptr< SimulationController > controller_
Custom controller to handle various simulation events.
sparta::RootTreeNode * getRoot() noexcept
Returns the tree root.
void addTreeNodeExtensionFactory_(const std::string &extension_name, std::function< TreeNode::ExtensionsBase *()> creator)
Include an extension factory for this simulation's device tree nodes. They will be given to specific ...
void setSimulationController_(std::shared_ptr< SimulationController > controller)
Set a controller to handle custom simulation events.
sparta::ResourceSet * getResourceSet() noexcept
Returns the resource set for this Simulation.
const std::string & getSimName() const noexcept
Returns this simulator's name.
sparta::Scheduler * getScheduler()
Returns the simulation's scheduler.
Macros for handling exponential backoff.