The Sparta Modeling Framework
Loading...
Searching...
No Matches
ConfigApplicators.hpp
Go to the documentation of this file.
1// <ConfigApplicators.h> -*- C++ -*-
2
3
9#pragma once
10
11#include <cinttypes>
12#include <string>
13#include <vector>
14#include <memory>
15#include <utility>
16#include <ostream>
17
18#include "sparta/parsers/ConfigParserYAML.hpp"
19#include "sparta/simulation/ParameterTree.hpp"
21
22namespace sparta {
23namespace app {
24
36{
37public:
41 virtual ~ConfigApplicator() {}
42
47 ASC_DEFER = 0,
48 ASC_MUST_ASSIGN = 1,
49 ASC_IGNORE = 2,
50 MAX_ASC
51 };
52
57 enum class LocationFilter {
61 ALL = 0,
62
69
73 //AT_NODE,
74
79 //BELOW_NODE,
80
84 MAX_AF
85 };
86
90 struct ApplyFilter {
95 : locfilter_(LocationFilter::ALL),
96 locfilter_node_(nullptr)
97 {;}
98
104 ApplyFilter(LocationFilter locfilter, const TreeNode* filternode)
105 : locfilter_(locfilter),
106 locfilter_node_(filternode)
107 {
108 sparta_assert(locfilter_node_,
109 "cannot create a location filter for parameter application with a null filter node");
110 }
111
112 ApplyFilter(const ApplyFilter&) = default;
113 ApplyFilter& operator=(const ApplyFilter&) = default;
114
120 bool test(const TreeNode* n) const {
121 sparta_assert(n);
122 switch(locfilter_)
123 {
125 return true;
126 break;
128 return n->isDescendantOf(locfilter_node_);
129 break;
131 // error out
132 break;
133 };
134 sparta_assert(false,
135 "Unhandled ConfigApplciator::ApplyFilter location filter case: "
136 << static_cast<uint32_t>(locfilter_));
137 return false;
138 }
139
143 LocationFilter getLocationFilter() const { return locfilter_; }
144
148 const TreeNode* getLocationFilterNode() const { return locfilter_node_; }
149
153 friend std::ostream& operator<<(std::ostream& o,
154 const ConfigApplicator::ApplyFilter* filter) {
155 if(filter == nullptr){
156 o << "<null config filter ptr>";
157 return o;
158 }
159
160 return o << *filter;
161 }
162
166 friend std::ostream& operator<<(std::ostream& o, const ConfigApplicator::ApplyFilter& filter) {
167 o << "<cfg-filter ";
168 switch(filter.getLocationFilter()){
170 o << "all_nodes";
171 break;
173 o << "at_or_below_node " << filter.getLocationFilterNode()->getLocation();
174 break;
175 default:
177 "Unhandled ConfigApplciator::ApplyFilter location filter case: " << static_cast<uint32_t>(filter.getLocationFilter()));
178 };
179 o << ">";
180 return o;
181 }
182
183 private:
184 LocationFilter locfilter_;
185 const TreeNode* locfilter_node_;
186 };
187
194 virtual void applyUnbound(sparta::ParameterTree& ptree, bool verbose=false) const = 0;
195
203 ApplyFilter filter=ApplyFilter(),
204 bool verbose=false) {
205 tryApply(root, ApplySuccessCondition::ASC_DEFER, filter, verbose);
206 }
207
213 virtual void tryApply(sparta::TreeNode* root,
214 ApplySuccessCondition required,
215 ApplyFilter filter=ApplyFilter(),
216 bool verbose=false) const = 0;
217
221 virtual std::string stringize() const = 0;
222};
223
228{
232 const std::string loc_pattern_;
233
237 const std::string value_;
238
242 const ApplySuccessCondition default_success_cond_;
243
248 ApplySuccessCondition getSuccessCondition(ApplySuccessCondition ovr) const {
250 return default_success_cond_;
251 }
252 return ovr;
253 }
254
255public:
256 ParameterApplicator(const std::string& loc_pattern,
257 const std::string& value,
259 loc_pattern_(loc_pattern), value_(value), default_success_cond_(required)
260 {;}
261
262 std::string stringize() const override {
263 std::stringstream ss;
264 ss << "Parameter \"" << loc_pattern_ << "\" <- value: \"" << value_ << "\"";
265 switch(default_success_cond_){
267 break; // Ok
269 ss << " [optional parameter]"; // Show
270 break;
272 break; // Ok
273 default:
274 ss << " Unknown ApplySuccessCondition value: " << (int)default_success_cond_;
275 break;
276 }
277 return ss.str();
278 }
279
281 ApplySuccessCondition required,
282 ApplyFilter filter,
283 bool verbose) const override
284 {
285 const ApplySuccessCondition effective_asc = getSuccessCondition(required);
286
287 assert(root);
288 std::vector<sparta::TreeNode*> results;
289 uint32_t found = root->findChildren(loc_pattern_, results);
290
291 // Filter the found nodes by the given filter
292 std::vector<sparta::TreeNode*> filtered_results;
293 std::copy_if(results.begin(), results.end(),
294 std::back_inserter(filtered_results), [&](TreeNode* n)->bool{return filter.test(n);});
295
296 if(0 == filtered_results.size()){
297 // These parameters will be in the unbound list as well. Unresolved
298 // parameters will be handled by the unbound tree so allow missing nodes
299 // while parsing this for now. Later, unread unbound parameters which do not
300 // correspond to sparta::Parameter Nodes will cause exceptions
302 switch(effective_asc){
304 throw sparta::SpartaException("Failed to find any nodes matching pattern \"")
305 << loc_pattern_ << "\" and filter " << filter << " for which to set parameter value \""
306 << value_ << "\"";
307 break;
309 break;
311 sparta_assert(0, "ParameterApplicator cannot have success policy of "
312 "ASC_DEFER. required=" << (int)required << " default="
313 << (int)default_success_cond_ << ". This is likely a bug in "
314 "sparta::app unless other code is creating ParameterApplicators");
315 break;
316 default:
317 sparta_assert(0, "Unknown ApplySuccessCondition value: " << (int)required);
318 break;
319 };
320 return;
321 }
322 uint32_t set = 0;
323 for(sparta::TreeNode* node : filtered_results){
324 sparta::ParameterBase* p = dynamic_cast<sparta::ParameterBase*>(node);
325 if(nullptr != p){
326 if(false == p->isVector()){
327 // Assign the string directly to this node.
328 // It is possible that this can just be parsed as YAML.
329 p->setValueFromString(value_);
330 }else{
331 // Parse the string as YAML and assign it to this node
332 ParameterTree ptree;
333 sparta::ConfigParser::YAML::EventHandler handler("<command line>",
334 {p},
335 ptree,
336 {},
337 verbose);
338
339 // These parameters will be in the unbound list first
340 // and then applied later where it MUST match existing nodes
341 handler.allowMissingNodes(false);
342 std::stringstream input(value_);
343 YP::Parser parser(input);
344 while(parser.HandleNextDocument(*((YP::EventHandler*)&handler))) {}
345
346 if(handler.getErrors().size() != 0){
347 sparta::SpartaException ex("One or more errors detected while parsing "
348 "command line parameter values.\n"
349 "Attempting to intrerpret YAML value '");
350 ex << value_ << "' at " << p->getLocation() << "\n";
351 for(const std::string& es : handler.getErrors()){
352 ex << es << '\n';
353 }
354 throw ex;
355 }
356 }
357 ++set;
358 }
359 }
360 if(0 == set && effective_asc == ApplySuccessCondition::ASC_MUST_ASSIGN){
361 throw sparta::SpartaException("Found ")
362 << found << " nodes matching parameter pattern \""
363 << loc_pattern_ << "\". " << filtered_results.size() << " matched filter "
364 << filter << "too. But none of them were actually parameters";
365 }
366 }
367
368 void applyUnbound(sparta::ParameterTree& ptree, bool verbose=false) const override {
369 (void) verbose;
370 const bool required = default_success_cond_ == ApplySuccessCondition::ASC_MUST_ASSIGN;
371 ptree.set(loc_pattern_, value_, required, "command line");
372 }
373};
374
379{
383 const std::string loc_pattern_;
384
388 const std::string value_;
389
393 const ApplySuccessCondition default_success_cond_;
394
399 ApplySuccessCondition getSuccessCondition(ApplySuccessCondition ovr) const {
401 return default_success_cond_;
402 }
403 return ovr;
404 }
405
406public:
407 ParameterDefaultApplicator(const std::string& loc_pattern,
408 const std::string& value,
410 loc_pattern_(loc_pattern), value_(value), default_success_cond_(required)
411 {;}
412
413 std::string stringize() const override {
414 std::stringstream ss;
415 ss << "Parameter \"" << loc_pattern_ << "\" <- arch value: \"" << value_ << "\"";
416 switch(default_success_cond_){
418 break; // Ok
420 ss << " [optional parameter]"; // Show
421 break;
423 break; // Ok
424 default:
425 ss << " Unknown ApplySuccessCondition value: " << (int)default_success_cond_;
426 break;
427 }
428 return ss.str();
429 }
430
432 ApplySuccessCondition required,
433 ApplyFilter filter=ApplyFilter(),
434 bool verbose=false) const override
435 {
436 const ApplySuccessCondition effective_asc = getSuccessCondition(required);
437
438 assert(root);
439 std::vector<sparta::TreeNode*> results;
440 uint32_t found = root->findChildren(loc_pattern_, results);
441
442 // Filter the found nodes by the given filter
443 std::vector<sparta::TreeNode*> filtered_results;
444 std::copy_if(results.begin(), results.end(),
445 std::back_inserter(filtered_results), [&](TreeNode* n)->bool{return filter.test(n);});
446
447 if(0 == filtered_results.size()){
448 // These parameters will be in the unbound list as well. Unresolved
449 // parameters will be handled by the unbound tree so allow missing nodes
450 // while parsing this for now. Later, unread unbound parameters which do not
451 // correspond to sparta::Parameter Nodes will cause exceptions
453 switch(effective_asc){
455 throw sparta::SpartaException("Failed to find any nodes matching pattern \"")
456 << loc_pattern_ << "\" and filter " << filter << " for which to set parameter value \""
457 << value_ << "\"";
458 break;
460 break;
462 sparta_assert(0, "ParameterDefaultApplicator cannot have success policy of "
463 "ASC_DEFER. required=" << (int)required << " default="
464 << (int)default_success_cond_ << ". This is likely a bug in "
465 "sparta::app unless other code is creating ParameterApplicators");
466 default:
467 sparta_assert(0, "Unknown ApplySuccessCondition value: " << (int)required);
468 };
469 return;
470 }
471 uint32_t set = 0;
472 for(sparta::TreeNode* node : filtered_results){
473 sparta::ParameterBase* p = dynamic_cast<sparta::ParameterBase*>(node);
474 if(nullptr != p){
475 if(false == p->isVector()){
476 // Assign the string directly to this node.
477 // It is possible that this can just be parsed as YAML.
478 p->overrideDefaultFromString(value_);
479 }else{
480 // Parse the string as YAML and assign it to this node
481 ParameterTree ptree;
482 sparta::ConfigParser::YAML::EventHandler handler("<command line>",
483 {p},
484 ptree,
485 {},
486 verbose);
487 // These parameters will be in the unbound list first
488 // and then applied later where it MUST match existing nodes
489 handler.allowMissingNodes(false);
490 handler.writeToDefault(true); // Overwrite DEFAULT value, not value
491 std::stringstream input(value_);
492 YP::Parser parser(input);
493 while(parser.HandleNextDocument(*((YP::EventHandler*)&handler))) {}
494
495 if(handler.getErrors().size() != 0){
496 sparta::SpartaException ex("One or more errors detected while parsing "
497 "command line parameter values.\n"
498 "Attempting to intrerpret YAML value '");
499 ex << value_ << "' at " << p->getLocation() << "\n";
500 for(const std::string& es : handler.getErrors()){
501 ex << es << '\n';
502 }
503 throw ex;
504 }
505 }
506 ++set;
507 }
508 }
509 if(0 == set && effective_asc == ApplySuccessCondition::ASC_MUST_ASSIGN){
510 throw sparta::SpartaException("Found ")
511 << found << " nodes matching parameter pattern \""
512 << loc_pattern_ << "\" and filter " << filter << " but none of them were actually parameters";
513 }
514 }
515
516 void applyUnbound(sparta::ParameterTree& ptree, bool verbose=false) const override {
517 (void) verbose;
518 const bool required = default_success_cond_ == ApplySuccessCondition::ASC_MUST_ASSIGN;
519 ptree.set(loc_pattern_, value_, required, "command line");
520 }
521};
522
523
528{
532 std::string loc_pattern_;
533
538 std::string filename_;
539
543 const std::vector<std::string> include_paths_;
544
548 bool verbose_;
549
550public:
551
552 NodeConfigFileApplicator(const std::string& loc_pattern,
553 const std::string& filename,
554 const std::vector<std::string>& include_paths,
555 bool verbose=false) :
556 loc_pattern_(loc_pattern), filename_(filename),
557 include_paths_(include_paths), verbose_(verbose)
558 {(void)verbose_;}
559
560 std::string stringize() const override {
561 std::stringstream ss;
562 ss << "Node \"" << loc_pattern_ << "\" <- file: \"" << filename_ << "\"";
563 return ss.str();
564 }
565
568 ApplyFilter filter=ApplyFilter(),
569 bool verbose=false) const override
570 {
572 "NodeConfigFileApplicator cannot have success policy of "
573 "ASC_DEFER. This is likely a bug in sparta::app unless other code "
574 "is creating ParameterApplicators");
575
576 assert(root);
577 std::vector<sparta::TreeNode*> results;
578 root->findChildren(loc_pattern_, results);
579
580 // Filter the found nodes by the given filter
581 std::vector<sparta::TreeNode*> filtered_results;
582 std::copy_if(results.begin(), results.end(),
583 std::back_inserter(filtered_results), [&](TreeNode* n)->bool{return filter.test(n);});
584
585 if(0 == filtered_results.size() && asc == ApplySuccessCondition::ASC_MUST_ASSIGN){
586 throw sparta::SpartaException("Failed to find any nodes matching pattern \"")
587 << loc_pattern_ << " and filter " << filter << " for which to apply configuration file \""
588 << filename_ << "\"";
589 }
590 sparta::ConfigParser::YAML param_file(filename_, include_paths_);
591 // These parameters will be in the unbound list as well. Unresolved parameters will be
592 // handled by the unbound tree so allow missing nodes while parsing this for now.
593 // Later, unread unbound parameters which do not correspond to sparta::Parameter Nodes
594 // will cause exceptions
598 param_file.allowMissingNodes(asc != ApplySuccessCondition::ASC_MUST_ASSIGN);
599 param_file.setParameterApplyFilter(std::bind(&ApplyFilter::test, &filter, std::placeholders::_1));
600 for(sparta::TreeNode* node : filtered_results){
601 param_file.consumeParameters(node, verbose);
602 }
603 }
604
605 void applyUnbound(sparta::ParameterTree& ptree, bool verbose=false) const override {
606 // Parse YAML file without actual device tree and extract parameter tree
607 TreeNode dummy("dummy", "dummy");
608 sparta::ConfigParser::YAML param_file(filename_, include_paths_);
609 param_file.allowMissingNodes(true);
610 param_file.consumeParameters(&dummy, verbose);
611 //param_file.getParameterTree().recursePrint(std::cout);
612 ptree.create(loc_pattern_, false)->appendTree(param_file.getParameterTree().getRoot()); // Apply to existing ptree
613 }
614};
615
621{
625 const std::string loc_pattern_;
626
631 const std::string filename_;
632
636 const std::vector<std::string> include_paths_;
637
638public:
639
640 ArchNodeConfigFileApplicator(const std::string& loc_pattern,
641 const std::string& filename,
642 const std::vector<std::string> & include_paths) :
643 loc_pattern_(loc_pattern), filename_(filename),
644 include_paths_(include_paths)
645 {;}
646
647 std::string stringize() const override {
648 std::stringstream ss;
649 ss << "ArchCfg Node \"" << loc_pattern_ << "\" <- file: \"" << filename_ << "\"";
650 return ss.str();
651 }
652
655 ApplyFilter filter=ApplyFilter(),
656 bool verbose=false) const override
657 {
658 (void) root;
659 (void) filter;
660 (void) asc;
661 (void) verbose;
662 throw SpartaException("Cannot \"apply\" ArchNodeConfigFileApplicator - it can only be "
663 "applied to a virtual parameter tree (applyUnbound). It is a bug "
664 "in SPARTA that this function is being called.");
665 }
666
667 void applyUnbound(sparta::ParameterTree& ptree, bool verbose=false) const override {
668 // Parse YAML file without actual device tree and extract parameter tree
669 TreeNode dummy("dummy", "dummy");
670 sparta::ConfigParser::YAML param_file(filename_, include_paths_);
671 param_file.allowMissingNodes(true);
672 param_file.consumeParameters(&dummy, verbose);
673 //param_file.getParameterTree().recursePrint(std::cout);
674 ptree.create(loc_pattern_, false)->appendTree(param_file.getParameterTree().getRoot()); // Apply to existing ptree
675 }
676};
677
678
679typedef std::vector<std::pair<std::string, std::string>> StringPairVec;
680typedef std::vector<std::unique_ptr<ConfigApplicator>> ConfigVec;
681
682
683} // namespace app
684} // namespace sparta
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Basic Node framework in sparta device tree composite pattern.
Non-templated base class for generic parameter access and iteration.
virtual bool isVector() const =0
Determines whether this Parameter is a vector or a scalar Parameter.
void setValueFromString(const std::string &str, bool poke=false)
Attempts to assign a value to this non-vector Parameter from a string.
virtual void overrideDefaultFromString(const std::string &val)=0
Sets the default value of this non-vector parameter for architecture baseline configuration purposes.
void appendTree(const Node *ot)
Appends a tree as a child of this node.
Virtual Parameter Tree. This represents a tree of parameters read from some source but does not neces...
Node * create(const std::string &path, bool required=false)
Add a node to the tree, with proper priority.
bool set(const std::string &path, const std::string &value, bool required, const std::string &origin="")
Add a parameter to the tree, replacing any existing parameter.
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:205
std::string getLocation() const override final
bool isDescendantOf(const TreeNode *ancestor, int32_t max_depth=-1) const
Determines if this node is a descendant of the specified ancestor node within some number of generati...
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 an architectural configuration (parameter defaults) to a virtual parameter tree....
std::string stringize() const override
Render this parameter action as a string.
void tryApply(sparta::TreeNode *root, ApplySuccessCondition asc, ApplyFilter filter=ApplyFilter(), bool verbose=false) const override
Apply the parameter contained in this object to the tree starting at root.
void applyUnbound(sparta::ParameterTree &ptree, bool verbose=false) const override
Apply the parameter contained in this object to the unbound (virtual) parameter tree ptree.
Base class for applying parameters or configuration files to the simulator device tree....
void apply(sparta::TreeNode *root, ApplyFilter filter=ApplyFilter(), bool verbose=false)
Apply the parameter contained in this object to the tree starting at root.
virtual ~ConfigApplicator()
Virtual destructor.
virtual void applyUnbound(sparta::ParameterTree &ptree, bool verbose=false) const =0
Apply the parameter contained in this object to the unbound (virtual) parameter tree ptree.
ApplySuccessCondition
Type for dictating how tryApply should behave.
@ ASC_DEFER
Defer to another layer in the parameter-application process to make the decision (i....
@ ASC_MUST_ASSIGN
Must assign the parameter to success.
@ ASC_IGNORE
Ignore failures to assign the parameter.
virtual std::string stringize() const =0
Render this parameter action as a string.
virtual void tryApply(sparta::TreeNode *root, ApplySuccessCondition required, ApplyFilter filter=ApplyFilter(), bool verbose=false) const =0
Apply the parameter contained in this object to the tree starting at root.
LocationFilter
Type for dictating how to filter the parameter application. (i.e. only apply to certain parts of the ...
@ AT_OR_BELOW_NODE
Apply configuration to any nodes that are or are below a given filter node. Typically,...
@ MAX_AF
Apply configuration only to a given filter node if applicable. (unimplemented)
@ ALL
Apply configuration to any nodes that match pattern and type (typical)
Applies a configuration file to a node pattern.
void tryApply(sparta::TreeNode *root, ApplySuccessCondition asc, ApplyFilter filter=ApplyFilter(), bool verbose=false) const override
Apply the parameter contained in this object to the tree starting at root.
std::string stringize() const override
Render this parameter action as a string.
void applyUnbound(sparta::ParameterTree &ptree, bool verbose=false) const override
Apply the parameter contained in this object to the unbound (virtual) parameter tree ptree.
Applies a value to a parameter 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.
void tryApply(sparta::TreeNode *root, ApplySuccessCondition required, ApplyFilter filter, bool verbose) const override
Apply the parameter contained in this object to the tree starting at root.
std::string stringize() const override
Render this parameter action as a string.
Applies a new default value to a parameter node pattern.
void tryApply(sparta::TreeNode *root, ApplySuccessCondition required, ApplyFilter filter=ApplyFilter(), bool verbose=false) const override
Apply the parameter contained in this object to the tree starting at root.
std::string stringize() const override
Render this parameter action as a string.
void applyUnbound(sparta::ParameterTree &ptree, bool verbose=false) const override
Apply the parameter contained in this object to the unbound (virtual) parameter tree ptree.
Macros for handling exponential backoff.
Represents a filter for applying parameters based on tree location.
friend std::ostream & operator<<(std::ostream &o, const ConfigApplicator::ApplyFilter *filter)
Prinit a configuration-application filter.
ApplyFilter()
Construct a null-filter (filters nothing)
LocationFilter getLocationFilter() const
Return the location filter policy.
const TreeNode * getLocationFilterNode() const
RReturn the location filter node (may be none)
ApplyFilter(LocationFilter locfilter, const TreeNode *filternode)
Construct a location-filter.
bool test(const TreeNode *n) const
Test a node against this filter.
friend std::ostream & operator<<(std::ostream &o, const ConfigApplicator::ApplyFilter &filter)
Prinit a configuration-application filter.