The Sparta Modeling Framework
Loading...
Searching...
No Matches
RootArchiveNode.hpp
1// <RootArchiveNode> -*- C++ -*-
2
3#pragma once
4
5#include "sparta/statistics/dispatch/archives/ArchiveNode.hpp"
7
8#include <boost/serialization/map.hpp>
9#include <boost/serialization/vector.hpp>
10
11namespace sparta {
12namespace statistics {
13
14class ArchiveNode;
15class ArchiveController;
16
35{
36public:
37 RootArchiveNode() = default;
38
39 explicit RootArchiveNode(const std::string & name) :
40 ArchiveNode(name)
41 {}
42
43 void initialize() {
44 size_t num_leaves = 0;
45 recursGetNumLeafChildren_(*this, num_leaves);
46 total_num_leaves_ = num_leaves;
47 }
48
50 void setMetadata(const app::NamedExtensions & metadata) {
51 metadata_ = metadata;
52 }
53
54 template <typename MetadataT>
55 void setMetadataValue(const std::string & name, const MetadataT & value) {
56 boost::any any_value(value);
57 metadata_[name] = any_value;
58 }
59
60 template <typename MetadataT>
61 const MetadataT & getMetadataValue(const std::string & name) const {
62 auto iter = metadata_.find(name);
63 if (iter == metadata_.end()) {
64 throw SpartaException("Metadata does not exist: ") << name;
65 }
66 try {
67 return boost::any_cast<const MetadataT &>(iter->second);
68 } catch (const boost::bad_any_cast &) {
69 throw SpartaException("Metadata named '")
70 << name << "' does exist, but is not of type '"
71 << typeid(MetadataT).name() << "'";
72 }
73 }
74
75 template <typename MetadataT>
76 const MetadataT * tryGetMetadataValue(const std::string & name) const {
77 auto iter = metadata_.find(name);
78 if (iter == metadata_.end()) {
79 return nullptr;
80 }
81 try {
82 return &boost::any_cast<const MetadataT &>(iter->second);
83 } catch (const boost::bad_any_cast &) {
84 return nullptr;
85 }
86 }
87
88 size_t getTotalNumLeaves() const {
89 return total_num_leaves_;
90 }
91
97 void setArchiveController(const std::shared_ptr<ArchiveController> & controller) {
98 archive_controller_ = controller;
99 }
100 void saveTo(const std::string & dir);
101 bool synchronize();
102
103private:
104 void recursGetNumLeafChildren_(
105 const RootArchiveNode & node, size_t & num_leaves) const
106 {
107 if (node.getChildren().empty()) {
108 ++num_leaves;
109 } else {
110 for (const auto & child : node.getChildren()) {
111 num_leaves += child->getTotalNumLeaves();
112 }
113 }
114 }
115
119 template <class Archive>
120 void serialize(Archive & ar, const unsigned int) {
121 //Keep in mind that this one method is called for both
122 //serialization to disk, and deserialization from disk.
123
124 //Read/write node name
125 ar & name_;
126
127 //Read/write children vector
128 ar & children_;
129
130 //Read/write the total_num_leaves_ value. This serialize()
131 //method is defined at the bottom of ArchiveNode.h
132 ar & total_num_leaves_;
133
134 //Serialize trigger metadata
135 if (!metadata_.empty()) {
136 //Boost has called this serialize() method, and since
137 //our metadata map is not empty, that means we are now
138 //*writing* to disk. This map is a bunch of boost::any's
139 //which cannot be serialized as easily as a std::string
140 //or size_t, etc. We will have to pick it apart into a
141 //std::map<std::string, std::string> and just serialize
142 //that data structure to get around it.
143 //
144 //Note that we are using a map and not an unordered_map
145 //because older Boost versions do not support serialization
146 //of unordered_map. This map is never larger than 4 or 5
147 //items, so performance is not really different either way.
148 auto iter = metadata_.find("trigger");
149 sparta_assert(iter != metadata_.end());
150 const app::TriggerKeyValues & source_kvs =
151 boost::any_cast<app::TriggerKeyValues&>(iter->second);
152
153 std::map<std::string, std::string> dest_kvs;
154 for (const auto & kv : source_kvs) {
155 dest_kvs[kv.first] = kv.second;
156 }
157
158 //Write the map<string,string> to disk
159 ar & dest_kvs;
160 } else {
161 //Read the trigger information from disk, and store
162 //it in our metadata. This map<string,string> is the
163 //same data structure we used when we serialized this
164 //node to disk.
165 std::map<std::string, std::string> source_kvs;
166 ar & source_kvs;
167
168 //The metadata variable's data structure is an unordered_map,
169 //however, so we have to convert the key-value pairs accordingly.
170 //Note that if SPARTA and all downstream users/repos start using a
171 //new enough Boost version, this could be switched to serialize
172 //unordered_map<string,string> directly.
173 //
174 // --> Boost v1.56 and above required <--
175 //
176 //--------------------------------------------------------------
177 app::TriggerKeyValues dest_kvs;
178 for (const auto & kv : source_kvs) {
179 dest_kvs[kv.first] = kv.second;
180 }
181 setMetadataValue("trigger", dest_kvs);
182 }
183 }
184
185 std::shared_ptr<ArchiveController> archive_controller_;
186 utils::ValidValue<size_t> total_num_leaves_;
187 app::NamedExtensions metadata_;
188};
189
190} // namespace statistics
191} // namespace sparta
192
Describes reports to instantiate and tracks their instantiations.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
When a simulation is configured to archive its statistics values, it will build a subset of its devic...
std::vector< std::shared_ptr< ArchiveNode > > children_
There is one of these root node objects at the top of each report's archive. The hierarchy looks like...
void setMetadata(const app::NamedExtensions &metadata)
Metadata.
friend class boost::serialization::access
void setArchiveController(const std::shared_ptr< ArchiveController > &controller)
Macros for handling exponential backoff.