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 this->
getRoot()->getSearchScope()->getChild(
"top.cpu.core0.rob"),
457 "sprintf_notif_channel",
458 "Notification channel for testing the 'sprintf-notif' report trigger",
459 "sprintf_notif_channel"));
462 getRoot()->getSearchScope()->getChild(
"top.cpu.core0.rob"),
464 "Notification channel for testing report toggling on/off (statistics profiling)",
469 "all_threads_warmup_instruction_count_retired_re4",
470 "Legacy notificiation channel for testing purposes only",
471 "all_threads_warmup_instruction_count_retired_re4"));
473 getRoot()->REGISTER_FOR_NOTIFICATION(
474 onTriggered_, std::string,
"sparta_expression_trigger_fired");
475 on_triggered_notifier_registered_ =
true;
478void ExampleSimulator::bindTree_()
485 auto cpu_factory = getCPUFactory_();
486 cpu_factory->bindTree(
getRoot());
488 sparta::SpartaHandler cb = sparta::SpartaHandler::from_member<
490 this,
"ExampleSimulator::postRandomNumber_");
492 random_number_trigger_.reset(
new sparta::trigger::ExpressionCounterTrigger(
493 "RandomNumber", cb,
"cpu.core0.rob.stats.total_number_retired 7500",
false, this->
getRoot()));
495 toggle_notif_trigger_.reset(
new sparta::trigger::ExpressionTimeTrigger(
501 static const uint32_t warmup_multiplier = 1000;
502 auto gen_expression = [](
const uint32_t core_idx) {
503 std::ostringstream oss;
504 oss <<
"cpu.core" << core_idx <<
".rob.stats.total_number_retired >= "
505 << ((core_idx+1) * warmup_multiplier);
509 num_cores_still_warming_up_ = num_cores_;
510 core_warmup_listeners_.reserve(num_cores_);
512 for (uint32_t core_idx = 0; core_idx < num_cores_; ++core_idx) {
513 core_warmup_listeners_.emplace_back(
514 new sparta::trigger::ExpressionTrigger(
515 "LegacyWarmupNotifications",
517 gen_expression(core_idx),
523void ExampleSimulator::onLegacyWarmupNotification_()
526 --num_cores_still_warming_up_;
527 if (num_cores_still_warming_up_ == 0) {
528 legacy_warmup_report_starter_->postNotification(1);
532const sparta::CounterBase* ExampleSimulator::findSemanticCounter_(CounterSemantic sem)
const {
542void ExampleSimulator::postRandomNumber_()
544 const size_t random = rand() % 25;
545 testing_notification_source_->postNotification(random);
547 if (sprintf_test_notification_source_->hasFormatString() && random % 10 == 0) {
548 sprintf_test_notification_source_->postNotification(
"random_stat",
static_cast<int>(random));
551 random_number_trigger_->reschedule();
554void ExampleSimulator::postToToggleTrigger_()
556 typedef std::pair<uint64_t,uint64_t> ValueCount;
557 static std::queue<ValueCount> values;
559 if (values.empty()) {
566 ValueCount tmp = values.front();
570 if (values.front().second == 0) {
572 ValueCount tmp = values.front();
575 --values.front().second;
578 const ValueCount & current_value = values.front();
579 const uint64_t value_to_post = current_value.first;
580 toggle_trigger_notification_source_->postNotification(value_to_post);
581 toggle_notif_trigger_->reschedule();
584void ExampleSimulator::onTriggered_(
const std::string & msg)
586 std::cout <<
" [trigger] " << msg << std::endl;
589template <
typename ParamT>
592 const std::string& param_name,
593 const std::string& ext_name)
599 sparta::TreeNode::ExtensionsBase * ext = ext_name.empty() ?
628template <
typename ExtensionT>
629ExtensionT* ExampleSimulator::getExtension_(
631 const std::string& ext_name)
633 static_assert(std::is_base_of<sparta::TreeNode::ExtensionsBase, ExtensionT>::value,
634 "ExtensionT must be derived from sparta::TreeNode::ExtensionsBase");
640 return ext_name.empty() ?
642 dynamic_cast<ExtensionT*
>(node->
getExtension(ext_name));
645void ExampleSimulator::validateTreeNodeExtensions_()
648 if (
auto prm = getExtensionParameter_<std::string>(
649 getRoot()->getChild(
"cpu.core0.lsu"),
"name_",
"cat"))
651 prm->addDependentValidationCallback(
654 },
"Parameter 'name_' should be 'Tom'");
658 if (
auto prm = getExtensionParameter_<std::string>(
659 getRoot()->getChild(
"cpu.core0.lsu"),
"language_",
"cat"))
661 prm->addDependentValidationCallback(
663 return val ==
"meow" || val ==
"grrr";
664 },
"Parameter 'language_' should be 'meow' or 'grrr'");
668 if (
auto prm = getExtensionParameter_<std::string>(
669 getRoot()->getChild(
"cpu.core0.lsu"),
"name_",
"mouse"))
671 prm->addDependentValidationCallback(
673 return val ==
"Jerry";
674 },
"Parameter 'name_' should be 'Jerry'");
678 if (
auto prm = getExtensionParameter_<std::string>(
679 getRoot()->getChild(
"cpu.core0.lsu"),
"language_",
"mouse"))
681 prm->addDependentValidationCallback(
683 return val ==
"squeak";
684 },
"Parameter 'language_' should be 'squeak'");
688 if (
auto prm = getExtensionParameter_<std::string>(
689 getRoot()->getChild(
"cpu.core0.fpu"),
"color_",
"circle"))
691 prm->addDependentValidationCallback(
693 return val ==
"green";
694 },
"Parameter 'color_' should be 'green'");
698 if (
auto prm = getExtensionParameter_<std::string>(
699 getRoot()->getChild(
"cpu.core0.fpu"),
"shape_",
"circle"))
701 prm->addDependentValidationCallback(
703 return val ==
"round";
704 },
"Parameter 'shape_' should be 'round'");
708 if (
auto prm = getExtensionParameter_<double>(
709 getRoot()->getChild(
"cpu.core0.fpu"),
"degrees_",
"circle"))
711 prm->addDependentValidationCallback(
714 },
"Parameter 'degrees_' should be 360.0");
718 getExtension_<CircleExtensions>(
getRoot()->getChild(
"cpu.core0.fpu"),
"circle")->doSomethingElse();
721 if (
auto prm = getExtensionParameter_<std::string>(
724 prm->addDependentValidationCallback(
727 },
"Parameter 'color_' should be 'red'");
737 if (core0_lsu->getNumExtensions() > 1) {
740 getExtension_<>(core0_lsu);
747 "call to TreeNode::getExtension()");
752 if (
auto prm = getExtensionParameter_<std::string>(
753 getRoot()->getChild(
"cpu.core0.fpu"),
"color_"))
755 prm->addDependentValidationCallback(
757 return val ==
"green";
758 },
"Parameter 'color_' should be 'green'");
762 if (
auto prm = getExtensionParameter_<std::string>(
763 getRoot()->getChild(
"cpu.core0.fpu"),
"shape_"))
765 prm->addDependentValidationCallback(
767 return val ==
"round";
768 },
"Parameter 'shape_' should be 'round'");
772 if (
auto prm = getExtensionParameter_<double>(
773 getRoot()->getChild(
"cpu.core0.fpu"),
"degrees_"))
775 prm->addDependentValidationCallback(
778 },
"Parameter 'degrees_' should be 360.0");
782 if (
auto prm = getExtensionParameter_<std::string>(
783 getRoot()->getChild(
"cpu.core0.fpu"),
"edges_"))
785 prm->addDependentValidationCallback(
788 },
"Parameter 'edges_' should be '0'");
792 if (
auto prm = getExtensionParameter_<std::string>(
793 getRoot()->getChild(
"cpu.core0.dispatch.baz_node",
false),
"ticket_",
"baz_ext"))
795 prm->addDependentValidationCallback(
798 },
"Parameter 'ticket_' should be '663'");
801 if (
auto ext =
getRoot()->getExtension(
"testing",
true )) {
802 auto expected_exts_file = ext->getParameterValueAs<std::string>(
"expected_extensions");
809 std::vector<const sparta::ParameterTree::Node*> ext_root_nodes;
812 for (
auto ext_root_node : ext_root_nodes) {
813 auto tn_pattern = ext_root_node->getParent()->getPath();
814 std::vector<sparta::TreeNode*> matching_tns;
817 for (
auto tn : matching_tns) {
818 for (
auto ext_node : ext_root_node->getChildren()) {
819 auto ext_name = ext_node->getName();
820 ext = tn->getExtension(ext_name);
823 for (
auto param_node : ext_node->getChildren()) {
824 auto actual_val = ext->getParameterValueAs<std::string>(param_node->getName());
825 auto expected_val = param_node->peekValue();
834ExampleSimulator::ExampleController::ExampleController(
836 sparta::app::Simulation::SimulationController(sim)
838 sparta::app::Simulation::SimulationController::addNamedCallback_(
841 sparta::app::Simulation::SimulationController::addNamedCallback_(
847 std::cout <<
" [control] Controller PAUSE method has been called for simulation '"
853 std::cout <<
" [control] Controller RESUME method has been called for simulation '"
859 std::cout <<
" [control] Controller TERMINATE method has been called for simulation '"
864void ExampleSimulator::ExampleController::customEatCallback_()
866 std::cout <<
" [control] Controller CUSTOM method has been called ('eat')" << std::endl;
869void ExampleSimulator::ExampleController::customSleepCallback_()
871 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.
Accepts a sprintf-style format string like "%s_%i.json" and uses the arguments given to postNotificat...
Node in a composite tree representing a sparta Tree item.
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,...
static constexpr group_idx_type GROUP_IDX_NONE
GroupIndex indicating that a node has no group index because it belongs to no group.
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.
Class that is the "top level" or starting point for simulation.
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.