7#include "ExampleSimulation.hpp"
9#include "CPUFactory.hpp"
12#include "sparta/utils/TimeManager.hpp"
14#include "sparta/simulation/TreeNodeExtensions.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;
76 std::cout <<
"That's the ticket: "
77 << ext->getParameters()->getParameterValueAs<std::string>(
"ticket_") << std::endl;
82 std::unique_ptr<IntParameterSet> baz_;
90 void doSomethingElse()
const {
91 std::cout <<
"Invoking a method that is unknown to the sparta::TreeNode object, "
92 "even though 'this' object was created by, and currently owned by, "
93 "a specific tree node.";
101 std::unique_ptr<sparta::Parameter<double>> degrees_;
106 void postCreate()
override {
109 "degrees_", 360.0,
"Number of degrees in a circle", ps));
116 void postCreate()
override {
119 "value_", 555,
"Dummy value", ps));
122 std::unique_ptr<sparta::Parameter<int>> value_;
125class Foobar :
public sparta::ExtensionsParamsOnly
128 void postCreate()
override {
131 "extra", 404,
"Extra postCreate parameter", ps));
134 std::unique_ptr<sparta::Parameter<int>> extra_;
140 using EnabledUnits = std::vector<std::vector<std::vector<std::string>>>;
143 void postCreate()
override {
144 auto ps = getParameters();
145 enabled_units_.reset(
new sparta::Parameter<std::vector<std::vector<std::vector<std::string>>>>(
146 "enabled_units", {},
"Enabled units to test nested vectors", ps));
150 std::unique_ptr<sparta::Parameter<EnabledUnits>> enabled_units_;
151 std::unique_ptr<sparta::Parameter<std::string>> fetch_type_;
154double calculateAverageOfInternalCounters(
155 const std::vector<const sparta::CounterBase*> & counters)
158 for (
const auto & ctr : counters) {
161 return agg / counters.size();
167 uint64_t instruction_limit,
168 bool show_factories) :
169 sparta::app::Simulation(
"sparta_core_example", &scheduler),
170 cpu_topology_(topology),
171 num_cores_(num_cores),
172 instruction_limit_(instruction_limit),
173 show_factories_(show_factories)
188 controller_.reset(
new ExampleSimulator::ExampleController(
this));
195 sparta::trigger::ContextCounterTrigger::registerContextCounterCalcFunction(
196 "avg", &calculateAverageOfInternalCounters);
199void ExampleSimulator::registerStatCalculationFcns_()
217ExampleSimulator::~ExampleSimulator()
220 if (on_triggered_notifier_registered_) {
221 getRoot()->DEREGISTER_FOR_NOTIFICATION(
222 onTriggered_, std::string,
"sparta_expression_trigger_fired");
228 auto sparta_res_factory = getResourceSet()->getResourceFactory(
"cpu");
233void ExampleSimulator::buildTree_()
237 registerStatCalculationFcns_();
239 auto cpu_factory = getCPUFactory_();
242 cpu_factory->setTopology(cpu_topology_, num_cores_);
254 cpu_factory->buildTree(
getRoot());
260 auto ps = ext->getParameters();
261 auto & p = ps->getParameterAs<std::string>(
"fetch_type");
267 std::cout <<
"Registered factories: \n";
268 for(
const auto& f : getCPUFactory_()->getResourceNames()){
269 std::cout <<
"\t" << f << std::endl;
274 for(uint32_t i = 0; i < num_cores_; ++i){
275 const std::string core_loc =
"cpu.core" + std::to_string(i);
276 const std::string dispatch_loc = core_loc +
".dispatch";
277 const std::string alu0_loc = core_loc +
".alu0";
278 const std::string alu1_loc = core_loc +
".alu1";
279 const std::string fpu_loc = core_loc +
".fpu";
282 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(dispatch_loc),
"when_",
"user_data")) {
283 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
284 return val ==
"buildTree_";
285 },
"Parameter 'when_' should be 'buildTree_'");
289 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(dispatch_loc),
"why_",
"user_data")) {
290 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
291 return val ==
"checkAvailability";
292 },
"Parameter 'why_' should be 'checkAvailability'");
296 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(dispatch_loc),
"edges_",
"square")) {
297 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
299 },
"Parameter 'edges_' should be '4'");
303 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(alu0_loc),
"color_",
"difficulty")) {
304 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
305 return val ==
"black";
306 },
"Parameter 'color_' should be 'black'");
310 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(alu0_loc),
"shape_",
"difficulty")) {
311 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
312 return val ==
"diamond";
313 },
"Parameter 'shape_' should be 'diamond'");
317 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(alu1_loc),
"color_",
"difficulty")) {
318 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
319 return val ==
"green";
320 },
"Parameter 'color_' should be 'green'");
324 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(alu1_loc),
"shape_",
"difficulty")) {
325 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
326 return val ==
"circle";
327 },
"Parameter 'shape_' should be 'circle'");
331 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(fpu_loc),
"color_",
"circle")) {
332 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
333 return val ==
"green";
334 },
"Parameter 'color_' should be 'green'");
338 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(fpu_loc),
"shape_",
"circle")) {
339 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
340 return val ==
"round";
341 },
"Parameter 'shape_' should be 'round'");
345 if (
auto prm = getExtensionParameter_<double>(
getRoot()->getChild(fpu_loc),
"degrees_",
"circle")) {
346 prm->addDependentValidationCallback([](
double & val,
const sparta::TreeNode*) ->
bool {
348 },
"Parameter 'degrees_' should be 360.0");
352 if (
auto prm = getExtensionParameter_<std::string>(
getRoot()->getChild(fpu_loc),
"edges_",
"circle")) {
353 prm->addDependentValidationCallback([](std::string & val,
const sparta::TreeNode*) ->
bool {
355 },
"Parameter 'edges_' should be '0'");
360 using NestedVector =
typename CoreExtensions::EnabledUnits;
361 if (
auto prm = getExtensionParameter_<NestedVector>(core_tn,
"enabled_units",
"core_extensions")) {
362 prm->addDependentValidationCallback([](NestedVector & actual_vecs,
const sparta::TreeNode* node) ->
bool {
363 if (actual_vecs.empty()) {
374 auto ps = ext->getParameters();
375 if (!ps->hasParameter(
"enabled_units")) {
379 auto& p = ps->getParameterAs<NestedVector>(
"enabled_units");
380 if (p.getValue() != actual_vecs) {
384 static NestedVector expected_vecs = {
389 {
"int",
"mul",
"i2f",
"cmov"}
393 return p.getValue() == expected_vecs;
394 },
"Invalid enabled units in 'core_extensions' (nested vector param)");
398 getExtension_<CircleExtensions>(
getRoot()->getChild(fpu_loc),
"circle")->doSomethingElse();
421 dispatch,
"Dummy node under top.cpu.core0.dispatch (to reproduce a SPARTA bug)"));
424 fpu,
"Dummy node under top.cpu.core0.fpu (to reproduce a SPARTA bug)"));
427void ExampleSimulator::configureTree_()
429 validateTreeNodeExtensions_();
437 dispatch_baz_->readParams();
438 fpu_baz_->readParams();
445 if(instruction_limit_ != 0){
450 this->
getRoot()->getSearchScope()->getChild(
"top.cpu.core0.rob"),
451 "testing_notif_channel",
452 "Notification channel for testing purposes only",
453 "testing_notif_channel"));
456 getRoot()->getSearchScope()->getChild(
"top.cpu.core0.rob"),
458 "Notification channel for testing report toggling on/off (statistics profiling)",
463 "all_threads_warmup_instruction_count_retired_re4",
464 "Legacy notificiation channel for testing purposes only",
465 "all_threads_warmup_instruction_count_retired_re4"));
467 getRoot()->REGISTER_FOR_NOTIFICATION(
468 onTriggered_, std::string,
"sparta_expression_trigger_fired");
469 on_triggered_notifier_registered_ =
true;
472void ExampleSimulator::bindTree_()
479 auto cpu_factory = getCPUFactory_();
480 cpu_factory->bindTree(
getRoot());
482 sparta::SpartaHandler cb = sparta::SpartaHandler::from_member<
484 this,
"ExampleSimulator::postRandomNumber_");
486 random_number_trigger_.reset(
new sparta::trigger::ExpressionCounterTrigger(
487 "RandomNumber", cb,
"cpu.core0.rob.stats.total_number_retired 7500",
false, this->
getRoot()));
489 toggle_notif_trigger_.reset(
new sparta::trigger::ExpressionTimeTrigger(
495 static const uint32_t warmup_multiplier = 1000;
496 auto gen_expression = [](
const uint32_t core_idx) {
497 std::ostringstream oss;
498 oss <<
"cpu.core" << core_idx <<
".rob.stats.total_number_retired >= "
499 << ((core_idx+1) * warmup_multiplier);
503 num_cores_still_warming_up_ = num_cores_;
504 core_warmup_listeners_.reserve(num_cores_);
506 for (uint32_t core_idx = 0; core_idx < num_cores_; ++core_idx) {
507 core_warmup_listeners_.emplace_back(
508 new sparta::trigger::ExpressionTrigger(
509 "LegacyWarmupNotifications",
511 gen_expression(core_idx),
517void ExampleSimulator::onLegacyWarmupNotification_()
520 --num_cores_still_warming_up_;
521 if (num_cores_still_warming_up_ == 0) {
522 legacy_warmup_report_starter_->postNotification(1);
526const sparta::CounterBase* ExampleSimulator::findSemanticCounter_(CounterSemantic sem)
const {
536void ExampleSimulator::postRandomNumber_()
538 const size_t random = rand() % 25;
539 testing_notification_source_->postNotification(random);
540 random_number_trigger_->reschedule();
543void ExampleSimulator::postToToggleTrigger_()
545 typedef std::pair<uint64_t,uint64_t> ValueCount;
546 static std::queue<ValueCount> values;
548 if (values.empty()) {
555 ValueCount tmp = values.front();
559 if (values.front().second == 0) {
561 ValueCount tmp = values.front();
564 --values.front().second;
567 const ValueCount & current_value = values.front();
568 const uint64_t value_to_post = current_value.first;
569 toggle_trigger_notification_source_->postNotification(value_to_post);
570 toggle_notif_trigger_->reschedule();
573void ExampleSimulator::onTriggered_(
const std::string & msg)
575 std::cout <<
" [trigger] " << msg << std::endl;
578template <
typename ParamT>
581 const std::string& param_name,
582 const std::string& ext_name)
588 sparta::TreeNode::ExtensionsBase * ext = ext_name.empty() ?
617template <
typename ExtensionT>
618ExtensionT* ExampleSimulator::getExtension_(
620 const std::string& ext_name)
622 static_assert(std::is_base_of<sparta::TreeNode::ExtensionsBase, ExtensionT>::value,
623 "ExtensionT must be derived from sparta::TreeNode::ExtensionsBase");
629 return ext_name.empty() ?
631 dynamic_cast<ExtensionT*
>(node->
getExtension(ext_name));
634void ExampleSimulator::validateTreeNodeExtensions_()
637 if (
auto prm = getExtensionParameter_<std::string>(
638 getRoot()->getChild(
"cpu.core0.lsu"),
"name_",
"cat"))
640 prm->addDependentValidationCallback(
643 },
"Parameter 'name_' should be 'Tom'");
647 if (
auto prm = getExtensionParameter_<std::string>(
648 getRoot()->getChild(
"cpu.core0.lsu"),
"language_",
"cat"))
650 prm->addDependentValidationCallback(
652 return val ==
"meow" || val ==
"grrr";
653 },
"Parameter 'language_' should be 'meow' or 'grrr'");
657 if (
auto prm = getExtensionParameter_<std::string>(
658 getRoot()->getChild(
"cpu.core0.lsu"),
"name_",
"mouse"))
660 prm->addDependentValidationCallback(
662 return val ==
"Jerry";
663 },
"Parameter 'name_' should be 'Jerry'");
667 if (
auto prm = getExtensionParameter_<std::string>(
668 getRoot()->getChild(
"cpu.core0.lsu"),
"language_",
"mouse"))
670 prm->addDependentValidationCallback(
672 return val ==
"squeak";
673 },
"Parameter 'language_' should be 'squeak'");
677 if (
auto prm = getExtensionParameter_<std::string>(
678 getRoot()->getChild(
"cpu.core0.fpu"),
"color_",
"circle"))
680 prm->addDependentValidationCallback(
682 return val ==
"green";
683 },
"Parameter 'color_' should be 'green'");
687 if (
auto prm = getExtensionParameter_<std::string>(
688 getRoot()->getChild(
"cpu.core0.fpu"),
"shape_",
"circle"))
690 prm->addDependentValidationCallback(
692 return val ==
"round";
693 },
"Parameter 'shape_' should be 'round'");
697 if (
auto prm = getExtensionParameter_<double>(
698 getRoot()->getChild(
"cpu.core0.fpu"),
"degrees_",
"circle"))
700 prm->addDependentValidationCallback(
703 },
"Parameter 'degrees_' should be 360.0");
707 getExtension_<CircleExtensions>(
getRoot()->getChild(
"cpu.core0.fpu"),
"circle")->doSomethingElse();
710 if (
auto prm = getExtensionParameter_<std::string>(
713 prm->addDependentValidationCallback(
716 },
"Parameter 'color_' should be 'red'");
726 if (core0_lsu->getNumExtensions() > 1) {
729 getExtension_<>(core0_lsu);
736 "call to TreeNode::getExtension()");
741 if (
auto prm = getExtensionParameter_<std::string>(
742 getRoot()->getChild(
"cpu.core0.fpu"),
"color_"))
744 prm->addDependentValidationCallback(
746 return val ==
"green";
747 },
"Parameter 'color_' should be 'green'");
751 if (
auto prm = getExtensionParameter_<std::string>(
752 getRoot()->getChild(
"cpu.core0.fpu"),
"shape_"))
754 prm->addDependentValidationCallback(
756 return val ==
"round";
757 },
"Parameter 'shape_' should be 'round'");
761 if (
auto prm = getExtensionParameter_<double>(
762 getRoot()->getChild(
"cpu.core0.fpu"),
"degrees_"))
764 prm->addDependentValidationCallback(
767 },
"Parameter 'degrees_' should be 360.0");
771 if (
auto prm = getExtensionParameter_<std::string>(
772 getRoot()->getChild(
"cpu.core0.fpu"),
"edges_"))
774 prm->addDependentValidationCallback(
777 },
"Parameter 'edges_' should be '0'");
781 if (
auto prm = getExtensionParameter_<std::string>(
782 getRoot()->getChild(
"cpu.core0.dispatch.baz_node",
false),
"ticket_",
"baz_ext"))
784 prm->addDependentValidationCallback(
787 },
"Parameter 'ticket_' should be '663'");
790 if (
auto ext =
getRoot()->getExtension(
"testing",
true )) {
791 auto expected_exts_file = ext->getParameterValueAs<std::string>(
"expected_extensions");
798 std::vector<const sparta::ParameterTree::Node*> ext_root_nodes;
801 for (
auto ext_root_node : ext_root_nodes) {
802 auto tn_pattern = ext_root_node->getParent()->getPath();
803 std::vector<sparta::TreeNode*> matching_tns;
806 for (
auto tn : matching_tns) {
807 for (
auto ext_node : ext_root_node->getChildren()) {
808 auto ext_name = ext_node->getName();
809 ext = tn->getExtension(ext_name);
812 for (
auto param_node : ext_node->getChildren()) {
813 auto actual_val = ext->getParameterValueAs<std::string>(param_node->getName());
814 auto expected_val = param_node->peekValue();
823ExampleSimulator::ExampleController::ExampleController(
825 sparta::app::Simulation::SimulationController(sim)
827 sparta::app::Simulation::SimulationController::addNamedCallback_(
830 sparta::app::Simulation::SimulationController::addNamedCallback_(
836 std::cout <<
" [control] Controller PAUSE method has been called for simulation '"
842 std::cout <<
" [control] Controller RESUME method has been called for simulation '"
848 std::cout <<
" [control] Controller TERMINATE method has been called for simulation '"
853void ExampleSimulator::ExampleController::customEatCallback_()
855 std::cout <<
" [control] Controller CUSTOM method has been called ('eat')" << std::endl;
858void ExampleSimulator::ExampleController::customSleepCallback_()
860 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.
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.
void recursFindPTreeNodesNamed(const std::string &name, std::vector< Node * > &matching_nodes)
Recursively find all nodes that have a given name.
Virtual Parameter Tree. This represents a tree of parameters read from some source but does not neces...
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 ...
GlobalTreeNode * getSearchScope()
Gets the search node "parent" of this root node which is suitable for performing searches that includ...
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.
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
ExtensionsBase * getExtension(const std::string &extension_name, bool no_factory_ok=false)
Get an extension object by extension name.
static constexpr char GROUP_NAME_NONE[]
Group name indicating that a node belongs to no group.
ExtensionsBase * createExtension(const std::string &extension_name, bool replace=false)
Create an extension on demand. This is useful if you want to add an extension to a node that was not ...
TreeNode()=delete
Not default-constructable.
ExtensionsBase * getExtension()
Get an extension without needing to specify any particular extension name. If no extensions exist,...
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.
uint32_t findChildren(const std::string &pattern, std::vector< TreeNode * > &results, std::vector< std::vector< std::string > > &replacements)
Finds all children starting at this node with a given pattern relative to this node by matching names...
Applies a configuration file to a node pattern.
void applyUnbound(sparta::ParameterTree &ptree, bool verbose=false) const override
Apply the parameter contained in this object to the unbound (virtual) parameter tree ptree.
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...
void addTreeNodeExtensionFactory_(const std::string &extension_name, std::function< TreeNode::ExtensionsBase *()> factory)
Include an extension factory for this simulation's device tree nodes. They will be given to specific ...
@ 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 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.