The Sparta Modeling Framework
Loading...
Searching...
No Matches
ExampleSimulation.cpp
1// <Simulation.cpp> -*- C++ -*-
2
3
4#include <iostream>
5
6
7#include "ExampleSimulation.hpp"
8#include "Core.hpp"
9#include "CPUFactory.hpp"
10
12#include "sparta/utils/TimeManager.hpp"
14#include "sparta/simulation/TreeNodeExtensions.hpp"
15#include "sparta/trigger/ContextCounterTrigger.hpp"
21
22#include "Fetch.hpp"
23#include "Decode.hpp"
24#include "Rename.hpp"
25#include "Dispatch.hpp"
26#include "Execute.hpp"
27#include "LSU.hpp"
28#include "ROB.hpp"
29#include "FlushManager.hpp"
30#include "Preloader.hpp"
31#include "CustomHistogramStats.hpp"
32
33// UPDATE
34#include "BIU.hpp"
35#include "MSS.hpp"
36
37namespace sparta {
38
39 // Example parameter set used to reproduce write-final-config
41 public:
42 IntParameterSet(TreeNode * parent) :
43 ParameterSet(parent),
44 int_param_(new Parameter<uint32_t>(
45 "baz", 0, "Example parameter set to reproduce bug"))
46 {
47 addParameter_(int_param_.get());
48 }
49
50 uint32_t read() const {
51 return int_param_->getValue();
52 }
53
54 private:
55 std::unique_ptr<Parameter<uint32_t>> int_param_;
56 };
57
58 // Dummy node class used together with IntParameterSet to
59 // reproduce write-final-config bug
60 class Baz : public TreeNode {
61 public:
62 Baz(TreeNode* parent,
63 const std::string & desc) :
64 TreeNode(parent, "baz_node", "BazGroup", 0, desc)
65 {
66 baz_.reset(new IntParameterSet(this));
67 }
68
69 void readParams() {
70 std::cout << " Node '" << getLocation()
71 << "' has parameter 'baz' with a value set to "
72 << baz_->read() << std::endl;
73
74 auto ext = getExtension("baz_ext", true);
75 if(ext) {
76 std::cout << "That's the ticket: "
77 << ext->getParameters()->getParameterValueAs<std::string>("ticket_") << std::endl;
78 }
79 }
80
81 private:
82 std::unique_ptr<IntParameterSet> baz_;
83 };
84
85}
86
87class CircleExtensions : public sparta::ExtensionsParamsOnly
88{
89public:
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.";
94 }
95
96private:
97 // Note: this parameter is NOT in the yaml config file,
98 // but subclasses can provide any parameter type supported
99 // by sparta::Parameter<T> which may be too complicated to
100 // clearly describe using simple yaml syntax
101 std::unique_ptr<sparta::Parameter<double>> degrees_;
102
103 // The base class will clobber together whatever parameter values it
104 // found in the yaml file, and give us a chance to add custom parameters
105 // to the same set
106 void postCreate() override {
107 sparta::ParameterSet * ps = getParameters();
108 degrees_.reset(new sparta::Parameter<double>(
109 "degrees_", 360.0, "Number of degrees in a circle", ps));
110 }
111};
112
113class NeverExplicitlyInstantiated : public sparta::ExtensionsParamsOnly
114{
115private:
116 void postCreate() override {
117 sparta::ParameterSet * ps = getParameters();
118 value_.reset(new sparta::Parameter<int>(
119 "value_", 555, "Dummy value", ps));
120 }
121
122 std::unique_ptr<sparta::Parameter<int>> value_;
123};
124
125double calculateAverageOfInternalCounters(
126 const std::vector<const sparta::CounterBase*> & counters)
127{
128 double agg = 0;
129 for (const auto & ctr : counters) {
130 agg += ctr->get();
131 }
132 return agg / counters.size();
133}
134
135ExampleSimulator::ExampleSimulator(const std::string& topology,
136 sparta::Scheduler & scheduler,
137 uint32_t num_cores,
138 uint64_t instruction_limit,
139 bool show_factories) :
140 sparta::app::Simulation("sparta_core_example", &scheduler),
141 cpu_topology_(topology),
142 num_cores_(num_cores),
143 instruction_limit_(instruction_limit),
144 show_factories_(show_factories)
145{
146 // Set up the CPU Resource Factory to be available through ResourceTreeNode
148
149 // Set up all node extension factories to be available during the simulation
150 // - This is only needed for parameter sets that also want to add some methods
151 // to their tree node extension, and/or for those that want to extend node
152 // parameter sets with more complicated sparta::Parameter<T> data types
153 addTreeNodeExtensionFactory_("circle", [](){return new CircleExtensions;});
154 addTreeNodeExtensionFactory_("never_explicitly_instantiated", [](){return new NeverExplicitlyInstantiated;});
155
156 // Initialize example simulation controller
157 controller_.reset(new ExampleSimulator::ExampleController(this));
159
160 // Register a custom calculation method for 'combining' a context counter's
161 // internal counters into one number. In this example simulator, let's just
162 // use an averaging function called "avg" which we can then invoke from report
163 // definition YAML files.
164 sparta::trigger::ContextCounterTrigger::registerContextCounterCalcFunction(
165 "avg", &calculateAverageOfInternalCounters);
166}
167
168void ExampleSimulator::registerStatCalculationFcns_()
169{
170 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, stdev_x3);
171 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, fraction_coverage_greaterThan2StdDev);
172 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, fraction_coverage_mean_p_StdDev_mean_p_2StdDev);
173 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, fraction_coverage_mean_mean_p_StdDev);
174 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, fraction_coverage_mean_m_StdDev_mean);
175 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, fraction_coverage_mean_m_2StdDev_mean_m_StdDev);
176 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, fraction_coverage_lesserThan2StdDev);
177 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, stdev_x3_h);
178 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, fraction_coverage_greaterThan2StdDev_h);
179 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, fraction_coverage_mean_p_StdDev_mean_p_2StdDev_h);
180 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, fraction_coverage_mean_mean_p_StdDev_h);
181 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, fraction_coverage_mean_m_StdDev_mean_h);
182 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, fraction_coverage_mean_m_2StdDev_mean_m_StdDev_h);
183 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, fraction_coverage_lesserThan2StdDev_h);
184}
185
186ExampleSimulator::~ExampleSimulator()
187{
188 getRoot()->enterTeardown(); // Allow deletion of nodes without error now
189 if (on_triggered_notifier_registered_) {
190 getRoot()->DEREGISTER_FOR_NOTIFICATION(
191 onTriggered_, std::string, "sparta_expression_trigger_fired");
192 }
193}
194
196auto ExampleSimulator::getCPUFactory_() -> core_example::CPUFactory*{
197 auto sparta_res_factory = getResourceSet()->getResourceFactory("cpu");
198 auto cpu_factory = dynamic_cast<core_example::CPUFactory*>(sparta_res_factory);
199 return cpu_factory;
200}
201
202void ExampleSimulator::buildTree_()
203{
204 // TREE_BUILDING Phase. See sparta::PhasedObject::TreePhase
205 // Register all the custom stat calculation functions with (cycle)histogram nodes
206 registerStatCalculationFcns_();
207
208 auto cpu_factory = getCPUFactory_();
209
210 // Set the cpu topology that will be built
211 cpu_factory->setTopology(cpu_topology_, num_cores_);
212
213 // Create a single CPU
215 "cpu",
218 "CPU Node",
219 cpu_factory);
220 to_delete_.emplace_back(cpu_tn);
221
222 // Tell the factory to build the resources now
223 cpu_factory->buildTree(getRoot());
224
225 // Print the registered factories
226 if(show_factories_){
227 std::cout << "Registered factories: \n";
228 for(const auto& f : getCPUFactory_()->getResourceNames()){
229 std::cout << "\t" << f << std::endl;
230 }
231 }
232
233 // Validate tree node extensions during tree building
234 for(uint32_t i = 0; i < num_cores_; ++i){
235 const std::string dispatch_loc = "cpu.core" + std::to_string(i) + ".dispatch";
236 const std::string alu0_loc = "cpu.core" + std::to_string(i) + ".alu0";
237 const std::string alu1_loc = "cpu.core" + std::to_string(i) + ".alu1";
238 const std::string fpu_loc = "cpu.core" + std::to_string(i) + ".fpu";
239
240 // user_data.when_ (dispatch)
241 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(dispatch_loc), "when_", "user_data")) {
242 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
243 return val == "buildTree_";
244 }, "Parameter 'when_' should be 'buildTree_'");
245 }
246
247 // user_data.why_ (dispatch)
248 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(dispatch_loc), "why_", "user_data")) {
249 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
250 return val == "checkAvailability";
251 }, "Parameter 'why_' should be 'checkAvailability'");
252 }
253
254 // square.edges_ (dispatch)
255 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(dispatch_loc), "edges_", "square")) {
256 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
257 return val == "4";
258 }, "Parameter 'edges_' should be '4'");
259 }
260
261 // difficulty.color_ (alu0)
262 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(alu0_loc), "color_", "difficulty")) {
263 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
264 return val == "black";
265 }, "Parameter 'color_' should be 'black'");
266 }
267
268 // difficulty.shape_ (alu0)
269 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(alu0_loc), "shape_", "difficulty")) {
270 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
271 return val == "diamond";
272 }, "Parameter 'shape_' should be 'diamond'");
273 }
274
275 // difficulty.color_ (alu1)
276 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(alu1_loc), "color_", "difficulty")) {
277 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
278 return val == "green";
279 }, "Parameter 'color_' should be 'green'");
280 }
281
282 // difficulty.shape_ (alu1)
283 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(alu1_loc), "shape_", "difficulty")) {
284 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
285 return val == "circle";
286 }, "Parameter 'shape_' should be 'circle'");
287 }
288
289 // circle.color_ (fpu)
290 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(fpu_loc), "color_", "circle")) {
291 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
292 return val == "green";
293 }, "Parameter 'color_' should be 'green'");
294 }
295
296 // circle.shape_ (fpu)
297 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(fpu_loc), "shape_", "circle")) {
298 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
299 return val == "round";
300 }, "Parameter 'shape_' should be 'round'");
301 }
302
303 // circle.degrees_ (fpu)
304 if (auto prm = getExtensionParameter_<double>(getRoot()->getChild(fpu_loc), "degrees_", "circle")) {
305 prm->addDependentValidationCallback([](double & val, const sparta::TreeNode*) -> bool {
306 return val == 360.0;
307 }, "Parameter 'degrees_' should be 360.0");
308 }
309
310 // circle.edges_ (fpu)
311 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(fpu_loc), "edges_", "circle")) {
312 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
313 return val == "0";
314 }, "Parameter 'edges_' should be '0'");
315 }
316
317 // User-specified extension class
318 getExtension_<CircleExtensions>(getRoot()->getChild(fpu_loc), "circle")->doSomethingElse();
319 }
320
321 // Attach two tree nodes to get the following:
322 // top
323 // core0
324 // dispatch
325 // baz_node
326 // params
327 // baz
328 // fpu
329 // baz_node
330 // params
331 // baz
332 //
333 // This is needed to reproduce a write-final-config bug where an arch file
334 // specifies 'top.core0.*.baz_node.params.baz: 300' and the ConfigEmitterYAML
335 // ends up throwing an exception due to the '*' which tripped up the tree node
336 // extensions code.
337 auto dispatch = getRoot()->getChild("cpu.core0.dispatch");
338 auto fpu = getRoot()->getChild("cpu.core0.fpu");
339
340 dispatch_baz_.reset(new sparta::Baz(
341 dispatch, "Dummy node under top.cpu.core0.dispatch (to reproduce a SPARTA bug)"));
342
343 fpu_baz_.reset(new sparta::Baz(
344 fpu, "Dummy node under top.cpu.core0.fpu (to reproduce a SPARTA bug)"));
345}
346
347void ExampleSimulator::configureTree_()
348{
349 validateTreeNodeExtensions_();
350
351 // In TREE_CONFIGURING phase
352 // Configuration from command line is already applied
353
354 // Read these parameter values to avoid 'unread unbound parameter' exceptions:
355 // top.cpu.core0.dispatch.baz_node.params.baz
356 // top.cpu.core0.fpu.baz_node.params.baz
357 dispatch_baz_->readParams();
358 fpu_baz_->readParams();
359
360 sparta::ParameterBase* max_instrs =
361 getRoot()->getChildAs<sparta::ParameterBase>("cpu.core0.rob.params.num_insts_to_retire");
362
363 // Safely assign as string for now in case parameter type changes.
364 // Direct integer assignment without knowing parameter type is not yet available through C++ API
365 if(instruction_limit_ != 0){
366 max_instrs->setValueFromString(sparta::utils::uint64_to_str(instruction_limit_));
367 }
368
369 testing_notification_source_.reset(new sparta::NotificationSource<uint64_t>(
370 this->getRoot()->getSearchScope()->getChild("top.cpu.core0.rob"),
371 "testing_notif_channel",
372 "Notification channel for testing purposes only",
373 "testing_notif_channel"));
374
375 toggle_trigger_notification_source_.reset(new sparta::NotificationSource<uint64_t>(
376 getRoot()->getSearchScope()->getChild("top.cpu.core0.rob"),
377 "stats_profiler",
378 "Notification channel for testing report toggling on/off (statistics profiling)",
379 "stats_profiler"));
380
381 legacy_warmup_report_starter_.reset(new sparta::NotificationSource<uint64_t>(
382 getRoot(),
383 "all_threads_warmup_instruction_count_retired_re4",
384 "Legacy notificiation channel for testing purposes only",
385 "all_threads_warmup_instruction_count_retired_re4"));
386
387 getRoot()->REGISTER_FOR_NOTIFICATION(
388 onTriggered_, std::string, "sparta_expression_trigger_fired");
389 on_triggered_notifier_registered_ = true;
390}
391
392void ExampleSimulator::bindTree_()
393{
394 // In TREE_FINALIZED phase
395 // Tree is finalized. Taps placed. No new nodes at this point
396 // Bind appropriate ports
397
398 //Tell the factory to bind all units
399 auto cpu_factory = getCPUFactory_();
400 cpu_factory->bindTree(getRoot());
401
402 sparta::SpartaHandler cb = sparta::SpartaHandler::from_member<
403 ExampleSimulator, &ExampleSimulator::postRandomNumber_>(
404 this, "ExampleSimulator::postRandomNumber_");
405
406 random_number_trigger_.reset(new sparta::trigger::ExpressionCounterTrigger(
407 "RandomNumber", cb, "cpu.core0.rob.stats.total_number_retired 7500", false, this->getRoot()));
408
409 toggle_notif_trigger_.reset(new sparta::trigger::ExpressionTimeTrigger(
410 "ToggleNotif",
411 CREATE_SPARTA_HANDLER(ExampleSimulator, postToToggleTrigger_),
412 "1 ns",
413 getRoot()));
414
415 static const uint32_t warmup_multiplier = 1000;
416 auto gen_expression = [](const uint32_t core_idx) {
417 std::ostringstream oss;
418 oss << "cpu.core" << core_idx << ".rob.stats.total_number_retired >= "
419 << ((core_idx+1) * warmup_multiplier);
420 return oss.str();
421 };
422
423 num_cores_still_warming_up_ = num_cores_;
424 core_warmup_listeners_.reserve(num_cores_);
425
426 for (uint32_t core_idx = 0; core_idx < num_cores_; ++core_idx) {
427 core_warmup_listeners_.emplace_back(
428 new sparta::trigger::ExpressionTrigger(
429 "LegacyWarmupNotifications",
430 CREATE_SPARTA_HANDLER(ExampleSimulator, onLegacyWarmupNotification_),
431 gen_expression(core_idx),
432 getRoot(),
433 nullptr));
434 }
435}
436
437void ExampleSimulator::onLegacyWarmupNotification_()
438{
439 sparta_assert(num_cores_still_warming_up_ > 0);
440 --num_cores_still_warming_up_;
441 if (num_cores_still_warming_up_ == 0) {
442 legacy_warmup_report_starter_->postNotification(1);
443 }
444}
445
446const sparta::CounterBase* ExampleSimulator::findSemanticCounter_(CounterSemantic sem) const {
447 switch(sem){
449 return getRoot()->getChildAs<const sparta::CounterBase>("cpu.core0.rob.stats.total_number_retired");
450 break;
451 default:
452 return nullptr;
453 }
454}
455
456void ExampleSimulator::postRandomNumber_()
457{
458 const size_t random = rand() % 25;
459 testing_notification_source_->postNotification(random);
460 random_number_trigger_->reschedule();
461}
462
463void ExampleSimulator::postToToggleTrigger_()
464{
465 typedef std::pair<uint64_t,uint64_t> ValueCount;
466 static std::queue<ValueCount> values;
467
468 if (values.empty()) {
469 values.push({0,15});
470 values.push({1,25});
471 values.push({0,15});
472 values.push({1,25});
473 values.push({0,15});
474
475 ValueCount tmp = values.front();
476 values.push(tmp);
477 }
478
479 if (values.front().second == 0) {
480 values.pop();
481 ValueCount tmp = values.front();
482 values.push(tmp);
483 } else {
484 --values.front().second;
485 }
486
487 const ValueCount & current_value = values.front();
488 const uint64_t value_to_post = current_value.first;
489 toggle_trigger_notification_source_->postNotification(value_to_post);
490 toggle_notif_trigger_->reschedule();
491}
492
493void ExampleSimulator::onTriggered_(const std::string & msg)
494{
495 std::cout << " [trigger] " << msg << std::endl;
496}
497
498template <typename ParamT>
499sparta::Parameter<ParamT>* ExampleSimulator::getExtensionParameter_(
500 sparta::TreeNode* node,
501 const std::string& param_name,
502 const std::string& ext_name)
503{
504 if (!node) {
505 return nullptr;
506 }
507
508 sparta::TreeNode::ExtensionsBase * ext = ext_name.empty() ?
509 node->createExtension() :
510 node->getExtension(ext_name, true);
511
512 if (!ext) {
513 return nullptr;
514 }
515
516 sparta::ParameterSet * params = ext->getParameters();
517 if (!params) {
518 return nullptr;
519 }
520
521 if (!params->hasParameter(param_name)) {
522 return nullptr;
523 }
524
525 auto param = &params->getParameterAs<ParamT>(param_name);
526
527 // The only reason this method exists is to get the parameter
528 // and then call addDependentValidationCallback() on it. The
529 // validation callbacks do not trigger an increment on the
530 // parameter's read count. Read the value now so we can avoid
531 // the "unread unbound parameter" exceptions.
532 param->getValue();
533
534 return param;
535}
536
537template <typename ExtensionT>
538ExtensionT* ExampleSimulator::getExtension_(
539 sparta::TreeNode* node,
540 const std::string& ext_name)
541{
542 static_assert(std::is_base_of<sparta::TreeNode::ExtensionsBase, ExtensionT>::value,
543 "ExtensionT must be derived from sparta::TreeNode::ExtensionsBase");
544
545 if (!node) {
546 return nullptr;
547 }
548
549 return ext_name.empty() ?
550 dynamic_cast<ExtensionT*>(node->getExtension()) :
551 dynamic_cast<ExtensionT*>(node->getExtension(ext_name));
552}
553
554void ExampleSimulator::validateTreeNodeExtensions_()
555{
556 // cat.name_
557 if (auto prm = getExtensionParameter_<std::string>(
558 getRoot()->getChild("cpu.core0.lsu"), "name_", "cat"))
559 {
560 prm->addDependentValidationCallback(
561 [](std::string & val, const sparta::TreeNode*) -> bool {
562 return val == "Tom";
563 }, "Parameter 'name_' should be 'Tom'");
564 }
565
566 // cat.language_
567 if (auto prm = getExtensionParameter_<std::string>(
568 getRoot()->getChild("cpu.core0.lsu"), "language_", "cat"))
569 {
570 prm->addDependentValidationCallback(
571 [](std::string & val, const sparta::TreeNode*) -> bool {
572 return val == "meow" || val == "grrr";
573 }, "Parameter 'language_' should be 'meow' or 'grrr'");
574 }
575
576 // mouse.name_
577 if (auto prm = getExtensionParameter_<std::string>(
578 getRoot()->getChild("cpu.core0.lsu"), "name_", "mouse"))
579 {
580 prm->addDependentValidationCallback(
581 [](std::string & val, const sparta::TreeNode*) -> bool {
582 return val == "Jerry";
583 }, "Parameter 'name_' should be 'Jerry'");
584 }
585
586 // mouse.language_
587 if (auto prm = getExtensionParameter_<std::string>(
588 getRoot()->getChild("cpu.core0.lsu"), "language_", "mouse"))
589 {
590 prm->addDependentValidationCallback(
591 [](std::string & val, const sparta::TreeNode*) -> bool {
592 return val == "squeak";
593 }, "Parameter 'language_' should be 'squeak'");
594 }
595
596 // circle.color_
597 if (auto prm = getExtensionParameter_<std::string>(
598 getRoot()->getChild("cpu.core0.fpu"), "color_", "circle"))
599 {
600 prm->addDependentValidationCallback(
601 [](std::string & val, const sparta::TreeNode*) -> bool {
602 return val == "green";
603 }, "Parameter 'color_' should be 'green'");
604 }
605
606 // circle.shape_
607 if (auto prm = getExtensionParameter_<std::string>(
608 getRoot()->getChild("cpu.core0.fpu"), "shape_", "circle"))
609 {
610 prm->addDependentValidationCallback(
611 [](std::string & val, const sparta::TreeNode*) -> bool {
612 return val == "round";
613 }, "Parameter 'shape_' should be 'round'");
614 }
615
616 // circle.degrees_
617 if (auto prm = getExtensionParameter_<double>(
618 getRoot()->getChild("cpu.core0.fpu"), "degrees_", "circle"))
619 {
620 prm->addDependentValidationCallback(
621 [](double & val, const sparta::TreeNode*) -> bool {
622 return val == 360.0;
623 }, "Parameter 'degrees_' should be 360.0");
624 }
625
626 // User-specified extension class
627 getExtension_<CircleExtensions>(getRoot()->getChild("cpu.core0.fpu"), "circle")->doSomethingElse();
628
629 // apple.color_
630 if (auto prm = getExtensionParameter_<std::string>(
631 getRoot(), "color_", "apple"))
632 {
633 prm->addDependentValidationCallback(
634 [](std::string & val, const sparta::TreeNode*) -> bool {
635 return val == "red";
636 }, "Parameter 'color_' should be 'red'");
637 }
638
639 // The 'core0.lsu' node has two named extensions, so asking that node for
640 // unqualified extensions (no name specified) should throw.
641 //
642 // Note that we still have to check if core0.lsu has multiple extensions,
643 // since it will have zero in most example simulations unless --extension-file
644 // was used.
645 auto core0_lsu = getRoot()->getChild("cpu.core0.lsu");
646 if (core0_lsu->getNumExtensions() > 1) {
647 bool threw = false;
648 try {
649 getExtension_<>(core0_lsu);
650 } catch (...) {
651 threw = true;
652 }
653
654 if (!threw) {
655 throw sparta::SpartaException("Expected an exception to be thrown for unqualified "
656 "call to TreeNode::getExtension()");
657 }
658 }
659
660 // <unnamed>.color_
661 if (auto prm = getExtensionParameter_<std::string>(
662 getRoot()->getChild("cpu.core0.fpu"), "color_"))
663 {
664 prm->addDependentValidationCallback(
665 [](std::string & val, const sparta::TreeNode*) -> bool {
666 return val == "green";
667 }, "Parameter 'color_' should be 'green'");
668 }
669
670 // <unnamed>.shape_
671 if (auto prm = getExtensionParameter_<std::string>(
672 getRoot()->getChild("cpu.core0.fpu"), "shape_"))
673 {
674 prm->addDependentValidationCallback(
675 [](std::string & val, const sparta::TreeNode*) -> bool {
676 return val == "round";
677 }, "Parameter 'shape_' should be 'round'");
678 }
679
680 // <unnamed>.degrees_
681 if (auto prm = getExtensionParameter_<double>(
682 getRoot()->getChild("cpu.core0.fpu"), "degrees_"))
683 {
684 prm->addDependentValidationCallback(
685 [](double & val, const sparta::TreeNode*) -> bool {
686 return val == 360.0;
687 }, "Parameter 'degrees_' should be 360.0");
688 }
689
690 // <unnamed>.edges_
691 if (auto prm = getExtensionParameter_<std::string>(
692 getRoot()->getChild("cpu.core0.fpu"), "edges_"))
693 {
694 prm->addDependentValidationCallback(
695 [](std::string & val, const sparta::TreeNode*) -> bool {
696 return val == "0";
697 }, "Parameter 'edges_' should be '0'");
698 }
699
700 // baz_ext.ticket_
701 if (auto prm = getExtensionParameter_<std::string>(
702 getRoot()->getChild("cpu.core0.dispatch.baz_node", false), "ticket_", "baz_ext"))
703 {
704 prm->addDependentValidationCallback(
705 [](std::string & val, const sparta::TreeNode*) -> bool {
706 return val == "663";
707 }, "Parameter 'ticket_' should be '663'");
708 }
709}
710
711ExampleSimulator::ExampleController::ExampleController(
712 const sparta::app::Simulation * sim) :
713 sparta::app::Simulation::SimulationController(sim)
714{
715 sparta::app::Simulation::SimulationController::addNamedCallback_(
716 "eat", CREATE_SPARTA_HANDLER(ExampleController, customEatCallback_));
717
718 sparta::app::Simulation::SimulationController::addNamedCallback_(
719 "sleep", CREATE_SPARTA_HANDLER(ExampleController, customSleepCallback_));
720}
721
722void ExampleSimulator::ExampleController::pause_(const sparta::app::Simulation * sim)
723{
724 std::cout << " [control] Controller PAUSE method has been called for simulation '"
725 << sim->getSimName() << "'" << std::endl;
726}
727
728void ExampleSimulator::ExampleController::resume_(const sparta::app::Simulation * sim)
729{
730 std::cout << " [control] Controller RESUME method has been called for simulation '"
731 << sim->getSimName() << "'" << std::endl;
732}
733
734void ExampleSimulator::ExampleController::terminate_(const sparta::app::Simulation * sim)
735{
736 std::cout << " [control] Controller TERMINATE method has been called for simulation '"
737 << sim->getSimName() << "'" << std::endl;
738 const_cast<sparta::Scheduler*>(sim->getScheduler())->stopRunning();
739}
740
741void ExampleSimulator::ExampleController::customEatCallback_()
742{
743 std::cout << " [control] Controller CUSTOM method has been called ('eat')" << std::endl;
744}
745
746void ExampleSimulator::ExampleController::customSleepCallback_()
747{
748 std::cout << " [control] Controller CUSTOM method has been called ('sleep')" << std::endl;
749}
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.
Cool string utilities.
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.
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.
Node in a composite tree representing a sparta Tree item.
Definition TreeNode.hpp:204
static const group_idx_type GROUP_IDX_NONE
GroupIndex indicating that a node has no group index because it belongs to no group.
Definition TreeNode.hpp:302
std::string getLocation() const override final
ExtensionsBase * getExtension(const std::string &extension_name, bool no_factory_ok=false)
Get an extension object by type string. Returns nullptr if not found (unrecognized).
static constexpr char GROUP_NAME_NONE[]
Group name indicating that a node belongs to no group.
Definition TreeNode.hpp:313
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.
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.