diff --git a/sparta/example/CoreModel/src/ROB.cpp b/sparta/example/CoreModel/src/ROB.cpp index dd2fc1c9f5..30407a8d61 100644 --- a/sparta/example/CoreModel/src/ROB.cpp +++ b/sparta/example/CoreModel/src/ROB.cpp @@ -16,7 +16,15 @@ namespace core_example "ipc", "Instructions retired per cycle", &unit_stat_set_, - "total_number_retired/cycles"), + "total_number_retired/cycles", + { + sparta::StatisticDef::VS_ABSOLUTE, + { + {"low", "0"}, + {"high", std::to_string(uint32_t(p->num_to_retire))}, + {"semantic", "higher"} + } + }), num_retired_(&unit_stat_set_, "total_number_retired", "The total number of instructions retired by this core", diff --git a/sparta/example/SkeletonPipeline/src/Consumer.hpp b/sparta/example/SkeletonPipeline/src/Consumer.hpp index 3077150473..1a43e5bec8 100644 --- a/sparta/example/SkeletonPipeline/src/Consumer.hpp +++ b/sparta/example/SkeletonPipeline/src/Consumer.hpp @@ -55,10 +55,10 @@ class Consumer : public sparta::Unit // Stats sparta::Counter num_consumed_{&unit_stat_set_, "num_consumed", - "Number of items consumed", sparta::Counter::COUNT_NORMAL}; + "Number of items consumed", + sparta::Counter::COUNT_NORMAL}; //! Loggers sparta::log::MessageSource consumer_log_; }; - diff --git a/sparta/sparta/report/format/JSON_detail.hpp b/sparta/sparta/report/format/JSON_detail.hpp index 0e2a0c47f3..159e789027 100644 --- a/sparta/sparta/report/format/JSON_detail.hpp +++ b/sparta/sparta/report/format/JSON_detail.hpp @@ -221,10 +221,7 @@ class JSON_detail : public BaseOstreamFormatter tmp.desc = desc; tmp.vis = si.second->getVisibility(); tmp.n_class = si.second->getClass(); - const StatisticDef * stat_defn = si.second->getStatisticDef(); - if (stat_defn != nullptr) { - tmp.metadata = stat_defn->getMetadata(); - } + tmp.metadata = si.second->getMetadata(); return tmp; }; diff --git a/sparta/sparta/statistics/ContextCounter.hpp b/sparta/sparta/statistics/ContextCounter.hpp index 3abafd5a19..4dce7b47f5 100644 --- a/sparta/sparta/statistics/ContextCounter.hpp +++ b/sparta/sparta/statistics/ContextCounter.hpp @@ -380,8 +380,11 @@ namespace sparta ++sub_stat_index; } - addMetadata_("context_name", context_name); - addMetadata_("num_contexts", std::to_string(num_contexts)); + meta_data_.insert(meta_data_.begin(), + { + {"context_name", context_name}, + {"num_contexts", std::to_string(num_contexts)} + }); begin_counter_ = &internal_counters_.front(); end_counter_ = &internal_counters_.back(); @@ -483,4 +486,3 @@ namespace sparta sparta::trigger::ContextCounterTrigger:: \ registerContextCounterAggregateFcn(handler, this, #method, aggregated_value); \ } - diff --git a/sparta/sparta/statistics/Counter.hpp b/sparta/sparta/statistics/Counter.hpp index 3467ff4a51..b6fedd7a0c 100644 --- a/sparta/sparta/statistics/Counter.hpp +++ b/sparta/sparta/statistics/Counter.hpp @@ -52,7 +52,7 @@ namespace sparta const std::string& group, TreeNode::group_idx_type group_idx, const std::string& desc, - CounterBehavior behave, + CounterBase::CounterBehaviorDetailed behave, visibility_t visibility) : CounterBase(parent, name, @@ -70,7 +70,7 @@ namespace sparta const std::string& group, TreeNode::group_idx_type group_idx, const std::string& desc, - CounterBehavior behave) : + CounterBase::CounterBehaviorDetailed behave) : Counter(parent, name, group, @@ -86,7 +86,7 @@ namespace sparta Counter(TreeNode* parent, const std::string& name, const std::string& desc, - CounterBehavior behave, + CounterBase::CounterBehaviorDetailed behave, visibility_t visibility) : Counter(parent, name, @@ -103,7 +103,7 @@ namespace sparta Counter(TreeNode* parent, const std::string& name, const std::string& desc, - CounterBehavior behave) : + CounterBase::CounterBehaviorDetailed behave) : Counter(parent, name, TreeNode::GROUP_NAME_NONE, @@ -304,4 +304,3 @@ namespace sparta }; } // namespace sparta - diff --git a/sparta/sparta/statistics/CounterBase.hpp b/sparta/sparta/statistics/CounterBase.hpp index a239ad54b5..ac1216f482 100644 --- a/sparta/sparta/statistics/CounterBase.hpp +++ b/sparta/sparta/statistics/CounterBase.hpp @@ -104,6 +104,82 @@ namespace sparta public: + /*! + * \class CounterBehaviorDetailed + * \brief Wrapper class to add meta information to a counter definition + * + * When defining the counter's behavior, this class enables + * the modeler to extend that behavior with meta information. + * During report generation to data serialization formats + * (like json, yaml, or SimDB) this information is included + * with the counter. + * + * Usage: + * \code + * new sparta::Counter(getContainer(), + * "my_counter_name", + * "my_counter_group_name, + * 0, // group idx + * "This is my fancy counter definition", // desc + * // CounterBehaviorDetailed + * { + * sparta::CounterBase::CounterBehavior::COUNT_NORMAL, + * { + * {"lowest_value" : "0" }, + * {"highest_value" : "100" }, + * {"polarity" : "positive" } // Positive polarity, higher is better + * } + * }); + * \endcode + * + * The modeler is not required to provide any meta data + * information. As an example, the following works as well: + * + * \code + * new sparta::Counter(getContainer(), + * "my_counter_name", + * "my_counter_group_name, + * 0, // group idx + * "This is my simple counter definition", // desc + * sparta::CounterBase::CounterBehavior::COUNT_NORMAL); + * \endcode + */ + class CounterBehaviorDetailed + { + public: + /*! + * \brief Construct a CounterBehaviorDetailed without meta data + * \param behavior The CounterBehavior + * \note Do not make this explicit + */ + CounterBehaviorDetailed(CounterBehavior behavior) : + CounterBehaviorDetailed(behavior, {}) + {} + + /*! + * \brief Construct a CounterBehaviorDetailed without meta data + * \param behavior The CounterBehavior + * \param meta_data MetadataPairs to assign `{("name", "value"}}` + */ + CounterBehaviorDetailed(CounterBehavior behavior, + const InstrumentationNode::MetadataPairs & meta_data) : + behavior_(behavior), + meta_data_(meta_data) + {} + + //! Casting operator to obtain the original behavior + operator CounterBehavior() const { return behavior_; } + + //! Get the meta data provided by the user + const InstrumentationNode::MetadataPairs & getMetadata() const { + return meta_data_; + } + + private: + const CounterBehavior behavior_; + const InstrumentationNode::MetadataPairs meta_data_; + }; + //! \name Construction & Initialization //! @{ //////////////////////////////////////////////////////////////////////// @@ -127,7 +203,7 @@ namespace sparta const std::string& group, TreeNode::group_idx_type group_idx, const std::string& desc, - CounterBehavior behave, + CounterBehaviorDetailed behave, visibility_t visibility) : InstrumentationNode(nullptr, name, @@ -144,6 +220,12 @@ namespace sparta ensureParentIsValid_(parent); parent->addChild(this); + + // Copy over the meta data to the InstrumentationNode. + meta_data_.insert(meta_data_.begin(), + behave.getMetadata().begin(), + behave.getMetadata().end()); + } // Alternate constructor @@ -152,7 +234,7 @@ namespace sparta const std::string& group, TreeNode::group_idx_type group_idx, const std::string& desc, - CounterBehavior behave) : + CounterBehaviorDetailed behave) : CounterBase(parent, name, group, @@ -168,7 +250,7 @@ namespace sparta CounterBase(TreeNode* parent, const std::string& name, const std::string& desc, - CounterBehavior behave) : + CounterBehaviorDetailed behave) : CounterBase(parent, name, TreeNode::GROUP_NAME_NONE, @@ -254,7 +336,7 @@ namespace sparta /*! * \brief Returns a string containing the name of the given behavior */ - static std::string getBehaviorName(CounterBehavior behave) { + static std::string getBehaviorName(CounterBehaviorDetailed behave) { switch(behave){ case COUNT_NORMAL: return "normal"; @@ -295,7 +377,7 @@ namespace sparta /*! * \brief Behavior of this counter */ - const CounterBehavior behave_; + const CounterBehaviorDetailed behave_; }; // class CounterBase diff --git a/sparta/sparta/statistics/InstrumentationNode.hpp b/sparta/sparta/statistics/InstrumentationNode.hpp index 1f7c36bfd1..d527ebec6d 100644 --- a/sparta/sparta/statistics/InstrumentationNode.hpp +++ b/sparta/sparta/statistics/InstrumentationNode.hpp @@ -8,6 +8,9 @@ #pragma once +#include +#include + #include "sparta/simulation/TreeNode.hpp" #include "sparta/utils/SpartaException.hpp" #include "sparta/utils/SpartaAssert.hpp" @@ -194,6 +197,14 @@ class InstrumentationNode : public TreeNode }; + //! MetadataPairs are name/value pairs appended to an + //! object/derived type in report generation. This information + //! can be used for communicating relevant information about an + //! InstrumentationNode like value ranges, big numbers good/bad, + //! etc. + using StringPair = std::pair; + using MetadataPairs = std::vector; + //////////////////////////////////////////////////////////////////////// //! @} @@ -220,6 +231,7 @@ class InstrumentationNode : public TreeNode */ InstrumentationNode(InstrumentationNode&& rhp) : TreeNode::TreeNode(std::move(rhp)), + meta_data_(std::move(rhp.meta_data_)), visibility_(rhp.visibility_), class_(rhp.class_), instrument_type_(rhp.instrument_type_) @@ -548,9 +560,8 @@ class InstrumentationNode : public TreeNode return false; } - using StringPair = std::pair; - const std::vector & getMetadata() const { - return metadata_; + const MetadataPairs & getMetadata() const { + return meta_data_; } //////////////////////////////////////////////////////////////////////// @@ -562,9 +573,7 @@ class InstrumentationNode : public TreeNode * \brief Add any arbitrary metadata as strings to this object. Used to * add extra information to statistics reports (json, etc.) */ - void addMetadata_(const std::string & key, const std::string & value){ - metadata_.emplace_back(std::make_pair(key, value)); - } + MetadataPairs meta_data_; private: @@ -582,11 +591,6 @@ class InstrumentationNode : public TreeNode * \brief Type hint for this node */ Type instrument_type_; - - /*! - * \brief - */ - std::vector metadata_; }; } // namespace sparta diff --git a/sparta/sparta/statistics/StatisticDef.hpp b/sparta/sparta/statistics/StatisticDef.hpp index 54581fdaba..b9cb6334a0 100644 --- a/sparta/sparta/statistics/StatisticDef.hpp +++ b/sparta/sparta/statistics/StatisticDef.hpp @@ -27,9 +27,10 @@ namespace sparta { -namespace trigger { -class ContextCounterTrigger; -} // namespace trigger + + namespace trigger { + class ContextCounterTrigger; + } // namespace trigger /*! * \brief Contains a statistic definition (some useful information which can @@ -115,6 +116,86 @@ class ContextCounterTrigger; //VS_UNITS = 4 }; + /*! + * \class ValueSemanticDetailed + * \brief Wrapper class to add meta information to a statistic definition + * + * When defining the ValueSemantic of a StatisticDef, this + * class enables the modeler to extend that semantic with meta + * information. During report generation to data + * serialization formats (like json, yaml, or SimDB) this + * information is included with the statistic. + * + * Usage: + * \code + * new sparta::StatisticDef(getContainer(), + * "my_stat_def_name", + * "my_stat_def_group_name, + * 0, // group idx + * "This is my fancy statistic definition", // desc + * getContainer(), // context + * "(counter1-counter2)/counter2 * 100", // expression + * // ValueSemanticDetailed + * { + * sparta::StatisticDef::ValueSemantic::VS_PERCENTAGE, + * { + * {"lowest_value" : "0" }, + * {"highest_value" : "100" }, + * {"polarity" : "positive" } // Positive polarity, higher is better + * } + * }); + * \endcode + * + * The modeler is not required to provide any meta data + * information. As an example, the following works as well: + * + * \code + * new sparta::StatisticDef(getContainer(), + * "my_stat_def_name", + * "my_stat_def_group_name, + * 0, // group idx + * "This is my simple statistic definition", // desc + * getContainer(), // context + * "(counter1-counter2)/counter2 * 100", // expression + * sparta::StatisticDef::ValueSemantic::VS_PERCENTAGE); // semantic + * \endcode + */ + class ValueSemanticDetailed + { + public: + /*! + * \brief Construct a ValueSemanticDetailed without meta data + * \param semantic The ValueSemantic + * \note Do not make this explicit + */ + ValueSemanticDetailed(ValueSemantic semantic) : + ValueSemanticDetailed(semantic, {}) + {} + + /*! + * \brief Construct a ValueSemanticDetailed without meta data + * \param semantic The ValueSemantic + * \param meta_data MetadataPairs to assign `{("name", "value"}}` + */ + ValueSemanticDetailed(ValueSemantic semantic, + const InstrumentationNode::MetadataPairs & meta_data) : + semantic_(semantic), + meta_data_(meta_data) + {} + + //! Casting operator to obtain the original semantic + operator ValueSemantic() const { return semantic_; } + + //! Get the meta data provided by the user + const InstrumentationNode::MetadataPairs & getMetadata() const { + return meta_data_; + } + + private: + const ValueSemantic semantic_; + const InstrumentationNode::MetadataPairs meta_data_; + }; + //////////////////////////////////////////////////////////////////////// //! @} @@ -138,7 +219,6 @@ class ContextCounterTrigger; expr_str_(rhp.expr_str_), context_(rhp.context_), semantic_(rhp.semantic_) - { // Note: this must happen in leaf type TreeNode* parent = rhp.getParent(); @@ -158,14 +238,14 @@ class ContextCounterTrigger; * * Example: * \code - * StatisticDef s1(parent, "foo0", "foo"m, 0, "The Foo", &stat_set, + * StatisticDef s1(parent, "foo0", "foo", 0, "The Foo", &stat_set, * "ctr_a/ctr_b", - * StatisticSet::VS_ABSOLUTE, - * StatisticSet::VIS_NORMAL); - * StatisticDef s2(parent, "foo0", "foo"m, 0, "The Foo", &stat_set, + * sparta::StatisticDef::VS_ABSOLUTE, + * sparta::StatisticDef::VIS_NORMAL); + * StatisticDef s2(parent, "foo0", "foo", 0, "The Foo", &stat_set, * Expression(5) / Expression(2), - * StatisticSet::VS_ABSOLUTE, - * StatisticSet::VIS_NORMAL); + * sparta::StatisticDef::VS_ABSOLUTE, + * sparta::StatisticDef::VIS_NORMAL); * \endcode */ StatisticDef(TreeNode* parent, @@ -175,7 +255,7 @@ class ContextCounterTrigger; const std::string& desc, TreeNode* context, ExpressionArg expression, - ValueSemantic semantic, + ValueSemanticDetailed semantic, visibility_t visibility) : InstrumentationNode(name, group, @@ -191,7 +271,7 @@ class ContextCounterTrigger; setExpectedParent_(parent); sparta_assert(semantic_ != VS_INVALID, - "Cannot construct a StatisticDef with VS_INVALID value semantic"); + "Cannot construct a StatisticDef with VS_INVALID value semantic"); if(prebuilt_expr_ != nullptr){ expr_str_ = prebuilt_expr_->stringize(); @@ -219,6 +299,11 @@ class ContextCounterTrigger; if(parent){ parent->addChild(this); } + + // Copy over the meta data to the InstrumentationNode. + meta_data_.insert(meta_data_.begin(), + semantic.getMetadata().begin(), + semantic.getMetadata().end()); } /*! @@ -230,7 +315,7 @@ class ContextCounterTrigger; const std::string& desc, TreeNode* context, ExpressionArg expression, - ValueSemantic semantic, + ValueSemanticDetailed semantic, visibility_t visibility) : StatisticDef(nullptr, name, @@ -257,7 +342,7 @@ class ContextCounterTrigger; const std::string& desc, TreeNode* context, ExpressionArg expression, - ValueSemantic semantic, + ValueSemanticDetailed semantic, visibility_t visibility) : StatisticDef(parent, name, @@ -283,7 +368,7 @@ class ContextCounterTrigger; const std::string& desc, TreeNode* context, ExpressionArg expression, - ValueSemantic semantic, + ValueSemanticDetailed semantic, visibility_t visibility) : StatisticDef(nullptr, name, @@ -399,7 +484,7 @@ class ContextCounterTrigger; const std::string& desc, TreeNode* context, ExpressionArg expression, - ValueSemantic semantic) : + ValueSemanticDetailed semantic) : StatisticDef(parent, name, group, @@ -422,7 +507,7 @@ class ContextCounterTrigger; const std::string& desc, TreeNode* context, ExpressionArg expression, - ValueSemantic semantic) : + ValueSemanticDetailed semantic) : StatisticDef(nullptr, name, group, @@ -447,7 +532,7 @@ class ContextCounterTrigger; const std::string& desc, TreeNode* context, ExpressionArg expression, - ValueSemantic semantic) : + ValueSemanticDetailed semantic) : StatisticDef(parent, name, GROUP_NAME_NONE, @@ -471,7 +556,7 @@ class ContextCounterTrigger; const std::string& desc, TreeNode* context, ExpressionArg expression, - ValueSemantic semantic) : + ValueSemanticDetailed semantic) : StatisticDef(nullptr, name, GROUP_NAME_NONE, @@ -629,7 +714,7 @@ class ContextCounterTrigger; //////////////////////////////////////////////////////////////////////// //! @} -private: + private: /*! * \brief Ensures that the parent node is a StatisticSet @@ -650,7 +735,7 @@ class ContextCounterTrigger; sparta::statistics::expression::Expression(expr_str_, context_); }catch(SpartaException &ex){ throw SpartaException("Failed to validate StatisticDef: \"") << getLocation() - << "\": " << ex.what(); + << "\": " << ex.what(); } } } @@ -679,7 +764,7 @@ class ContextCounterTrigger; /*! * \brief Value semantic */ - const ValueSemantic semantic_; + const ValueSemanticDetailed semantic_; /*! * \brief All pending substatistic information (TreeNode* and statistic @@ -704,4 +789,3 @@ class ContextCounterTrigger; }; } // namespace sparta - diff --git a/sparta/sparta/statistics/StatisticInstance.hpp b/sparta/sparta/statistics/StatisticInstance.hpp index 5fe3a9d8cf..0806eb3b65 100644 --- a/sparta/sparta/statistics/StatisticInstance.hpp +++ b/sparta/sparta/statistics/StatisticInstance.hpp @@ -375,6 +375,11 @@ namespace sparta */ InstrumentationNode::class_t getClass() const; + /*! + * \brief Get the meta data associated with this instance + */ + const InstrumentationNode::MetadataPairs & getMetadata() const; + /*! * \brief Returns the StatisticDef used to compute this statistic */ @@ -404,7 +409,7 @@ namespace sparta } /*! - * \Returns the parameter used to compute this statistic + * \returns the parameter used to compute this statistic */ const ParameterBase* getParameter() { return par_; diff --git a/sparta/src/JsonFormatter.cpp b/sparta/src/JsonFormatter.cpp index fbcc166a31..20d8974ede 100644 --- a/sparta/src/JsonFormatter.cpp +++ b/sparta/src/JsonFormatter.cpp @@ -28,411 +28,411 @@ #include "sparta/statistics/StatisticInstance.hpp" namespace sparta { -class CounterBase; -class ParameterBase; - -namespace report { -namespace format { - -rapidjson::Value getReportMetadata( - const std::map & metadata, - rapidjson::Document & doc) -{ - rapidjson::Value metadata_json; - metadata_json.SetObject(); - - for (const auto & md : metadata) { - rapidjson::Value metadata_name_json; - metadata_name_json.SetString( - md.first.c_str(), - md.first.size(), - doc.GetAllocator()); - - rapidjson::Value metadata_value_json; - metadata_value_json.SetString( - md.second.c_str(), - md.second.size(), - doc.GetAllocator()); - - metadata_json.AddMember( - metadata_name_json, - metadata_value_json, - doc.GetAllocator()); - } - - return metadata_json; -} + class CounterBase; + class ParameterBase; + + namespace report { + namespace format { + + rapidjson::Value getReportMetadata( + const std::map & metadata, + rapidjson::Document & doc) + { + rapidjson::Value metadata_json; + metadata_json.SetObject(); + + for (const auto & md : metadata) { + rapidjson::Value metadata_name_json; + metadata_name_json.SetString( + md.first.c_str(), + md.first.size(), + doc.GetAllocator()); + + rapidjson::Value metadata_value_json; + metadata_value_json.SetString( + md.second.c_str(), + md.second.size(), + doc.GetAllocator()); + + metadata_json.AddMember( + metadata_name_json, + metadata_value_json, + doc.GetAllocator()); + } -std::string flattenReportName(std::string full_name) -{ - std::string local_name = full_name; - std::size_t last_dot_idx = full_name.find_last_of("."); - if (last_dot_idx != std::string::npos){ - local_name = full_name.substr(last_dot_idx+1); - } + return metadata_json; + } - return local_name; -} + std::string flattenReportName(std::string full_name) + { + std::string local_name = full_name; + std::size_t last_dot_idx = full_name.find_last_of("."); + if (last_dot_idx != std::string::npos){ + local_name = full_name.substr(last_dot_idx+1); + } -void getTotalNumReports(unsigned int & total_num_reports, - unsigned int & total_num_stats, - const Report * r) -{ - ++total_num_reports; - total_num_stats += r->getStatistics().size(); - for (const Report & sr : r->getSubreports()) { - getTotalNumReports(total_num_reports, total_num_stats, &sr); - } -} + return local_name; + } -//////////////////////// JSON Formatter methods (full) ///////////////////// - -void extractStatisticsJsonFull(rapidjson::Document & doc, - rapidjson::Value & report_json, - const Report * r, - std::vector> & ordered_keys_, - std::vector & statistics_descs_, - std::vector & report_local_names_) -{ - ordered_keys_.push_back({}); - std::vector & ordered_keys_for_report = ordered_keys_.back(); - - rapidjson::Value contents; - contents.SetObject(); - - // Don't write out the complete hierarchical name - // This information is already captured in the nested structure of the dictionary - // XXX: This might cause name collisions if max_report_depth != -1 - std::string local_name = flattenReportName(r->getName()); - - // Keep track of the order in which stats and subunits are written - std::set dont_print_these; - - for (const statistics::stat_pair_t & si : r->getStatistics()) - { - const std::string stat_name = !si.first.empty() ? si.first : si.second->getLocation(); - if (!stat_name.empty()) { - rapidjson::Value stats_json; - stats_json.SetObject(); - - std::string desc = si.second->getDesc(false); - boost::replace_all(desc, "\"", "\\\""); - statistics_descs_.emplace_back(desc); - const std::string & desc_ref = statistics_descs_.back(); - - stats_json.AddMember("desc", rapidjson::StringRef(desc_ref.c_str()), - doc.GetAllocator()); - stats_json.AddMember("vis", rapidjson::Value(si.second->getVisibility()), - doc.GetAllocator()); - - const double val = si.second->getValue(); - if (isnan(val)) { - stats_json.AddMember("val", rapidjson::Value("nan"), doc.GetAllocator()); - } else if (isinf(val)) { - stats_json.AddMember("val", rapidjson::Value("inf"), doc.GetAllocator()); - } else { - double dbl_formatted = 0; - std::stringstream ss; - ss << Report::formatNumber(val); - ss >> dbl_formatted; - - double int_part = 0; - const double remainder = std::modf(dbl_formatted, &int_part); - if (remainder == 0) { - //This double has no remainder, so print it as an integer - stats_json.AddMember("val", rapidjson::Value(static_cast(dbl_formatted)), - doc.GetAllocator()); - } else { - //This double has some remainder, so print it as-is - stats_json.AddMember("val", rapidjson::Value(dbl_formatted), - doc.GetAllocator()); + void getTotalNumReports(unsigned int & total_num_reports, + unsigned int & total_num_stats, + const Report * r) + { + ++total_num_reports; + total_num_stats += r->getStatistics().size(); + for (const Report & sr : r->getSubreports()) { + getTotalNumReports(total_num_reports, total_num_stats, &sr); } } - rapidjson::Value stat_name_json; - stat_name_json.SetString(stat_name.c_str(), stat_name.size(), doc.GetAllocator()); - contents.AddMember(stat_name_json, - stats_json, doc.GetAllocator()); - ordered_keys_for_report.emplace_back(stat_name); - } - } - if (!ordered_keys_for_report.empty()) { - rapidjson::Value keys_array; - keys_array.SetArray(); - for (const auto & key : ordered_keys_for_report) { - keys_array.PushBack(rapidjson::StringRef(key.c_str()), doc.GetAllocator()); - } - contents.AddMember("ordered_keys", keys_array, doc.GetAllocator()); - } + //////////////////////// JSON Formatter methods (full) ///////////////////// + + void extractStatisticsJsonFull(rapidjson::Document & doc, + rapidjson::Value & report_json, + const Report * r, + std::vector> & ordered_keys_, + std::vector & statistics_descs_, + std::vector & report_local_names_) + { + ordered_keys_.push_back({}); + std::vector & ordered_keys_for_report = ordered_keys_.back(); + + rapidjson::Value contents; + contents.SetObject(); + + // Don't write out the complete hierarchical name + // This information is already captured in the nested structure of the dictionary + // XXX: This might cause name collisions if max_report_depth != -1 + std::string local_name = flattenReportName(r->getName()); + + // Keep track of the order in which stats and subunits are written + std::set dont_print_these; + + for (const statistics::stat_pair_t & si : r->getStatistics()) + { + const std::string stat_name = !si.first.empty() ? si.first : si.second->getLocation(); + if (!stat_name.empty()) { + rapidjson::Value stats_json; + stats_json.SetObject(); + + std::string desc = si.second->getDesc(false); + boost::replace_all(desc, "\"", "\\\""); + statistics_descs_.emplace_back(desc); + const std::string & desc_ref = statistics_descs_.back(); + + stats_json.AddMember("desc", rapidjson::StringRef(desc_ref.c_str()), + doc.GetAllocator()); + stats_json.AddMember("vis", rapidjson::Value(si.second->getVisibility()), + doc.GetAllocator()); + + const double val = si.second->getValue(); + if (isnan(val)) { + stats_json.AddMember("val", rapidjson::Value("nan"), doc.GetAllocator()); + } else if (isinf(val)) { + stats_json.AddMember("val", rapidjson::Value("inf"), doc.GetAllocator()); + } else { + double dbl_formatted = 0; + std::stringstream ss; + ss << Report::formatNumber(val); + ss >> dbl_formatted; + + double int_part = 0; + const double remainder = std::modf(dbl_formatted, &int_part); + if (remainder == 0) { + //This double has no remainder, so print it as an integer + stats_json.AddMember("val", rapidjson::Value(static_cast(dbl_formatted)), + doc.GetAllocator()); + } else { + //This double has some remainder, so print it as-is + stats_json.AddMember("val", rapidjson::Value(dbl_formatted), + doc.GetAllocator()); + } + } + rapidjson::Value stat_name_json; + stat_name_json.SetString(stat_name.c_str(), stat_name.size(), doc.GetAllocator()); + contents.AddMember(stat_name_json, + stats_json, doc.GetAllocator()); + ordered_keys_for_report.emplace_back(stat_name); + } + } - report_local_names_.emplace_back(local_name); - const std::string & local_ref = report_local_names_.back(); + if (!ordered_keys_for_report.empty()) { + rapidjson::Value keys_array; + keys_array.SetArray(); + for (const auto & key : ordered_keys_for_report) { + keys_array.PushBack(rapidjson::StringRef(key.c_str()), doc.GetAllocator()); + } + contents.AddMember("ordered_keys", keys_array, doc.GetAllocator()); + } - for (const Report & sr : r->getSubreports()) { - extractStatisticsJsonFull(doc, contents, &sr, ordered_keys_, - statistics_descs_, report_local_names_); - } - report_json.AddMember(rapidjson::StringRef(local_ref.c_str()), - contents, doc.GetAllocator()); -} + report_local_names_.emplace_back(local_name); + const std::string & local_ref = report_local_names_.back(); -void extractVisibilitiesJsonFull(rapidjson::Document & doc) -{ - rapidjson::Value vis_json; - vis_json.SetObject(); - - auto hidden = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_HIDDEN )); - auto support = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_SUPPORT )); - auto detail = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_DETAIL )); - auto normal = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_NORMAL )); - auto summary = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_SUMMARY )); - auto critical = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_CRITICAL )); - - vis_json.AddMember("hidden", hidden, doc.GetAllocator()); - vis_json.AddMember("support", support, doc.GetAllocator()); - vis_json.AddMember("detail", detail, doc.GetAllocator()); - vis_json.AddMember("normal", normal, doc.GetAllocator()); - vis_json.AddMember("summary", summary, doc.GetAllocator()); - vis_json.AddMember("critical", critical, doc.GetAllocator()); - - doc.AddMember("vis", vis_json, doc.GetAllocator()); -} + for (const Report & sr : r->getSubreports()) { + extractStatisticsJsonFull(doc, contents, &sr, ordered_keys_, + statistics_descs_, report_local_names_); + } + report_json.AddMember(rapidjson::StringRef(local_ref.c_str()), + contents, doc.GetAllocator()); + } -void extractSimInfoJsonFull(rapidjson::Document & doc, - rapidjson::Value & siminfo_json, - const std::string & version, - std::vector & local_strings) -{ - local_strings.reserve(5); - local_strings.emplace_back(SimulationInfo::getInstance().sim_name); - local_strings.emplace_back(SimulationInfo::getInstance().simulator_version); - local_strings.emplace_back(SimulationInfo::getInstance().getSpartaVersion()); - local_strings.emplace_back(version); - local_strings.emplace_back(SimulationInfo::getInstance().reproduction_info); - - auto sim_name = rapidjson::StringRef(local_strings[0].c_str()); - auto sim_ver = rapidjson::StringRef(local_strings[1].c_str()); - auto sparta_ver = rapidjson::StringRef(local_strings[2].c_str()); - auto ver = rapidjson::StringRef(local_strings[3].c_str()); - auto repro = rapidjson::StringRef(local_strings[4].c_str()); - - siminfo_json.AddMember("name", sim_name, doc.GetAllocator()); - siminfo_json.AddMember("sim_version", sim_ver, doc.GetAllocator()); - siminfo_json.AddMember("sparta_version", sparta_ver, doc.GetAllocator()); - siminfo_json.AddMember("json_report_version", ver, doc.GetAllocator()); - siminfo_json.AddMember("reproduction", repro, doc.GetAllocator()); -} + void extractVisibilitiesJsonFull(rapidjson::Document & doc) + { + rapidjson::Value vis_json; + vis_json.SetObject(); + + auto hidden = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_HIDDEN )); + auto support = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_SUPPORT )); + auto detail = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_DETAIL )); + auto normal = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_NORMAL )); + auto summary = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_SUMMARY )); + auto critical = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_CRITICAL )); + + vis_json.AddMember("hidden", hidden, doc.GetAllocator()); + vis_json.AddMember("support", support, doc.GetAllocator()); + vis_json.AddMember("detail", detail, doc.GetAllocator()); + vis_json.AddMember("normal", normal, doc.GetAllocator()); + vis_json.AddMember("summary", summary, doc.GetAllocator()); + vis_json.AddMember("critical", critical, doc.GetAllocator()); + + doc.AddMember("vis", vis_json, doc.GetAllocator()); + } -void JSON::writeContentToStream_(std::ostream & out) const -{ - unsigned int total_num_reports = 0; - unsigned int total_num_stats = 0; - getTotalNumReports(total_num_reports, total_num_stats, report_); - report_local_names_.reserve(total_num_reports); - statistics_descs_.reserve(total_num_stats); - ordered_keys_.reserve(total_num_reports); - - rapidjson::Document doc; - doc.SetObject(); - - rapidjson::Value stats_json; - stats_json.SetObject(); - extractStatisticsJsonFull(doc, stats_json, report_, ordered_keys_, - statistics_descs_, report_local_names_); - doc.AddMember("Statistics", stats_json, doc.GetAllocator()); - - extractVisibilitiesJsonFull(doc); - - rapidjson::Value siminfo_json; - siminfo_json.SetObject(); - std::vector local_strings; - extractSimInfoJsonFull(doc, siminfo_json, getVersion(), local_strings); - doc.AddMember("siminfo", siminfo_json, doc.GetAllocator()); - - rapidjson::Value report_metadata_json = getReportMetadata(metadata_kv_pairs_, doc); - doc.AddMember("report_metadata", report_metadata_json, doc.GetAllocator()); - - rapidjson::StringBuffer buffer; - rapidjson::PrettyWriter writer(buffer); - doc.Accept(writer); - - if (prettyPrintEnabled()) { - out << buffer.GetString(); - } else { - std::stringstream no_pretty_print_ss; - no_pretty_print_ss << buffer.GetString(); - - std::string line; - while (std::getline(no_pretty_print_ss, line)) { - boost::trim_left(line); - out << line << "\n"; - } - } -} + void extractSimInfoJsonFull(rapidjson::Document & doc, + rapidjson::Value & siminfo_json, + const std::string & version, + std::vector & local_strings) + { + local_strings.reserve(5); + local_strings.emplace_back(SimulationInfo::getInstance().sim_name); + local_strings.emplace_back(SimulationInfo::getInstance().simulator_version); + local_strings.emplace_back(SimulationInfo::getInstance().getSpartaVersion()); + local_strings.emplace_back(version); + local_strings.emplace_back(SimulationInfo::getInstance().reproduction_info); + + auto sim_name = rapidjson::StringRef(local_strings[0].c_str()); + auto sim_ver = rapidjson::StringRef(local_strings[1].c_str()); + auto sparta_ver = rapidjson::StringRef(local_strings[2].c_str()); + auto ver = rapidjson::StringRef(local_strings[3].c_str()); + auto repro = rapidjson::StringRef(local_strings[4].c_str()); + + siminfo_json.AddMember("name", sim_name, doc.GetAllocator()); + siminfo_json.AddMember("sim_version", sim_ver, doc.GetAllocator()); + siminfo_json.AddMember("sparta_version", sparta_ver, doc.GetAllocator()); + siminfo_json.AddMember("json_report_version", ver, doc.GetAllocator()); + siminfo_json.AddMember("reproduction", repro, doc.GetAllocator()); + } -//////////////////////// JSON Formatter methods (reduced) ////////////////// + void JSON::writeContentToStream_(std::ostream & out) const + { + unsigned int total_num_reports = 0; + unsigned int total_num_stats = 0; + getTotalNumReports(total_num_reports, total_num_stats, report_); + report_local_names_.reserve(total_num_reports); + statistics_descs_.reserve(total_num_stats); + ordered_keys_.reserve(total_num_reports); + + rapidjson::Document doc; + doc.SetObject(); + + rapidjson::Value stats_json; + stats_json.SetObject(); + extractStatisticsJsonFull(doc, stats_json, report_, ordered_keys_, + statistics_descs_, report_local_names_); + doc.AddMember("Statistics", stats_json, doc.GetAllocator()); + + extractVisibilitiesJsonFull(doc); + + rapidjson::Value siminfo_json; + siminfo_json.SetObject(); + std::vector local_strings; + extractSimInfoJsonFull(doc, siminfo_json, getVersion(), local_strings); + doc.AddMember("siminfo", siminfo_json, doc.GetAllocator()); + + rapidjson::Value report_metadata_json = getReportMetadata(metadata_kv_pairs_, doc); + doc.AddMember("report_metadata", report_metadata_json, doc.GetAllocator()); + + rapidjson::StringBuffer buffer; + rapidjson::PrettyWriter writer(buffer); + doc.Accept(writer); + + if (prettyPrintEnabled()) { + out << buffer.GetString(); + } else { + std::stringstream no_pretty_print_ss; + no_pretty_print_ss << buffer.GetString(); + + std::string line; + while (std::getline(no_pretty_print_ss, line)) { + boost::trim_left(line); + out << line << "\n"; + } + } + } -void extractVisibilitiesJsonReduced(rapidjson::Document & doc) -{ - rapidjson::Value vis_json; - vis_json.SetObject(); + //////////////////////// JSON Formatter methods (reduced) ////////////////// - auto hidden = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_HIDDEN )); - auto support = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_SUPPORT )); - auto detail = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_DETAIL )); - auto normal = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_NORMAL )); - auto summary = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_SUMMARY )); - auto critical = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_CRITICAL )); + void extractVisibilitiesJsonReduced(rapidjson::Document & doc) + { + rapidjson::Value vis_json; + vis_json.SetObject(); - vis_json.AddMember("hidden", hidden, doc.GetAllocator()); - vis_json.AddMember("support", support, doc.GetAllocator()); - vis_json.AddMember("detail", detail, doc.GetAllocator()); - vis_json.AddMember("normal", normal, doc.GetAllocator()); - vis_json.AddMember("summary", summary, doc.GetAllocator()); - vis_json.AddMember("critical", critical, doc.GetAllocator()); + auto hidden = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_HIDDEN )); + auto support = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_SUPPORT )); + auto detail = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_DETAIL )); + auto normal = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_NORMAL )); + auto summary = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_SUMMARY )); + auto critical = rapidjson::Value( static_cast(sparta::InstrumentationNode::VIS_CRITICAL )); - doc.AddMember("vis", vis_json, doc.GetAllocator()); -} + vis_json.AddMember("hidden", hidden, doc.GetAllocator()); + vis_json.AddMember("support", support, doc.GetAllocator()); + vis_json.AddMember("detail", detail, doc.GetAllocator()); + vis_json.AddMember("normal", normal, doc.GetAllocator()); + vis_json.AddMember("summary", summary, doc.GetAllocator()); + vis_json.AddMember("critical", critical, doc.GetAllocator()); -void extractSimInfoJsonReduced(rapidjson::Document & doc, - rapidjson::Value & siminfo_json, - const std::string & version, - std::vector & local_strings) -{ - local_strings.reserve(5); - local_strings.emplace_back(SimulationInfo::getInstance().sim_name); - local_strings.emplace_back(SimulationInfo::getInstance().simulator_version); - local_strings.emplace_back(SimulationInfo::getInstance().getSpartaVersion()); - local_strings.emplace_back(version); - local_strings.emplace_back(SimulationInfo::getInstance().reproduction_info); - - auto sim_name = rapidjson::StringRef(local_strings[0].c_str()); - auto sim_ver = rapidjson::StringRef(local_strings[1].c_str()); - auto sparta_ver = rapidjson::StringRef(local_strings[2].c_str()); - auto ver = rapidjson::StringRef(local_strings[3].c_str()); - auto repro = rapidjson::StringRef(local_strings[4].c_str()); - - siminfo_json.AddMember("name", sim_name, doc.GetAllocator()); - siminfo_json.AddMember("sim_version", sim_ver, doc.GetAllocator()); - siminfo_json.AddMember("sparta_version", sparta_ver, doc.GetAllocator()); - siminfo_json.AddMember("json_report_version", ver, doc.GetAllocator()); - siminfo_json.AddMember("reproduction", repro, doc.GetAllocator()); -} + doc.AddMember("vis", vis_json, doc.GetAllocator()); + } -void extractStatisticsJsonReduced(rapidjson::Document & doc, - rapidjson::Value & report_json, - const Report * r, - std::vector & report_local_names_, - const bool omit_zero_values) -{ - rapidjson::Value contents; - contents.SetObject(); - - // Don't write out the complete hierarchical name - // This information is already captured in the nested structure of the dictionary - // XXX: This might cause name collisions if max_report_depth != -1 - std::string local_name = flattenReportName(r->getName()); - - // Keep track of the order in which stats and subunits are written - std::set dont_print_these; - - for (const statistics::stat_pair_t & si : r->getStatistics()) { - const std::string stat_name = !si.first.empty() ? si.first : si.second->getLocation(); - if (!stat_name.empty()) { - const double val = si.second->getValue(); - if (omit_zero_values && val == 0) { - continue; + void extractSimInfoJsonReduced(rapidjson::Document & doc, + rapidjson::Value & siminfo_json, + const std::string & version, + std::vector & local_strings) + { + local_strings.reserve(5); + local_strings.emplace_back(SimulationInfo::getInstance().sim_name); + local_strings.emplace_back(SimulationInfo::getInstance().simulator_version); + local_strings.emplace_back(SimulationInfo::getInstance().getSpartaVersion()); + local_strings.emplace_back(version); + local_strings.emplace_back(SimulationInfo::getInstance().reproduction_info); + + auto sim_name = rapidjson::StringRef(local_strings[0].c_str()); + auto sim_ver = rapidjson::StringRef(local_strings[1].c_str()); + auto sparta_ver = rapidjson::StringRef(local_strings[2].c_str()); + auto ver = rapidjson::StringRef(local_strings[3].c_str()); + auto repro = rapidjson::StringRef(local_strings[4].c_str()); + + siminfo_json.AddMember("name", sim_name, doc.GetAllocator()); + siminfo_json.AddMember("sim_version", sim_ver, doc.GetAllocator()); + siminfo_json.AddMember("sparta_version", sparta_ver, doc.GetAllocator()); + siminfo_json.AddMember("json_report_version", ver, doc.GetAllocator()); + siminfo_json.AddMember("reproduction", repro, doc.GetAllocator()); } - rapidjson::Value stat_name_json; - stat_name_json.SetString(stat_name.c_str(), stat_name.size(), doc.GetAllocator()); - if (isnan(val)) { - contents.AddMember(stat_name_json, - rapidjson::Value("nan"), - doc.GetAllocator()); - } else if(isinf(val)) { - contents.AddMember(stat_name_json, - rapidjson::Value("inf"), - doc.GetAllocator()); - } else { - double dbl_formatted = 0; - std::stringstream ss; - ss << Report::formatNumber(val); - ss >> dbl_formatted; - - double int_part = 0; - const double remainder = std::modf(dbl_formatted, &int_part); - if (remainder == 0) { - //This double has no remainder, so print it as an integer - contents.AddMember(stat_name_json, - rapidjson::Value(static_cast(dbl_formatted)), - doc.GetAllocator()); - } else { - //This double has some remainder, so print it as-is - contents.AddMember(stat_name_json, - rapidjson::Value(dbl_formatted), - doc.GetAllocator()); + + void extractStatisticsJsonReduced(rapidjson::Document & doc, + rapidjson::Value & report_json, + const Report * r, + std::vector & report_local_names_, + const bool omit_zero_values) + { + rapidjson::Value contents; + contents.SetObject(); + + // Don't write out the complete hierarchical name + // This information is already captured in the nested structure of the dictionary + // XXX: This might cause name collisions if max_report_depth != -1 + std::string local_name = flattenReportName(r->getName()); + + // Keep track of the order in which stats and subunits are written + std::set dont_print_these; + + for (const statistics::stat_pair_t & si : r->getStatistics()) { + const std::string stat_name = !si.first.empty() ? si.first : si.second->getLocation(); + if (!stat_name.empty()) { + const double val = si.second->getValue(); + if (omit_zero_values && val == 0) { + continue; + } + rapidjson::Value stat_name_json; + stat_name_json.SetString(stat_name.c_str(), stat_name.size(), doc.GetAllocator()); + if (isnan(val)) { + contents.AddMember(stat_name_json, + rapidjson::Value("nan"), + doc.GetAllocator()); + } else if(isinf(val)) { + contents.AddMember(stat_name_json, + rapidjson::Value("inf"), + doc.GetAllocator()); + } else { + double dbl_formatted = 0; + std::stringstream ss; + ss << Report::formatNumber(val); + ss >> dbl_formatted; + + double int_part = 0; + const double remainder = std::modf(dbl_formatted, &int_part); + if (remainder == 0) { + //This double has no remainder, so print it as an integer + contents.AddMember(stat_name_json, + rapidjson::Value(static_cast(dbl_formatted)), + doc.GetAllocator()); + } else { + //This double has some remainder, so print it as-is + contents.AddMember(stat_name_json, + rapidjson::Value(dbl_formatted), + doc.GetAllocator()); + } + } + } + } + + report_local_names_.emplace_back(local_name); + const std::string & local_ref = report_local_names_.back(); + + for (const Report & sr : r->getSubreports()) { + extractStatisticsJsonReduced(doc, contents, &sr, report_local_names_, + omit_zero_values); } + report_json.AddMember(rapidjson::StringRef(local_ref.c_str()), + contents, doc.GetAllocator()); } - } - } - report_local_names_.emplace_back(local_name); - const std::string & local_ref = report_local_names_.back(); + void JSON_reduced::writeContentToStream_(std::ostream & out) const + { + unsigned int total_num_reports = 0; + unsigned int unused_var = 0; + getTotalNumReports(total_num_reports, unused_var, report_); + report_local_names_.reserve(total_num_reports); - for (const Report & sr : r->getSubreports()) { - extractStatisticsJsonReduced(doc, contents, &sr, report_local_names_, - omit_zero_values); - } - report_json.AddMember(rapidjson::StringRef(local_ref.c_str()), - contents, doc.GetAllocator()); -} + rapidjson::Document doc; + doc.SetObject(); + + rapidjson::Value stats_json; + stats_json.SetObject(); + const bool omit_zero_values = statsWithValueZeroAreOmitted(); + extractStatisticsJsonReduced(doc, stats_json, report_, report_local_names_, + omit_zero_values); + doc.AddMember("Statistics", stats_json, doc.GetAllocator()); + + extractVisibilitiesJsonReduced(doc); + + rapidjson::Value siminfo_json; + siminfo_json.SetObject(); + std::vector local_strings; + extractSimInfoJsonReduced(doc, siminfo_json, getVersion(), local_strings); + doc.AddMember("siminfo", siminfo_json, doc.GetAllocator()); + + rapidjson::Value report_metadata_json = getReportMetadata(metadata_kv_pairs_, doc); + doc.AddMember("report_metadata", report_metadata_json, doc.GetAllocator()); + + rapidjson::StringBuffer buffer; + rapidjson::PrettyWriter writer(buffer); + doc.Accept(writer); + + if (prettyPrintEnabled()) { + out << buffer.GetString(); + } else { + std::stringstream no_pretty_print_ss; + no_pretty_print_ss << buffer.GetString(); + + std::string line; + while (std::getline(no_pretty_print_ss, line)) { + boost::trim_left(line); + out << line << "\n"; + } + } + } -void JSON_reduced::writeContentToStream_(std::ostream & out) const -{ - unsigned int total_num_reports = 0; - unsigned int unused_var = 0; - getTotalNumReports(total_num_reports, unused_var, report_); - report_local_names_.reserve(total_num_reports); - - rapidjson::Document doc; - doc.SetObject(); - - rapidjson::Value stats_json; - stats_json.SetObject(); - const bool omit_zero_values = statsWithValueZeroAreOmitted(); - extractStatisticsJsonReduced(doc, stats_json, report_, report_local_names_, - omit_zero_values); - doc.AddMember("Statistics", stats_json, doc.GetAllocator()); - - extractVisibilitiesJsonReduced(doc); - - rapidjson::Value siminfo_json; - siminfo_json.SetObject(); - std::vector local_strings; - extractSimInfoJsonReduced(doc, siminfo_json, getVersion(), local_strings); - doc.AddMember("siminfo", siminfo_json, doc.GetAllocator()); - - rapidjson::Value report_metadata_json = getReportMetadata(metadata_kv_pairs_, doc); - doc.AddMember("report_metadata", report_metadata_json, doc.GetAllocator()); - - rapidjson::StringBuffer buffer; - rapidjson::PrettyWriter writer(buffer); - doc.Accept(writer); - - if (prettyPrintEnabled()) { - out << buffer.GetString(); - } else { - std::stringstream no_pretty_print_ss; - no_pretty_print_ss << buffer.GetString(); - - std::string line; - while (std::getline(no_pretty_print_ss, line)) { - boost::trim_left(line); - out << line << "\n"; } } } - -} -} -} diff --git a/sparta/src/ReportStatsCollector.cpp b/sparta/src/ReportStatsCollector.cpp index 731e940b2a..f82ab642d0 100644 --- a/sparta/src/ReportStatsCollector.cpp +++ b/sparta/src/ReportStatsCollector.cpp @@ -462,33 +462,34 @@ void ReportStatsCollector::writeReportInfo_( } const auto& stats = r->getStatistics(); - for (const auto& si : stats) { - const auto& si_name = si.first; + for (const auto& si : stats) + { const auto si_loc = si.second->getLocation(); - const auto si_desc = si.second->getDesc(false); - const auto si_vis = static_cast(si.second->getVisibility()); - const auto si_class = static_cast(si.second->getClass()); - if (!visited_stats.insert(si_loc).second) { continue; } + const auto& si_name = si.first; + const auto si_desc = si.second->getDesc(false); + const auto si_vis = static_cast(si.second->getVisibility()); + const auto si_class = static_cast(si.second->getClass()); + const auto si_meta = si.second->getMetadata(); + auto si_record = db_mgr_->INSERT( SQL_TABLE("StatisticInsts"), SQL_COLUMNS("ReportID", "StatisticName", "StatisticLoc", "StatisticDesc", "StatisticVis", "StatisticClass"), SQL_VALUES(report_id, si_name, si_loc, si_desc, si_vis, si_class)); - if (auto stat_def = si.second->getStatisticDef()) { - const auto si_id = si_record->getId(); - for (const auto& pair : stat_def->getMetadata()) { - const auto& meta_name = pair.first; - const auto& meta_value = pair.second; + const auto si_id = si_record->getId(); + for (const auto& pair : si_meta) + { + const auto& meta_name = pair.first; + const auto& meta_value = pair.second; - db_mgr_->INSERT( - SQL_TABLE("StatisticDefnMetadata"), - SQL_COLUMNS("StatisticInstID", "MetaName", "MetaValue"), - SQL_VALUES(si_id, meta_name, meta_value)); - } + db_mgr_->INSERT( + SQL_TABLE("StatisticDefnMetadata"), + SQL_COLUMNS("StatisticInstID", "MetaName", "MetaValue"), + SQL_VALUES(si_id, meta_name, meta_value)); } simdb_stats_[desc].push_back(si.second.get()); @@ -510,7 +511,7 @@ void ReportStatsCollector::writeReportInfo_( } break; - } + } } for (const auto& sr : r->getSubreports()) { diff --git a/sparta/src/StatisticInstance.cpp b/sparta/src/StatisticInstance.cpp index fc32857fb4..1a14a723bb 100644 --- a/sparta/src/StatisticInstance.cpp +++ b/sparta/src/StatisticInstance.cpp @@ -498,6 +498,21 @@ namespace sparta return InstrumentationNode::DEFAULT_CLASS; } + const InstrumentationNode::MetadataPairs & StatisticInstance::getMetadata() const + { + static const InstrumentationNode::MetadataPairs no_pairs; + + if(sdef_) { + return sdef_->getMetadata(); + } + + if(ctr_) { + return ctr_->getMetadata(); + } + + return no_pairs; + } + void StatisticInstance::getClocks(std::vector& clocks) const { if(sdef_){ if(node_ref_.expired() == true){ diff --git a/sparta/test/Report/Report_test.cpp b/sparta/test/Report/Report_test.cpp index 2588306232..cd0e62d8d1 100644 --- a/sparta/test/Report/Report_test.cpp +++ b/sparta/test/Report/Report_test.cpp @@ -10,6 +10,7 @@ #include "sparta/report/format/BasicHTML.hpp" #include "sparta/report/format/Text.hpp" #include "sparta/report/format/Gnuplot.hpp" +#include "sparta/report/format/JSON_detail.hpp" #include "sparta/kernel/Scheduler.hpp" #include "sparta/statistics/Counter.hpp" #include "sparta/statistics/ReadOnlyCounter.hpp" @@ -329,13 +330,29 @@ int main() // Ok StatisticDefs in tree StatisticDef sd1(&sset0, "s1", "Statistic Description", &sset0, "c1", StatisticDef::VS_PERCENTAGE); StatisticDef sd2(&sset0, "s2", "Statistic Description", &sset0, "c2", StatisticDef::VS_FRACTIONAL); - StatisticDef sd3(&sset0, "s3", "Statistic Description", &core0, "stats.c3/stats.s4", StatisticDef::VS_ABSOLUTE); // Stat-reference + StatisticDef sd3(&sset0, "s3", "Statistic Description", &core0, "stats.c3/stats.s4", + { + StatisticDef::VS_ABSOLUTE, + { + {"range", "0:100" }, + {"semantic", "higher" } + } + } + ); // Stat-reference with meta data StatisticDef sd4(&sset0, "s4", "Statistic Description", &sset0, "log2(16)/4+c3**c4"); // Expression on counters TreeNode dummy(&core0, "dummy", "Dummy node fore testing subtree-depth limits"); StatisticSet sset_dummy(&dummy); Counter dummy_c1(&sset_dummy, "c1", "Counter 1 in dummy", Counter::COUNT_NORMAL, Counter::VIS_SUMMARY); - Counter dummy_c2(&sset_dummy, "c2", "Counter 2 in dummy", Counter::COUNT_NORMAL, Counter::VIS_NORMAL); + Counter dummy_c2(&sset_dummy, "c2", "Counter 2 in dummy", + { + Counter::COUNT_NORMAL, + { + {"range", "0:100000000"}, + {"semantic", "lower"}, + } + }, + Counter::VIS_NORMAL); // Invalid StatisticDefs EXPECT_THROW(StatisticDef sd5(&sset0, "s5", "Statistic Description", &sset0, "1", StatisticDef::VS_INVALID)); @@ -348,7 +365,6 @@ int main() EXPECT_EQUAL(c3.getVisibility(), sparta::InstrumentationNode::VIS_HIDDEN); EXPECT_EQUAL(c4.getVisibility(), sparta::InstrumentationNode::VIS_NORMAL); - // Finalization root.enterConfiguring(); @@ -679,6 +695,10 @@ R"(name: "String-based report Autopopulation Test" txt_9.setShowSimInfo(false); std::ofstream("test_autopopulate_multi_nested.txt", std::ios::out) << txt_9; + // Write a json-detailed report to ensure meta data is included + sparta::report::format::JSON_detail json_det_10(&r9); + std::ofstream("test_json_detailed_with_meta.json", std::ios::out) << json_det_10; + // Check output files EXPECT_FILES_EQUAL("test_report_out", "test_report_out.EXPECTED"); @@ -695,7 +715,8 @@ R"(name: "String-based report Autopopulation Test" EXPECT_FILES_EQUAL("test_autopopulate_from_string.html", "test_autopopulate_from_string.html.EXPECTED"); EXPECT_FILES_EQUAL("test_autopopulate_multireport.txt", "test_autopopulate_multireport.txt.EXPECTED"); EXPECT_FILES_EQUAL("test_autopopulate_multi_nested.txt", "test_autopopulate_multi_nested.txt.EXPECTED"); - EXPECT_FILES_EQUAL("test_periodic.csv", "test_periodic.csv.EXPECTED") + EXPECT_FILES_EQUAL("test_periodic.csv", "test_periodic.csv.EXPECTED"); + EXPECT_FILES_EQUAL("test_json_detailed_with_meta.json", "test_json_detailed_with_meta.json.EXPECTED"); // Print out some info about the report std::cout << "Context : " << report.getContext() << std::endl; diff --git a/sparta/test/Report/test_json_detailed_with_meta.json.EXPECTED b/sparta/test/Report/test_json_detailed_with_meta.json.EXPECTED new file mode 100644 index 0000000000..7b73165741 --- /dev/null +++ b/sparta/test/Report/test_json_detailed_with_meta.json.EXPECTED @@ -0,0 +1,110 @@ +{ "_id": " ", + "report_metadata": {}, + "stat_info": { + "c1": [ + { "name": "Report X.core0.c1", + "desc": "Counter 1 (NORMAL VIS)", + "vis": "100000000", + "class": "50" + }, + { "name": "Report X.core0.dummy.c1", + "desc": "Counter 1 in dummy", + "vis": "200000000", + "class": "50" + }, + { "name": "Report X.core1.c1", + "desc": "Counter 1", + "vis": "100000000", + "class": "50" + } + ], + "c2": [ + { "name": "Report X.core0.c2", + "desc": "Counter 2 (SUMMARY VIS)", + "vis": "200000000", + "class": "50" + }, + { "name": "Report X.core0.dummy.c2", + "desc": "Counter 2 in dummy", + "vis": "100000000", + "class": "50", + "range": "0:100000000", + "semantic": "lower" + }, + { "name": "Report X.core1.c2", + "desc": "Counter 2", + "vis": "100000000", + "class": "50" + } + ], + "c3": [ + { "name": "Report X.core0.c3", + "desc": "Counter 3 (HIDDEN VIS)", + "vis": "0", + "class": "50" + }, + { "name": "Report X.core1.c3", + "desc": "Counter 3", + "vis": "100000000", + "class": "50" + } + ], + "c4": [ + { "name": "Report X.core0.c4", + "desc": "Counter 4 (NORMAL VIS)", + "vis": "100000000", + "class": "50" + }, + { "name": "Report X.core1.c4", + "desc": "Counter 4", + "vis": "100000000", + "class": "50" + } + ], + "c5": [ + { "name": "Report X.core0.c5", + "desc": "Counter 5 (NORMAL VIS)", + "vis": "100000000", + "class": "50" + } + ], + "s1": [ + { "name": "Report X.core0.s1", + "desc": "Statistic Description", + "vis": "100000000", + "class": "50" + } + ], + "s2": [ + { "name": "Report X.core0.s2", + "desc": "Statistic Description", + "vis": "100000000", + "class": "50" + } + ], + "s3": [ + { "name": "Report X.core0.s3", + "desc": "Statistic Description", + "vis": "100000000", + "class": "50", + "range": "0:100", + "semantic": "higher" + } + ], + "s4": [ + { "name": "Report X.core0.s4", + "desc": "Statistic Description", + "vis": "100000000", + "class": "50" + } + ], + "s5": [ + { "name": "Report X.core0.s5", + "desc": "Statistic Description", + "vis": "100000000", + "class": "50" + } + ] + } +} +