diff --git a/src/sst/core/Makefile.am b/src/sst/core/Makefile.am index 022ee74ce..852a2120d 100644 --- a/src/sst/core/Makefile.am +++ b/src/sst/core/Makefile.am @@ -30,10 +30,6 @@ nobase_dist_sst_HEADERS = \ configShared.h \ configGraph.h \ configGraphOutput.h \ - cfgoutput/pythonConfigOutput.h \ - cfgoutput/dotConfigOutput.h \ - cfgoutput/xmlConfigOutput.h \ - cfgoutput/jsonConfigOutput.h \ decimal_fixedpoint.h \ env/envquery.h \ env/envconfig.h \ @@ -162,8 +158,7 @@ nobase_dist_sst_HEADERS = \ statapi/statnull.h \ threadsafe.h \ cputimer.h \ - warnmacros.h \ - model/element_python.h + warnmacros.h deprecated_nobase_dist_sst_headers = @@ -185,12 +180,7 @@ sst_core_sources = \ configBase.cc \ configBaseSer.cc \ configShared.cc \ - configGraph.cc \ configGraphOutput.cc \ - cfgoutput/pythonConfigOutput.cc \ - cfgoutput/dotConfigOutput.cc \ - cfgoutput/xmlConfigOutput.cc \ - cfgoutput/jsonConfigOutput.cc \ env/envquery.cc \ env/envconfig.cc \ eli/elibase.cc \ diff --git a/src/sst/core/baseComponent.cc b/src/sst/core/baseComponent.cc index 7e35650a0..954e9c5e5 100644 --- a/src/sst/core/baseComponent.cc +++ b/src/sst/core/baseComponent.cc @@ -14,10 +14,10 @@ #include "sst/core/baseComponent.h" #include "sst/core/component.h" -#include "sst/core/configGraph.h" #include "sst/core/factory.h" #include "sst/core/link.h" #include "sst/core/linkMap.h" +#include "sst/core/model/configGraph.h" #include "sst/core/portModule.h" #include "sst/core/profile/clockHandlerProfileTool.h" #include "sst/core/profile/eventHandlerProfileTool.h" diff --git a/src/sst/core/componentInfo.cc b/src/sst/core/componentInfo.cc index 8302cf1db..a0e8d6374 100644 --- a/src/sst/core/componentInfo.cc +++ b/src/sst/core/componentInfo.cc @@ -13,8 +13,8 @@ #include "sst/core/componentInfo.h" -#include "sst/core/configGraph.h" #include "sst/core/linkMap.h" +#include "sst/core/model/configGraph.h" #include "sst/core/serialization/serialize.h" #include "sst/core/serialization/serializer.h" diff --git a/src/sst/core/configGraph.h b/src/sst/core/configGraph.h index e33f447ab..f9eebd8ce 100644 --- a/src/sst/core/configGraph.h +++ b/src/sst/core/configGraph.h @@ -14,888 +14,9 @@ #ifndef SST_CORE_CONFIGGRAPH_H #define SST_CORE_CONFIGGRAPH_H -#include "sst/core/params.h" -#include "sst/core/rankInfo.h" -#include "sst/core/serialization/serializable.h" -#include "sst/core/sparseVectorMap.h" -#include "sst/core/sst_types.h" -#include "sst/core/statapi/statbase.h" -#include "sst/core/statapi/statoutput.h" -#include "sst/core/timeConverter.h" -#include "sst/core/unitAlgebra.h" +#warning \ + "sst/core/configGraph.h has been moved to sst/core/model/configGraph.h. sst/core/confgGraph.h will be removed in SST 16." -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace SST::Statistics; - -namespace SST { - -class Simulation_impl; - -class Config; -class TimeLord; -class ConfigGraph; - -using ComponentIdMap_t = SparseVectorMap; -using LinkIdMap_t = std::vector; - -/** Represents the configuration of a generic Link */ -class ConfigLink -{ - // Static data structures to map latency string to an index that - // will hold the SimTime_t for the latency once the atomic - // timebase has been set. - static std::map lat_to_index; - - static uint32_t getIndexForLatency(const char* latency); - static std::vector initializeLinkLatencyVector(); - SimTime_t getLatencyFromIndex(uint32_t index); - -public: - /** - Components that are connected to this link. They are filled in - the order they are attached in. If the link is marked as - non-local, then component[1] holds the rank of the remote - component. - */ - ComponentId_t component[2] = { 0, 0 }; /*!< IDs of the connected components */ - - /** - This is a dual purpose data member. - - Graph construction - during graph construction, it holds the - index into the LinkLatencyVector, which maps the stored index - to the actual latency string. This is done to reduce memory - usage because we assume there will be a small number of - different latencies specified. - - Post graph construction - after graph construction, the latency - index is replaced with the SimTime_t value representing the - specified latency that will be used by the link to add the - specified latency to the event. - - In both cases, the indices match the indices found in the - component array, and represent the latency of the link for - events sent from the corresponding component. - - If the link is marked as non-local, then latency[1] holds the - thread of the remote component. - */ - SimTime_t latency[2] = { 0, 0 }; - - /** - Name of the link. This is used in three cases: - - Errors - if an error is found in the graph construction, the - name is used to report the error to the user - - Link ordering - the event ordering for links is based on the - alphabetized name of the links. The links are sorted by name - and order is assigned linearly starting at 1 - - Parallel load - for parallel load, links that cross partition - boundaries are connected by matching link names - */ - std::string name; - - /** - id of the link. This is used primarily to find the link in - ConfigGraph::links - */ - LinkId_t id = 0; - - /** - This is a dual purpose data member. During graph construction, - it counts the number of components currently referencing this - link. After graph construction, it is assigned the value used - to enforce ordering of events based on the links they were sent - on. - - @see Activity::setOrderTag, Link::tag - */ - LinkId_t order = 0; - - /** - Name of the ports the link is connected to. The indices match - the ones used in the component array - */ - std::string port[2]; - - /** - Whether or not this link is set to be no-cut - */ - bool no_cut = false; - - /** - Whether this link crosses the graph boundary and is connected - on one end to a non-local component. If set to true, there - will only be one component connected (information in index 0 - for the arrays) and the rank for the remote component will be - stored in component[1] and the thread in latency[1]. - */ - bool nonlocal = false; - - /** - Set to true if this is a cross rank link - */ - bool cross_rank = false; - - /** - Set to true if this is a cross thread link on same rank - */ - bool cross_thread = false; - - inline LinkId_t key() const { return id; } - - /** Return the minimum latency of this link (from both sides) */ - SimTime_t getMinLatency() const - { - if ( nonlocal ) return latency[0]; - if ( latency[0] < latency[1] ) return latency[0]; - return latency[1]; - } - - std::string latency_str(uint32_t index) const; - - /** - Sets the link as a non-local link. - - @param which_local specifies which index is for the local side - of the link - - @param remote_rank_info Rank of the remote side of the link - - */ - void setAsNonLocal(int which_local, RankInfo remote_rank_info); - - /** Print the Link information */ - void print(std::ostream& os) const - { - os << "Link " << name << " (id = " << id << ")" << std::endl; - os << " nonlocal = " << nonlocal << std::endl; - os << " component[0] = " << component[0] << std::endl; - os << " port[0] = " << port[0] << std::endl; - os << " latency[0] = " << latency[0] << std::endl; - os << " component[1] = " << component[1] << std::endl; - os << " port[1] = " << port[1] << std::endl; - os << " latency[1] = " << latency[1] << std::endl; - } - - /* Do not use. For serialization only */ - ConfigLink() {} - - void serialize_order(SST::Core::Serialization::serializer& ser) /*override*/ - { - SST_SER(id); - SST_SER(name); - SST_SER(component[0]); - SST_SER(component[1]); - SST_SER(port[0]); - SST_SER(port[1]); - SST_SER(latency[0]); - SST_SER(latency[1]); - SST_SER(order); - SST_SER(nonlocal); - SST_SER(no_cut); - SST_SER(cross_rank); - SST_SER(cross_thread); - } - -private: - friend class ConfigGraph; - explicit ConfigLink(LinkId_t id) : - id(id), - no_cut(false) - { - order = 0; - - // Initialize the component data items - component[0] = ULONG_MAX; - component[1] = ULONG_MAX; - } - - ConfigLink(LinkId_t id, const std::string& n) : - id(id), - no_cut(false) - { - order = 0; - name = n; - - // Initialize the component data items - component[0] = ULONG_MAX; - component[1] = ULONG_MAX; - } - - void updateLatencies(); -}; - -class ConfigStatistic : public SST::Core::Serialization::serializable -{ -public: - StatisticId_t id; /*!< Unique ID of this statistic */ - Params params; - bool shared = false; - std::string name; - - ConfigStatistic(StatisticId_t _id, bool _shared = false, std::string _name = "") : - id(_id), - shared(_shared), - name(_name) - {} - - ConfigStatistic() : - id(stat_null_id) - {} - - ConfigStatistic(const ConfigStatistic&) = default; - ConfigStatistic(ConfigStatistic&&) = default; - ConfigStatistic& operator=(const ConfigStatistic&) = default; - ConfigStatistic& operator=(ConfigStatistic&&) = default; - ~ConfigStatistic() override = default; - - inline const StatisticId_t& getId() const { return id; } - - void addParameter(const std::string& key, const std::string& value, bool overwrite); - - void serialize_order(SST::Core::Serialization::serializer& ser) override - { - SST_SER(id); - SST_SER(shared); - SST_SER(name); - SST_SER(params); - } - - ImplementSerializable(ConfigStatistic) - - static constexpr StatisticId_t stat_null_id = std::numeric_limits::max(); -}; - -class ConfigStatGroup : public SST::Core::Serialization::serializable -{ -public: - std::string name; - std::map statMap; - std::vector components; - size_t outputID; - UnitAlgebra outputFrequency; - - explicit ConfigStatGroup(const std::string& name) : - name(name), - outputID(0) - {} - ConfigStatGroup() {} /* Do not use */ - - bool addComponent(ComponentId_t id); - bool addStatistic(const std::string& name, Params& p); - bool setOutput(size_t id); - bool setFrequency(const std::string& freq); - - /** - * Checks to make sure that all components in the group support all - * of the statistics as configured in the group. - * @return pair of: bool for OK, string for error message (if any) - */ - std::pair verifyStatsAndComponents(const ConfigGraph* graph); - - void serialize_order(SST::Core::Serialization::serializer& ser) override - { - SST_SER(name); - SST_SER(statMap); - SST_SER(components); - SST_SER(outputID); - SST_SER(outputFrequency); - } - - ImplementSerializable(SST::ConfigStatGroup) -}; - -class ConfigStatOutput : public SST::Core::Serialization::serializable -{ -public: - std::string type; - Params params; - - explicit ConfigStatOutput(const std::string& type) : - type(type) - {} - ConfigStatOutput() {} - - void addParameter(const std::string& key, const std::string& val) { params.insert(key, val); } - - void serialize_order(SST::Core::Serialization::serializer& ser) override - { - SST_SER(type); - SST_SER(params); - } - - ImplementSerializable(SST::ConfigStatOutput) -}; - -using ConfigLinkMap_t = SparseVectorMap; - -/** - Class that represents a PortModule in ConfigGraph - */ -class ConfigPortModule -{ -public: - std::string type; - Params params; - uint8_t stat_load_level = STATISTICLOADLEVELUNINITIALIZED; - Params all_stat_config; /*!< If all stats are enabled, the config information for the stats */ - std::map per_stat_configs; - - ConfigPortModule() = default; - ConfigPortModule(const std::string& type, const Params& params) : - type(type), - params(params) - {} - - void addParameter(const std::string& key, const std::string& value); - void addSharedParamSet(const std::string& set); - void setStatisticLoadLevel(const uint8_t level); - void enableAllStatistics(const SST::Params& params); - void enableStatistic(const std::string& statistic_name, const SST::Params& params); - - void serialize_order(SST::Core::Serialization::serializer& ser) - { - SST_SER(type); - SST_SER(params); - SST_SER(stat_load_level); - SST_SER(all_stat_config); - SST_SER(per_stat_configs); - } -}; - - -/** Represents the configuration of a generic component */ -class ConfigComponent : public SST::Core::Serialization::serializable -{ - friend class ComponentInfo; - -public: - ComponentId_t id; /*!< Unique ID of this component */ - ConfigGraph* graph; /*!< Graph that this component belongs to */ - std::string name; /*!< Name of this component, or slot name for subcomp */ - int slot_num; /*!< Slot number. Only valid for subcomponents */ - std::string type; /*!< Type of this component */ - float weight; /*!< Partitioning weight for this component */ - RankInfo rank; /*!< Parallel Rank for this component */ - std::vector links; /*!< List of links connected */ - Params params; /*!< Set of Parameters */ - uint8_t statLoadLevel; /*!< Statistic load level for this component */ - - std::map> - port_modules; /*!< Map of port names to port modules loaded on that port */ - std::map - enabledStatNames; /*!< Map of explicitly enabled statistic names to unique IDs */ - bool enabledAllStats; /*!< Whether all stats in this (sub)component have been enabled */ - ConfigStatistic allStatConfig; /*!< If all stats are enabled, the config information for the stats */ - - std::vector subComponents; /*!< List of subcomponents */ - std::vector coords; - uint16_t nextSubID; /*!< Next subID to use for children, if component, if subcomponent, subid of parent */ - uint16_t nextStatID; /*!< Next statID to use for children */ - bool visited; /*! Used when traversing graph to indicate component was visited already */ - - static constexpr ComponentId_t null_id = std::numeric_limits::max(); - - inline const ComponentId_t& key() const { return id; } - - /** Print Component information */ - void print(std::ostream& os) const; - - ConfigComponent* cloneWithoutLinks(ConfigGraph* new_graph) const; - ConfigComponent* cloneWithoutLinksOrParams(ConfigGraph* new_graph) const; - void setConfigGraphPointer(ConfigGraph* graph_ptr); - - ~ConfigComponent() {} - ConfigComponent() : - id(null_id), - statLoadLevel(STATISTICLOADLEVELUNINITIALIZED), - enabledAllStats(false), - nextSubID(1), - visited(false) - {} - - StatisticId_t getNextStatisticID(); - - ConfigComponent* getParent() const; - std::string getFullName() const; - - void setRank(RankInfo r); - void setWeight(double w); - void setCoordinates(const std::vector& c); - void addParameter(const std::string& key, const std::string& value, bool overwrite); - ConfigComponent* addSubComponent(const std::string& name, const std::string& type, int slot); - ConfigComponent* findSubComponent(ComponentId_t); - const ConfigComponent* findSubComponent(ComponentId_t) const; - ConfigComponent* findSubComponentByName(const std::string& name); - ConfigStatistic* findStatistic(const std::string& name) const; - ConfigStatistic* insertStatistic(StatisticId_t id); - ConfigStatistic* findStatistic(StatisticId_t) const; - ConfigStatistic* enableStatistic( - const std::string& statisticName, const SST::Params& params, bool recursively = false); - ConfigStatistic* createStatistic(); - bool reuseStatistic(const std::string& statisticName, StatisticId_t sid); - void addStatisticParameter( - const std::string& statisticName, const std::string& param, const std::string& value, bool recursively = false); - void setStatisticParameters(const std::string& statisticName, const Params& params, bool recursively = false); - void setStatisticLoadLevel(uint8_t level, bool recursively = false); - - void addSharedParamSet(const std::string& set) { params.addSharedParamSet(set); } - [[deprecated( - "addGlobalParamSet() has been deprecated and will be removed in SST 16. Please use addSharedParamSet()")]] - void addGlobalParamSet(const std::string& set) - { - params.addSharedParamSet(set); - } - std::vector getParamsLocalKeys() const { return params.getLocalKeys(); } - std::vector getSubscribedSharedParamSets() const { return params.getSubscribedSharedParamSets(); } - - [[deprecated("getSubscribedGlobalParamSets() has been deprecated and will be removed in SST 16. Please use " - "getSubscribedSharedParamSets()")]] - std::vector getSubscribedGlobalParamSets() const - { - return params.getSubscribedSharedParamSets(); - } - - /* Adds a PortModule on the port 'port' of the associated component. Returns the index of the - * module in the component's vector of PortModules for the given port. */ - size_t addPortModule(const std::string& port, const std::string& type, const Params& params); - - std::vector allLinks() const; - - // Gets all the links to return, then clears links from self and - // all subcomponents. Used when splitting graphs. - std::vector clearAllLinks(); - - void serialize_order(SST::Core::Serialization::serializer& ser) override - { - SST_SER(id); - SST_SER(name); - SST_SER(slot_num); - SST_SER(type); - SST_SER(weight); - SST_SER(rank.rank); - SST_SER(rank.thread); - SST_SER(links); - SST_SER(params); - SST_SER(statLoadLevel); - SST_SER(port_modules); - SST_SER(enabledStatNames); - SST_SER(enabledAllStats); - SST_SER(statistics_); - SST_SER(allStatConfig); - SST_SER(subComponents); - SST_SER(coords); - SST_SER(nextSubID); - SST_SER(nextStatID); - } - - ImplementSerializable(SST::ConfigComponent) - -private: - std::map - statistics_; /* Map of explicitly enabled stat IDs to config info for each stat */ - - ComponentId_t getNextSubComponentID(); - - friend class ConfigGraph; - /** Checks to make sure port names are valid and that a port isn't used twice - */ - void checkPorts() const; - - /** Create a new Component */ - ConfigComponent(ComponentId_t id, ConfigGraph* graph, const std::string& name, const std::string& type, - float weight, RankInfo rank) : - id(id), - graph(graph), - name(name), - slot_num(0), - type(type), - weight(weight), - rank(rank), - statLoadLevel(STATISTICLOADLEVELUNINITIALIZED), - enabledAllStats(false), - nextSubID(1), - nextStatID(1) - { - coords.resize(3, 0.0); - } - - ConfigComponent(ComponentId_t id, ConfigGraph* graph, uint16_t parent_subid, const std::string& name, int slot_num, - const std::string& type, float weight, RankInfo rank) : - id(id), - graph(graph), - name(name), - slot_num(slot_num), - type(type), - weight(weight), - rank(rank), - statLoadLevel(STATISTICLOADLEVELUNINITIALIZED), - enabledAllStats(false), - nextSubID(parent_subid), - nextStatID(parent_subid) - { - coords.resize(3, 0.0); - } -}; - -/** Map names to Links */ -// using ConfigLinkMap_t = std::map; -// using ConfigLinkMap_t = SparseVectorMap; -/** Map IDs to Components */ -using ConfigComponentMap_t = SparseVectorMap; -/** Map names to Components */ -using ConfigComponentNameMap_t = std::map; -/** Map names to Parameter Sets: XML only */ -using ParamsMap_t = std::map; -/** Map names to variable values: XML only */ -using VariableMap_t = std::map; - -class PartitionGraph; - -struct StatsConfig -{ - std::map groups; - std::vector outputs; // [0] is default group - uint8_t load_level; - - void serialize_order(SST::Core::Serialization::serializer& ser) - { - SST_SER(groups); - SST_SER(outputs); - SST_SER(load_level); - } -}; - -/** A Configuration Graph - * A graph representing Components and Links - */ -class ConfigGraph : public SST::Core::Serialization::serializable -{ -public: - /** Print the configuration graph */ - void print(std::ostream& os) const - { - os << "Printing graph" << std::endl; - os << "Components:" << std::endl; - for ( ConfigComponentMap_t::const_iterator i = comps_.begin(); i != comps_.end(); ++i ) { - (*i)->print(os); - } - os << "Links:" << std::endl; - for ( auto i = links_.begin(); i != links_.end(); ++i ) { - (*i)->print(os); - } - } - - ConfigGraph() : - nextComponentId(0) - { - links_.clear(); - comps_.clear(); - // Init the statistic output settings - stats_config_ = new StatsConfig(); - stats_config_->load_level = STATISTICSDEFAULTLOADLEVEL; - stats_config_->outputs.emplace_back(STATISTICSDEFAULTOUTPUTNAME); - // Output is only used for warnings or fatal that should go to stderr - Output& o = Output::getDefaultObject(); - output.init(o.getPrefix(), o.getVerboseLevel(), o.getVerboseMask(), Output::STDERR); - } - - ~ConfigGraph() - { - for ( auto comp : comps_ ) { - delete comp; - } - - if ( stats_config_ ) delete stats_config_; - } - - size_t getNumComponents() { return comps_.data.size(); } - - size_t getNumComponentsInMPIRank(uint32_t rank); - - /** Helper function to set all the ranks to the same value */ - void setComponentRanks(RankInfo rank); - /** Checks to see if rank contains at least one component */ - bool containsComponentInRank(RankInfo rank); - /** Verify that all components have valid Ranks assigned */ - bool checkRanks(RankInfo ranks); - - // API for programmatic initialization - /** Create a new component */ - ComponentId_t addComponent(const std::string& name, const std::string& type); - - /** Add a parameter to a shared param set */ - void addSharedParam(const std::string& shared_set, const std::string& key, const std::string& value); - - [[deprecated("addGlobalParam() has been deprecated and will be removed in SST 16. Please use addSharedParam()")]] - void addGlobalParam(const std::string& shared_set, const std::string& key, const std::string& value); - - /** Set the statistic output module */ - void setStatisticOutput(const std::string& name); - - /** Add parameter to the statistic output module */ - void addStatisticOutputParameter(const std::string& param, const std::string& value); - - /** Set a set of parameter to the statistic output module */ - void setStatisticOutputParams(const Params& p); - - /** Set the statistic system load level */ - void setStatisticLoadLevel(uint8_t loadLevel); - - std::vector& getStatOutputs() { return stats_config_->outputs; } - - const ConfigStatOutput& getStatOutput(size_t index = 0) const { return stats_config_->outputs[index]; } - - long getStatLoadLevel() const { return stats_config_->load_level; } - - /** - Create link and return it's ID. The provided name is not - checked against existing links - */ - LinkId_t createLink(const char* name, const char* latency = nullptr); - - /** Add a Link to a Component on a given Port */ - void addLink(ComponentId_t comp_id, LinkId_t link_id, const char* port, const char* latency_str); - - /** - Adds the remote rank info for nonlocal links - */ - void addNonLocalLink(LinkId_t link_id, int rank, int thread); - - /** Set a Link to be no-cut */ - void setLinkNoCut(LinkId_t link_name); - - /** Perform any post-creation cleanup processes */ - void postCreationCleanup(); - - /** Check the graph for Structural errors */ - bool checkForStructuralErrors(); - - // Temporary until we have a better API - /** Return the map of components */ - ConfigComponentMap_t& getComponentMap() { return comps_; } - - const std::map& getStatGroups() const { return stats_config_->groups; } - ConfigStatGroup* getStatGroup(const std::string& name) - { - auto found = stats_config_->groups.find(name); - if ( found == stats_config_->groups.end() ) { - bool ok; - std::tie(found, ok) = stats_config_->groups.emplace(name, name); - } - return &(found->second); - } - - bool containsComponent(ComponentId_t id) const; - ConfigComponent* findComponent(ComponentId_t); - ConfigComponent* findComponentByName(const std::string& name); - const ConfigComponent* findComponent(ComponentId_t) const; - - ConfigStatistic* findStatistic(StatisticId_t) const; - - /** Return the map of links */ - ConfigLinkMap_t& getLinkMap() { return links_; } - - ConfigGraph* splitGraph(const std::set& orig_rank_set, const std::set& new_rank_set); - void reduceGraphToSingleRank(uint32_t rank); - - SimTime_t getMinimumPartitionLatency(); - - PartitionGraph* getPartitionGraph(); - PartitionGraph* getCollapsedPartitionGraph(); - void annotateRanks(PartitionGraph* graph); - void getConnectedNoCutComps(ComponentId_t start, std::set& group); - StatsConfig* getStatsConfig() { return stats_config_; } - StatsConfig* takeStatsConfig() - { - auto* ret = stats_config_; - stats_config_ = nullptr; - return ret; - } - - void setComponentConfigGraphPointers(); - void serialize_order(SST::Core::Serialization::serializer& ser) override - { - SST_SER(links_); - SST_SER(comps_); - SST_SER(stats_config_); - if ( ser.mode() == SST::Core::Serialization::serializer::UNPACK ) { - // Need to reinitialize the ConfigGraph ptrs in the - // ConfigComponents - setComponentConfigGraphPointers(); - } - - SST_SER(cpt_ranks); - SST_SER(cpt_currentSimCycle); - SST_SER(cpt_currentPriority); - SST_SER(cpt_minPart); - SST_SER(cpt_minPartTC); - SST_SER(cpt_max_event_id); - - SST_SER(*(cpt_libnames.get())); - SST_SER(*(cpt_shared_objects.get())); - SST_SER(*(cpt_stats_config.get())); - } - - void restoreRestartData(); - - /********* vv Variables used on restarts only vv ***********/ - RankInfo cpt_ranks; - SimTime_t cpt_currentSimCycle = 0; - int cpt_currentPriority = 0; - SimTime_t cpt_minPart = std::numeric_limits::max(); - TimeConverter cpt_minPartTC; - uint64_t cpt_max_event_id = 0; - - std::shared_ptr> cpt_libnames = std::make_shared>(); - std::shared_ptr> cpt_shared_objects = std::make_shared>(); - std::shared_ptr> cpt_stats_config = std::make_shared>(); - - /********* ^^ Variables used on restarts only ^^ ***********/ - - -private: - friend class Simulation_impl; - friend class SSTSDLModelDefinition; - - Output output; - - ComponentId_t nextComponentId; - - ConfigLinkMap_t links_; // SparseVectorMap - ConfigComponentMap_t comps_; // SparseVectorMap - ConfigComponentNameMap_t comps_by_name_; // std::map - - std::map link_names_; - - StatsConfig* stats_config_; - - ImplementSerializable(SST::ConfigGraph) - - // Filter class - class GraphFilter - { - ConfigGraph* ograph_; - ConfigGraph* ngraph_; - const std::set& oset_; - const std::set& nset_; - - public: - GraphFilter(ConfigGraph* original_graph, ConfigGraph* new_graph, const std::set& original_rank_set, - const std::set& new_rank_set); - - ConfigLink* operator()(ConfigLink* link); - ConfigComponent* operator()(ConfigComponent* comp); - }; -}; - -class PartitionComponent -{ -public: - ComponentId_t id; - float weight; - RankInfo rank; - LinkIdMap_t links; - - ComponentIdMap_t group; - - explicit PartitionComponent(const ConfigComponent* cc) - { - id = cc->id; - weight = cc->weight; - rank = cc->rank; - } - - explicit PartitionComponent(LinkId_t id) : - id(id), - weight(0), - rank(RankInfo(RankInfo::UNASSIGNED, 0)) - {} - - // PartitionComponent(ComponentId_t id, ConfigGraph* graph, const ComponentIdMap_t& group); - void print(std::ostream& os, const PartitionGraph* graph) const; - - inline ComponentId_t key() const { return id; } -}; - -class PartitionLink -{ -public: - LinkId_t id; - ComponentId_t component[2]; - SimTime_t latency[2]; - bool no_cut; - - PartitionLink(const ConfigLink& cl) - { - id = cl.id; - component[0] = cl.component[0]; - component[1] = cl.component[1]; - latency[0] = cl.latency[0]; - latency[1] = cl.latency[1]; - no_cut = cl.no_cut; - } - - inline LinkId_t key() const { return id; } - - /** Return the minimum latency of this link (from both sides) */ - SimTime_t getMinLatency() const - { - if ( latency[0] < latency[1] ) return latency[0]; - return latency[1]; - } - - /** Print the Link information */ - void print(std::ostream& os) const - { - os << " Link " << id << std::endl; - os << " component[0] = " << component[0] << std::endl; - os << " latency[0] = " << latency[0] << std::endl; - os << " component[1] = " << component[1] << std::endl; - os << " latency[1] = " << latency[1] << std::endl; - } -}; - -using PartitionComponentMap_t = SparseVectorMap; -using PartitionLinkMap_t = SparseVectorMap; - -class PartitionGraph -{ -private: - PartitionComponentMap_t comps_; - PartitionLinkMap_t links_; - -public: - /** Print the configuration graph */ - void print(std::ostream& os) const - { - os << "Printing graph" << std::endl; - for ( PartitionComponentMap_t::const_iterator i = comps_.begin(); i != comps_.end(); ++i ) { - (*i)->print(os, this); - } - } - - PartitionComponentMap_t& getComponentMap() { return comps_; } - PartitionLinkMap_t& getLinkMap() { return links_; } - - const PartitionLink& getLink(LinkId_t id) const { return links_[id]; } - - size_t getNumComponents() { return comps_.size(); } -}; - -} // namespace SST +#include "sst/core/model/configGraph.h" #endif // SST_CORE_CONFIGGRAPH_H diff --git a/src/sst/core/configGraphOutput.h b/src/sst/core/configGraphOutput.h index 477044c39..926c05a19 100644 --- a/src/sst/core/configGraphOutput.h +++ b/src/sst/core/configGraphOutput.h @@ -12,7 +12,7 @@ #ifndef SST_CORE_CONFIGGRAPH_OUTPUT_H #define SST_CORE_CONFIGGRAPH_OUTPUT_H -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/params.h" #include "sst/core/util/filesystem.h" diff --git a/src/sst/core/impl/partitioners/linpart.cc b/src/sst/core/impl/partitioners/linpart.cc index 30fd33c22..9f23e5349 100644 --- a/src/sst/core/impl/partitioners/linpart.cc +++ b/src/sst/core/impl/partitioners/linpart.cc @@ -13,7 +13,7 @@ #include "sst/core/impl/partitioners/linpart.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/output.h" #include "sst/core/warnmacros.h" diff --git a/src/sst/core/impl/partitioners/rrobin.cc b/src/sst/core/impl/partitioners/rrobin.cc index 779a8117a..428f2ee9b 100644 --- a/src/sst/core/impl/partitioners/rrobin.cc +++ b/src/sst/core/impl/partitioners/rrobin.cc @@ -13,7 +13,7 @@ #include "sst/core/impl/partitioners/rrobin.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/warnmacros.h" namespace SST::IMPL::Partition { diff --git a/src/sst/core/impl/partitioners/simplepart.cc b/src/sst/core/impl/partitioners/simplepart.cc index 0706ae7a5..73a3c5735 100644 --- a/src/sst/core/impl/partitioners/simplepart.cc +++ b/src/sst/core/impl/partitioners/simplepart.cc @@ -13,7 +13,7 @@ #include "sst/core/impl/partitioners/simplepart.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/warnmacros.h" #include diff --git a/src/sst/core/impl/partitioners/simplepart.h b/src/sst/core/impl/partitioners/simplepart.h index 0266e96bd..932aab3d5 100644 --- a/src/sst/core/impl/partitioners/simplepart.h +++ b/src/sst/core/impl/partitioners/simplepart.h @@ -12,8 +12,8 @@ #ifndef SST_CORE_IMPL_PARTITONERS_SIMPLEPART_H #define SST_CORE_IMPL_PARTITONERS_SIMPLEPART_H -#include "sst/core/configGraph.h" #include "sst/core/eli/elementinfo.h" +#include "sst/core/model/configGraph.h" #include "sst/core/sst_types.h" #include "sst/core/sstpart.h" diff --git a/src/sst/core/impl/partitioners/singlepart.cc b/src/sst/core/impl/partitioners/singlepart.cc index 9e9121a6e..27aaaa68b 100644 --- a/src/sst/core/impl/partitioners/singlepart.cc +++ b/src/sst/core/impl/partitioners/singlepart.cc @@ -13,7 +13,7 @@ #include "sst/core/impl/partitioners/singlepart.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/warnmacros.h" using namespace SST::IMPL::Partition; diff --git a/src/sst/core/main.cc b/src/sst/core/main.cc index d722d0add..bdbd97604 100644 --- a/src/sst/core/main.cc +++ b/src/sst/core/main.cc @@ -32,7 +32,6 @@ REENABLE_WARNING #include "sst/core/activity.h" #include "sst/core/checkpointAction.h" #include "sst/core/config.h" -#include "sst/core/configGraph.h" #include "sst/core/cputimer.h" #include "sst/core/exit.h" #include "sst/core/factory.h" @@ -41,6 +40,7 @@ REENABLE_WARNING #include "sst/core/mempool.h" #include "sst/core/mempoolAccessor.h" #include "sst/core/memuse.h" +#include "sst/core/model/configGraph.h" #include "sst/core/model/sstmodel.h" #include "sst/core/objectComms.h" #include "sst/core/rankInfo.h" @@ -66,11 +66,11 @@ REENABLE_WARNING #include // Configuration Graph Generation Options -#include "sst/core/cfgoutput/dotConfigOutput.h" -#include "sst/core/cfgoutput/jsonConfigOutput.h" -#include "sst/core/cfgoutput/pythonConfigOutput.h" #include "sst/core/configGraphOutput.h" #include "sst/core/eli/elementinfo.h" +#include "sst/core/model/cfgoutput/dotConfigOutput.h" +#include "sst/core/model/cfgoutput/jsonConfigOutput.h" +#include "sst/core/model/cfgoutput/pythonConfigOutput.h" using namespace SST::Core; using namespace SST::Partition; diff --git a/src/sst/core/model/Makefile.inc b/src/sst/core/model/Makefile.inc index 9dea930a6..80fc63657 100644 --- a/src/sst/core/model/Makefile.inc +++ b/src/sst/core/model/Makefile.inc @@ -8,10 +8,31 @@ sst_core_sources += \ model/sstmodel.h \ model/sstmodel.cc \ + model/configComponent.h \ + model/configComponent.cc \ + model/configGraph.cc \ + model/configLink.h \ + model/configLink.cc \ + model/configStatistic.h \ + model/configStatistic.cc \ model/element_python.h \ model/element_python.cc \ model/restart/sstcptmodel.h \ - model/restart/sstcptmodel.cc + model/restart/sstcptmodel.cc \ + model/cfgoutput/pythonConfigOutput.h \ + model/cfgoutput/pythonConfigOutput.cc \ + model/cfgoutput/dotConfigOutput.h \ + model/cfgoutput/dotConfigOutput.cc \ + model/cfgoutput/xmlConfigOutput.h \ + model/cfgoutput/xmlConfigOutput.cc \ + model/cfgoutput/jsonConfigOutput.h \ + model/cfgoutput/jsonConfigOutput.cc + + +nobase_dist_sst_HEADERS += \ + model/configGraph.h \ + model/element_python.h + sst_core_python_headers = \ model/python/pymacros.h diff --git a/src/sst/core/cfgoutput/CMakeLists.txt b/src/sst/core/model/cfgoutput/CMakeLists.txt similarity index 100% rename from src/sst/core/cfgoutput/CMakeLists.txt rename to src/sst/core/model/cfgoutput/CMakeLists.txt diff --git a/src/sst/core/cfgoutput/dotConfigOutput.cc b/src/sst/core/model/cfgoutput/dotConfigOutput.cc similarity index 99% rename from src/sst/core/cfgoutput/dotConfigOutput.cc rename to src/sst/core/model/cfgoutput/dotConfigOutput.cc index 7507d1751..ee90ff4f0 100644 --- a/src/sst/core/cfgoutput/dotConfigOutput.cc +++ b/src/sst/core/model/cfgoutput/dotConfigOutput.cc @@ -12,7 +12,7 @@ #include "sst_config.h" -#include "dotConfigOutput.h" +#include "sst/core/model/cfgoutput/dotConfigOutput.h" #include "sst/core/config.h" #include "sst/core/configGraphOutput.h" diff --git a/src/sst/core/cfgoutput/dotConfigOutput.h b/src/sst/core/model/cfgoutput/dotConfigOutput.h similarity index 96% rename from src/sst/core/cfgoutput/dotConfigOutput.h rename to src/sst/core/model/cfgoutput/dotConfigOutput.h index 169b67595..339c9b381 100644 --- a/src/sst/core/cfgoutput/dotConfigOutput.h +++ b/src/sst/core/model/cfgoutput/dotConfigOutput.h @@ -13,8 +13,8 @@ #ifndef SST_CORE_DOT_CONFIG_OUTPUT_H #define SST_CORE_DOT_CONFIG_OUTPUT_H -#include "sst/core/configGraph.h" #include "sst/core/configGraphOutput.h" +#include "sst/core/model/configGraph.h" #include diff --git a/src/sst/core/cfgoutput/jsonConfigOutput.cc b/src/sst/core/model/cfgoutput/jsonConfigOutput.cc similarity index 99% rename from src/sst/core/cfgoutput/jsonConfigOutput.cc rename to src/sst/core/model/cfgoutput/jsonConfigOutput.cc index 8eb327563..fb1aad1b2 100644 --- a/src/sst/core/cfgoutput/jsonConfigOutput.cc +++ b/src/sst/core/model/cfgoutput/jsonConfigOutput.cc @@ -12,11 +12,9 @@ #include "sst_config.h" -#include "sst/core/cfgoutput/jsonConfigOutput.h" +#include "sst/core/model/cfgoutput/jsonConfigOutput.h" #include "sst/core/config.h" -#include "sst/core/configGraph.h" -#include "sst/core/configGraphOutput.h" #include "sst/core/params.h" #include "sst/core/simulation_impl.h" #include "sst/core/util/filesystem.h" diff --git a/src/sst/core/cfgoutput/jsonConfigOutput.h b/src/sst/core/model/cfgoutput/jsonConfigOutput.h similarity index 97% rename from src/sst/core/cfgoutput/jsonConfigOutput.h rename to src/sst/core/model/cfgoutput/jsonConfigOutput.h index da19c308e..580807de9 100644 --- a/src/sst/core/cfgoutput/jsonConfigOutput.h +++ b/src/sst/core/model/cfgoutput/jsonConfigOutput.h @@ -13,8 +13,8 @@ #ifndef SST_CORE_JSON_CONFIG_OUTPUT_H #define SST_CORE_JSON_CONFIG_OUTPUT_H -#include "sst/core/configGraph.h" #include "sst/core/configGraphOutput.h" +#include "sst/core/model/configGraph.h" #include "sst/core/util/filesystem.h" #include diff --git a/src/sst/core/cfgoutput/pythonConfigOutput.cc b/src/sst/core/model/cfgoutput/pythonConfigOutput.cc similarity index 99% rename from src/sst/core/cfgoutput/pythonConfigOutput.cc rename to src/sst/core/model/cfgoutput/pythonConfigOutput.cc index d995420d3..bd77d89b1 100644 --- a/src/sst/core/cfgoutput/pythonConfigOutput.cc +++ b/src/sst/core/model/cfgoutput/pythonConfigOutput.cc @@ -12,7 +12,7 @@ #include "sst_config.h" -#include "pythonConfigOutput.h" +#include "sst/core/model/cfgoutput/pythonConfigOutput.h" #include "sst/core/config.h" #include "sst/core/simulation_impl.h" diff --git a/src/sst/core/cfgoutput/pythonConfigOutput.h b/src/sst/core/model/cfgoutput/pythonConfigOutput.h similarity index 98% rename from src/sst/core/cfgoutput/pythonConfigOutput.h rename to src/sst/core/model/cfgoutput/pythonConfigOutput.h index beca3e5b1..a303e64a4 100644 --- a/src/sst/core/cfgoutput/pythonConfigOutput.h +++ b/src/sst/core/model/cfgoutput/pythonConfigOutput.h @@ -13,8 +13,8 @@ #ifndef SST_CORE_PYTHON_CONFIG_OUTPUT_H #define SST_CORE_PYTHON_CONFIG_OUTPUT_H -#include "sst/core/configGraph.h" #include "sst/core/configGraphOutput.h" +#include "sst/core/model/configGraph.h" #include #include diff --git a/src/sst/core/cfgoutput/xmlConfigOutput.cc b/src/sst/core/model/cfgoutput/xmlConfigOutput.cc similarity index 98% rename from src/sst/core/cfgoutput/xmlConfigOutput.cc rename to src/sst/core/model/cfgoutput/xmlConfigOutput.cc index 263187ee9..d47bd2242 100644 --- a/src/sst/core/cfgoutput/xmlConfigOutput.cc +++ b/src/sst/core/model/cfgoutput/xmlConfigOutput.cc @@ -12,7 +12,7 @@ #include "sst_config.h" -#include "xmlConfigOutput.h" +#include "sst/core/model/cfgoutput/xmlConfigOutput.h" #include "sst/core/configGraphOutput.h" #include "sst/core/warnmacros.h" diff --git a/src/sst/core/cfgoutput/xmlConfigOutput.h b/src/sst/core/model/cfgoutput/xmlConfigOutput.h similarity index 96% rename from src/sst/core/cfgoutput/xmlConfigOutput.h rename to src/sst/core/model/cfgoutput/xmlConfigOutput.h index 48ff8b1c3..3e884870b 100644 --- a/src/sst/core/cfgoutput/xmlConfigOutput.h +++ b/src/sst/core/model/cfgoutput/xmlConfigOutput.h @@ -13,8 +13,8 @@ #ifndef SST_CORE_XML_CONFIG_OUTPUT_H #define SST_CORE_XML_CONFIG_OUTPUT_H -#include "sst/core/configGraph.h" #include "sst/core/configGraphOutput.h" +#include "sst/core/model/configGraph.h" #include diff --git a/src/sst/core/model/configComponent.cc b/src/sst/core/model/configComponent.cc new file mode 100644 index 000000000..e7d710629 --- /dev/null +++ b/src/sst/core/model/configComponent.cc @@ -0,0 +1,613 @@ +// Copyright 2009-2025 NTESS. Under the terms +// of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Copyright (c) 2009-2025, NTESS +// All rights reserved. +// +// This file is part of the SST software package. For license +// information, see the LICENSE file in the top level directory of the +// distribution. + +#include "sst_config.h" + +#include "sst/core/model/configComponent.h" + +#include "sst/core/component.h" +#include "sst/core/config.h" +#include "sst/core/factory.h" +#include "sst/core/from_string.h" +#include "sst/core/model/configGraph.h" +#include "sst/core/namecheck.h" +#include "sst/core/simulation_impl.h" +#include "sst/core/timeLord.h" +#include "sst/core/warnmacros.h" + +#include +#include +#include +#include +#include + + +namespace SST { + +// void +// ConfigStatistic::addParameter(const std::string& key, const std::string& value, bool overwrite) +// { +// bool bk = params.enableVerify(false); +// params.insert(key, value, overwrite); +// params.enableVerify(bk); +// } + +// bool +// ConfigStatGroup::addComponent(ComponentId_t id) +// { +// if ( std::find(components.begin(), components.end(), id) == components.end() ) { +// components.push_back(id); +// } +// return true; +// } + +// bool +// ConfigStatGroup::addStatistic(const std::string& name, Params& p) +// { +// statMap[name] = p; +// if ( outputFrequency.getValue() == 0 ) { +// /* aka, not yet really set to anything other than 0 */ +// setFrequency(p.find("rate", "0ns")); +// } +// return true; +// } + +// bool +// ConfigStatGroup::setOutput(size_t id) +// { +// outputID = id; +// return true; +// } + +// bool +// ConfigStatGroup::setFrequency(const std::string& freq) +// { +// UnitAlgebra uaFreq(freq); +// if ( uaFreq.hasUnits("s") || uaFreq.hasUnits("hz") ) { +// outputFrequency = uaFreq; +// return true; +// } +// return false; +// } + +// std::pair +// ConfigStatGroup::verifyStatsAndComponents(const ConfigGraph* graph) +// { +// for ( auto id : components ) { +// const ConfigComponent* comp = graph->findComponent(id); +// if ( !comp ) { +// std::stringstream ss; +// ss << "Component id " << id << " is not a valid component"; +// return std::make_pair(false, ss.str()); +// } +// for ( auto& statKV : statMap ) { + +// bool ok = Factory::getFactory()->GetStatisticValidityAndEnableLevel(comp->type, statKV.first) != 255; + +// if ( !ok ) { +// std::stringstream ss; +// ss << "Component " << comp->name << " does not support statistic " << statKV.first; +// return std::make_pair(false, ss.str()); +// } +// } +// } + +// return std::make_pair(true, ""); +// } + +void +ConfigPortModule::addParameter(const std::string& key, const std::string& value) +{ + params.insert(key, value); +} + +void +ConfigPortModule::addSharedParamSet(const std::string& set) +{ + params.addSharedParamSet(set); +} + +void +ConfigPortModule::setStatisticLoadLevel(const uint8_t level) +{ + stat_load_level = level; +} + +void +ConfigPortModule::enableAllStatistics(const SST::Params& params) +{ + all_stat_config.insert(params); +} + +void +ConfigPortModule::enableStatistic(const std::string& statistic_name, const SST::Params& params) +{ + auto iter = per_stat_configs.find(statistic_name); + if ( iter == per_stat_configs.end() ) { + per_stat_configs[statistic_name] = params; + } + else { + per_stat_configs[statistic_name].insert(params); + } +} + +void +ConfigComponent::print(std::ostream& os) const +{ + os << "Component " << name << " (id = " << std::hex << id << std::dec << ")" << std::endl; + os << " slot_num = " << slot_num << std::endl; + os << " type = " << type << std::endl; + os << " weight = " << weight << std::endl; + os << " rank = " << rank.rank << std::endl; + os << " thread = " << rank.thread << std::endl; + os << " Links:" << std::endl; + for ( size_t i = 0; i != links.size(); ++i ) { + os << " " << links[i]; + } + os << std::endl; + os << " Params:" << std::endl; + params.print_all_params(os, " "); + os << " statLoadLevel = " << (uint32_t)statLoadLevel << std::endl; + os << " enabledAllStats = " << enabledAllStats << std::endl; + os << " Params:" << std::endl; + allStatConfig.params.print_all_params(os, " "); + os << " Statistics:" << std::endl; + for ( auto& pair : enabledStatNames ) { + os << " " << pair.first << std::endl; + os << " Params:" << std::endl; + auto iter = statistics_.find(pair.second); + iter->second.params.print_all_params(os, " "); + } + os << " SubComponents:\n"; + for ( auto* sc : subComponents ) { + sc->print(os); + } +} + +void +ConfigComponent::setConfigGraphPointer(ConfigGraph* graph_ptr) +{ + graph = graph_ptr; + for ( auto* x : subComponents ) { + x->setConfigGraphPointer(graph_ptr); + } +} + +ComponentId_t +ConfigComponent::getNextSubComponentID() +{ + // If we are the ultimate component, get nextSubID and increment + // for next time + if ( id == COMPONENT_ID_MASK(id) ) { + uint16_t subid = nextSubID; + nextSubID++; + return SUBCOMPONENT_ID_CREATE(id, subid); + } + else { + // Get the ultimate parent and call getNextSubComponentID on + // it + return graph->findComponent(COMPONENT_ID_MASK(id))->getNextSubComponentID(); + } +} + +StatisticId_t +ConfigComponent::getNextStatisticID() +{ + uint16_t statId = nextStatID++; + return STATISTIC_ID_CREATE(id, statId); +} + +ConfigComponent* +ConfigComponent::getParent() const +{ + if ( id == COMPONENT_ID_MASK(id) ) { + return nullptr; + } + return graph->findComponent((((ComponentId_t)nextSubID) << COMPONENT_ID_BITS) | COMPONENT_ID_MASK(id)); +} + +std::string +ConfigComponent::getFullName() const +{ + if ( id == COMPONENT_ID_MASK(id) ) { + // We are a component + return name; + } + + // Get full name of parent + std::string parent_name = getParent()->getFullName(); + + // For ConfigComponent, we will always put in [] for the slot number. + return parent_name + ":" + name + "[" + std::to_string(slot_num) + "]"; +} + +void +ConfigComponent::setRank(RankInfo r) +{ + rank = r; + for ( auto* i : subComponents ) { + i->setRank(r); + } +} + +void +ConfigComponent::setWeight(double w) +{ + weight = w; + for ( auto* i : subComponents ) { + i->setWeight(w); + } +} + +void +ConfigComponent::setCoordinates(const std::vector& c) +{ + coords = c; + /* Maintain minimum of 3D information */ + while ( coords.size() < 3 ) + coords.push_back(0.0); +} + +void +ConfigComponent::addParameter(const std::string& key, const std::string& value, bool overwrite) +{ + bool bk = params.enableVerify(false); + params.insert(key, value, overwrite); + params.enableVerify(bk); +} + +ConfigStatistic* +ConfigComponent::createStatistic() +{ + StatisticId_t stat_id = getNextStatisticID(); + + auto* parent = getParent(); + ConfigStatistic* cs = nullptr; + if ( parent ) { + cs = parent->insertStatistic(stat_id); + } + else { + cs = &statistics_[stat_id]; + } + cs->id = stat_id; + return cs; +} + +ConfigStatistic* +ConfigComponent::enableStatistic(const std::string& statisticName, const SST::Params& params, bool recursively) +{ + // NOTE: For every statistic in the statistics List, there must be + // a corresponding params entry in enabledStatParams list. The two + // lists will always be the same size. + if ( recursively ) { + for ( auto* sc : subComponents ) { + sc->enableStatistic(statisticName, params, true); + } + } + StatisticId_t stat_id; + if ( statisticName == STATALLFLAG ) { + // Special sentinel id for enable all + // The ConfigStatistic object for STATALLFLAG is not an entry of the statistics + // It has its own ConfigStatistic as a member variable of ConfigComponent which must be used + // in case of enabledAllStats == true. + enabledAllStats = true; + allStatConfig.id = STATALL_ID; + allStatConfig.params.insert(params); + return &allStatConfig; + } + else { + // this is a valid statistic + auto iter = enabledStatNames.find(statisticName); + if ( iter == enabledStatNames.end() ) { + // this is the first time being enabled + stat_id = getNextStatisticID(); + enabledStatNames[statisticName] = stat_id; + auto* parent = getParent(); + if ( parent ) { + ConfigStatistic* cs = parent->insertStatistic(stat_id); + cs->id = stat_id; + cs->params.insert(params); + return cs; + } + } + else { + // this was already enabled + stat_id = iter->second; + } + } + + ConfigStatistic& cs = statistics_[stat_id]; + cs.id = stat_id; + cs.params.insert(params); + return &cs; +} + +bool +ConfigComponent::reuseStatistic(const std::string& statisticName, StatisticId_t sid) +{ + if ( statisticName == STATALLFLAG ) { + // We cannot use reuseStatistic with STATALLFLAG + Output::getDefaultObject().fatal(CALL_INFO, 1, "Cannot reuse a Statistic with STATALLFLAG as parameter"); + return false; + } + + auto* comp = this; + while ( comp->getParent() != nullptr ) { + comp = comp->getParent(); + } + + if ( !Factory::getFactory()->DoesComponentInfoStatisticNameExist(type, statisticName) ) { + Output::getDefaultObject().fatal(CALL_INFO, 1, + "Failed to create statistic '%s' on '%s' of type '%s' - this is not a valid statistic\n", + statisticName.c_str(), name.c_str(), type.c_str()); + return false; + } + + auto iter = comp->statistics_.find(sid); + if ( iter == comp->statistics_.end() ) { + Output::getDefaultObject().fatal(CALL_INFO, 1, "Cannot reuse a statistic that doesn't exist for the parent"); + return false; + } + else { + enabledStatNames[statisticName] = sid; + return true; + } +} + +void +ConfigComponent::addStatisticParameter( + const std::string& statisticName, const std::string& param, const std::string& value, bool recursively) +{ + // NOTE: For every statistic in the statistics map, there must be + // a corresponding params entry in enabledStatParams list. The two + // lists will always be the same size. + if ( recursively ) { + for ( auto* sc : subComponents ) { + sc->addStatisticParameter(statisticName, param, value, true); + } + } + + ConfigStatistic* cs = nullptr; + if ( statisticName == STATALLFLAG ) { + cs = &allStatConfig; + } + else { + cs = findStatistic(statisticName); + } + if ( !cs ) { + Output::getDefaultObject().fatal( + CALL_INFO, 1, "cannot add parameter '%s' to unknown statistic '%s'", param.c_str(), statisticName.c_str()); + } + cs->params.insert(param, value); +} + +void +ConfigComponent::setStatisticParameters(const std::string& statisticName, const Params& params, bool recursively) +{ + if ( recursively ) { + for ( auto* sc : subComponents ) { + sc->setStatisticParameters(statisticName, params, true); + } + } + + if ( statisticName == STATALLFLAG ) { + allStatConfig.params.insert(params); + ; + } + else { + findStatistic(statisticName)->params.insert(params); + } +} + +void +ConfigComponent::setStatisticLoadLevel(uint8_t level, bool recursively) +{ + statLoadLevel = level; + + if ( recursively ) { + for ( auto* sc : subComponents ) { + sc->setStatisticLoadLevel(level, true); + } + } +} + +ConfigComponent* +ConfigComponent::addSubComponent(const std::string& name, const std::string& type, int slot_num) +{ + ComponentId_t sid = getNextSubComponentID(); + /* Check for existing subComponent with this name */ + for ( auto* i : subComponents ) { + if ( i->name == name && i->slot_num == slot_num ) return nullptr; + } + + uint16_t parent_sub_id = SUBCOMPONENT_ID_MASK(id); + + subComponents.push_back( + new ConfigComponent(sid, graph, parent_sub_id, name, slot_num, type, this->weight, this->rank)); + + return subComponents.back(); +} + +ConfigComponent* +ConfigComponent::findSubComponent(ComponentId_t sid) +{ + return const_cast(const_cast(this)->findSubComponent(sid)); +} + +const ConfigComponent* +ConfigComponent::findSubComponent(ComponentId_t sid) const +{ + if ( sid == this->id ) return this; + + for ( auto* s : subComponents ) { + const ConfigComponent* res = s->findSubComponent(sid); + if ( res != nullptr ) return res; + } + + return nullptr; +} + +ConfigComponent* +ConfigComponent::findSubComponentByName(const std::string& name) +{ + size_t colon_index = name.find(":"); + std::string slot = name.substr(0, colon_index); + + // Get the slot number + int slot_num = 0; + size_t bracket_index = slot.find("["); + if ( bracket_index == std::string::npos ) { + // No brackets, slot_num 0 + slot_num = 0; + } + else { + size_t close_index = slot.find("]"); + size_t length = close_index - bracket_index - 1; + slot_num = Core::from_string(slot.substr(bracket_index + 1, length)); + slot = slot.substr(0, bracket_index); + } + + // Now, see if we have something in this slot and slot_num + for ( auto* sc : subComponents ) { + if ( sc->name == slot && sc->slot_num == slot_num ) { + // Found the subcomponent + if ( colon_index == std::string::npos ) { + // Last level of hierarchy + return sc; + } + else { + return sc->findSubComponentByName(name.substr(colon_index + 1, std::string::npos)); + } + } + } + return nullptr; +} + +ConfigStatistic* +ConfigComponent::insertStatistic(StatisticId_t sid) +{ + ConfigComponent* parent = getParent(); + if ( parent ) { + return parent->insertStatistic(sid); + } + else { + return &statistics_[sid]; + } +} + +ConfigStatistic* +ConfigComponent::findStatistic(const std::string& name) const +{ + auto iter = enabledStatNames.find(name); + if ( iter != enabledStatNames.end() ) { + StatisticId_t id = iter->second; + return findStatistic(id); + } + else { + return nullptr; + } +} + +ConfigStatistic* +ConfigComponent::findStatistic(StatisticId_t sid) const +{ + auto* parent = getParent(); + if ( parent ) { + return parent->findStatistic(sid); + } + else { + auto iter = statistics_.find(sid); + if ( iter == statistics_.end() ) { + return nullptr; + } + else { + // I hate that I have to do this + return const_cast(&iter->second); + } + } +} + +size_t +ConfigComponent::addPortModule(const std::string& port, const std::string& type, const Params& params) +{ + port_modules[port].emplace_back(type, params); + return port_modules.size() - 1; +} + +std::vector +ConfigComponent::allLinks() const +{ + std::vector res; + res.insert(res.end(), links.begin(), links.end()); + for ( auto* sc : subComponents ) { + std::vector s = sc->allLinks(); + res.insert(res.end(), s.begin(), s.end()); + } + return res; +} + +std::vector +ConfigComponent::clearAllLinks() +{ + std::vector res; + res.insert(res.end(), links.begin(), links.end()); + links.clear(); + for ( auto* sc : subComponents ) { + std::vector s = sc->clearAllLinks(); + res.insert(res.end(), s.begin(), s.end()); + } + return res; +} + +void +ConfigComponent::checkPorts() const +{ + std::map ports; + + auto& graph_links = graph->getLinkMap(); + + // Loop over all the links + for ( unsigned int i = 0; i < links.size(); i++ ) { + const ConfigLink* link = graph_links[links[i]]; + for ( int j = 0; j < 2; j++ ) { + + if ( link->component[j] == id ) { + // If port is not found, print an error + if ( !Factory::getFactory()->isPortNameValid(type, link->port[j]) ) { + // For now this is not a fatal error + // found_error = true; + Output::getDefaultObject().fatal(CALL_INFO, 1, + "ERROR: Attempting to connect to unknown port: %s, " + "in component %s of type %s.\n", + link->port[j].c_str(), name.c_str(), type.c_str()); + } + + // Check for multiple links hooked to port + auto ret = ports.insert(std::make_pair(link->port[j], link->name)); + if ( !ret.second ) { + // Check to see if this is a loopback link + if ( ret.first->second != link->name ) + // Not a loopback link, fatal... + Output::getDefaultObject().fatal(CALL_INFO, 1, + "ERROR: Port %s of Component %s connected to two links: %s, %s.\n", link->port[j].c_str(), + name.c_str(), link->name.c_str(), ret.first->second.c_str()); + } + } + } + } + + // Now loop over all subcomponents and call the check function + for ( auto* subcomp : subComponents ) { + subcomp->checkPorts(); + } +} + +} // namespace SST diff --git a/src/sst/core/model/configComponent.h b/src/sst/core/model/configComponent.h new file mode 100644 index 000000000..2fd675ed2 --- /dev/null +++ b/src/sst/core/model/configComponent.h @@ -0,0 +1,259 @@ +// -*- c++ -*- + +// Copyright 2009-2025 NTESS. Under the terms +// of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Copyright (c) 2009-2025, NTESS +// All rights reserved. +// +// This file is part of the SST software package. For license +// information, see the LICENSE file in the top level directory of the +// distribution. + +#ifndef SST_CORE_MODEL_CONFIGCOMPONENT_H +#define SST_CORE_MODEL_CONFIGCOMPONENT_H + +#include "sst/core/model/configStatistic.h" +#include "sst/core/params.h" +#include "sst/core/rankInfo.h" +#include "sst/core/serialization/serializable.h" +#include "sst/core/sparseVectorMap.h" +#include "sst/core/sst_types.h" +#include "sst/core/statapi/statbase.h" +#include "sst/core/statapi/statoutput.h" +#include "sst/core/timeConverter.h" +#include "sst/core/unitAlgebra.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace SST::Statistics; + +namespace SST { + +class ConfigGraph; +class ConfigLink; + +/** + Class that represents a PortModule in ConfigGraph + */ +class ConfigPortModule +{ +public: + std::string type; + Params params; + uint8_t stat_load_level = STATISTICLOADLEVELUNINITIALIZED; + Params all_stat_config; /*!< If all stats are enabled, the config information for the stats */ + std::map per_stat_configs; + + ConfigPortModule() = default; + ConfigPortModule(const std::string& type, const Params& params) : + type(type), + params(params) + {} + + void addParameter(const std::string& key, const std::string& value); + void addSharedParamSet(const std::string& set); + void setStatisticLoadLevel(const uint8_t level); + void enableAllStatistics(const SST::Params& params); + void enableStatistic(const std::string& statistic_name, const SST::Params& params); + + void serialize_order(SST::Core::Serialization::serializer& ser) + { + SST_SER(type); + SST_SER(params); + SST_SER(stat_load_level); + SST_SER(all_stat_config); + SST_SER(per_stat_configs); + } +}; + + +/** Represents the configuration of a generic component */ +class ConfigComponent : public SST::Core::Serialization::serializable +{ + friend class ComponentInfo; + +public: + ComponentId_t id; /*!< Unique ID of this component */ + ConfigGraph* graph; /*!< Graph that this component belongs to */ + std::string name; /*!< Name of this component, or slot name for subcomp */ + int slot_num; /*!< Slot number. Only valid for subcomponents */ + std::string type; /*!< Type of this component */ + float weight; /*!< Partitioning weight for this component */ + RankInfo rank; /*!< Parallel Rank for this component */ + std::vector links; /*!< List of links connected */ + Params params; /*!< Set of Parameters */ + uint8_t statLoadLevel; /*!< Statistic load level for this component */ + + std::map> + port_modules; /*!< Map of port names to port modules loaded on that port */ + std::map + enabledStatNames; /*!< Map of explicitly enabled statistic names to unique IDs */ + bool enabledAllStats; /*!< Whether all stats in this (sub)component have been enabled */ + ConfigStatistic allStatConfig; /*!< If all stats are enabled, the config information for the stats */ + + std::vector subComponents; /*!< List of subcomponents */ + std::vector coords; + uint16_t nextSubID; /*!< Next subID to use for children, if component, if subcomponent, subid of parent */ + uint16_t nextStatID; /*!< Next statID to use for children */ + bool visited; /*! Used when traversing graph to indicate component was visited already */ + + static constexpr ComponentId_t null_id = std::numeric_limits::max(); + + inline const ComponentId_t& key() const { return id; } + + /** Print Component information */ + void print(std::ostream& os) const; + + void setConfigGraphPointer(ConfigGraph* graph_ptr); + + ~ConfigComponent() {} + ConfigComponent() : + id(null_id), + statLoadLevel(STATISTICLOADLEVELUNINITIALIZED), + enabledAllStats(false), + nextSubID(1), + visited(false) + {} + + StatisticId_t getNextStatisticID(); + + ConfigComponent* getParent() const; + std::string getFullName() const; + + void setRank(RankInfo r); + void setWeight(double w); + void setCoordinates(const std::vector& c); + void addParameter(const std::string& key, const std::string& value, bool overwrite); + ConfigComponent* addSubComponent(const std::string& name, const std::string& type, int slot); + ConfigComponent* findSubComponent(ComponentId_t); + const ConfigComponent* findSubComponent(ComponentId_t) const; + ConfigComponent* findSubComponentByName(const std::string& name); + ConfigStatistic* findStatistic(const std::string& name) const; + ConfigStatistic* insertStatistic(StatisticId_t id); + ConfigStatistic* findStatistic(StatisticId_t) const; + ConfigStatistic* enableStatistic( + const std::string& statisticName, const SST::Params& params, bool recursively = false); + ConfigStatistic* createStatistic(); + bool reuseStatistic(const std::string& statisticName, StatisticId_t sid); + void addStatisticParameter( + const std::string& statisticName, const std::string& param, const std::string& value, bool recursively = false); + void setStatisticParameters(const std::string& statisticName, const Params& params, bool recursively = false); + void setStatisticLoadLevel(uint8_t level, bool recursively = false); + + void addSharedParamSet(const std::string& set) { params.addSharedParamSet(set); } + [[deprecated( + "addGlobalParamSet() has been deprecated and will be removed in SST 16. Please use addSharedParamSet()")]] + void addGlobalParamSet(const std::string& set) + { + params.addSharedParamSet(set); + } + std::vector getParamsLocalKeys() const { return params.getLocalKeys(); } + std::vector getSubscribedSharedParamSets() const { return params.getSubscribedSharedParamSets(); } + + [[deprecated("getSubscribedGlobalParamSets() has been deprecated and will be removed in SST 16. Please use " + "getSubscribedSharedParamSets()")]] + std::vector getSubscribedGlobalParamSets() const + { + return params.getSubscribedSharedParamSets(); + } + + /** + Adds a PortModule on the port 'port' of the associated component. Returns the index of the module in the + component's vector of PortModules for the given port. + */ + size_t addPortModule(const std::string& port, const std::string& type, const Params& params); + + std::vector allLinks() const; + + /** + Gets all the links to return, then clears links from self and + all subcomponents. Used when splitting graphs. + */ + std::vector clearAllLinks(); + + void serialize_order(SST::Core::Serialization::serializer& ser) override + { + SST_SER(id); + SST_SER(name); + SST_SER(slot_num); + SST_SER(type); + SST_SER(weight); + SST_SER(rank.rank); + SST_SER(rank.thread); + SST_SER(links); + SST_SER(params); + SST_SER(statLoadLevel); + SST_SER(port_modules); + SST_SER(enabledStatNames); + SST_SER(enabledAllStats); + SST_SER(statistics_); + SST_SER(allStatConfig); + SST_SER(subComponents); + SST_SER(coords); + SST_SER(nextSubID); + SST_SER(nextStatID); + } + + ImplementSerializable(SST::ConfigComponent) + +private: + std::map + statistics_; /* Map of explicitly enabled stat IDs to config info for each stat */ + + ComponentId_t getNextSubComponentID(); + + friend class ConfigGraph; + /** Checks to make sure port names are valid and that a port isn't used twice + */ + void checkPorts() const; + + /** Create a new Component */ + ConfigComponent(ComponentId_t id, ConfigGraph* graph, const std::string& name, const std::string& type, + float weight, RankInfo rank) : + id(id), + graph(graph), + name(name), + slot_num(0), + type(type), + weight(weight), + rank(rank), + statLoadLevel(STATISTICLOADLEVELUNINITIALIZED), + enabledAllStats(false), + nextSubID(1), + nextStatID(1) + { + coords.resize(3, 0.0); + } + + ConfigComponent(ComponentId_t id, ConfigGraph* graph, uint16_t parent_subid, const std::string& name, int slot_num, + const std::string& type, float weight, RankInfo rank) : + id(id), + graph(graph), + name(name), + slot_num(slot_num), + type(type), + weight(weight), + rank(rank), + statLoadLevel(STATISTICLOADLEVELUNINITIALIZED), + enabledAllStats(false), + nextSubID(parent_subid), + nextStatID(parent_subid) + { + coords.resize(3, 0.0); + } +}; + +} // namespace SST + +#endif // SST_CORE_MODEL_CONFIGCOMPONENT_H diff --git a/src/sst/core/configGraph.cc b/src/sst/core/model/configGraph.cc similarity index 57% rename from src/sst/core/configGraph.cc rename to src/sst/core/model/configGraph.cc index 35adb35bf..117e72e63 100644 --- a/src/sst/core/configGraph.cc +++ b/src/sst/core/model/configGraph.cc @@ -11,12 +11,14 @@ #include "sst_config.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/component.h" #include "sst/core/config.h" #include "sst/core/factory.h" #include "sst/core/from_string.h" +#include "sst/core/model/configLink.h" +#include "sst/core/model/configStatistic.h" #include "sst/core/namecheck.h" #include "sst/core/simulation_impl.h" #include "sst/core/timeLord.h" @@ -29,7 +31,6 @@ #include namespace { -// bool zero_latency_warning = false; // Functions to check component and link names int bad_comp_name_count = 0; @@ -70,705 +71,65 @@ checkForValidLinkName(const std::string& name) namespace SST { -std::map ConfigLink::lat_to_index; -uint32_t -ConfigLink::getIndexForLatency(const char* latency) +ConfigGraph::ConfigGraph() : + nextComponentId(0) { - std::string lat(latency); - uint32_t& index = lat_to_index[lat]; - if ( index == 0 ) { - // Wasn't there, set it to lat_to_index.size(), which is the - // next index (skipping zero as that is the check for a new - // entry) - index = lat_to_index.size(); - } - return index; -} - -std::vector -ConfigLink::initializeLinkLatencyVector() -{ - TimeLord* timeLord = Simulation_impl::getTimeLord(); - std::vector vec; - vec.resize(lat_to_index.size() + 1); - for ( auto& [lat, index] : lat_to_index ) { - vec[index] = timeLord->getSimCycles(lat, __FUNCTION__); - } - return vec; -} - -SimTime_t -ConfigLink::getLatencyFromIndex(uint32_t index) -{ - static std::vector vec = initializeLinkLatencyVector(); - return vec[index]; -} - -std::string -ConfigLink::latency_str(uint32_t index) const -{ - static TimeLord* timelord = Simulation_impl::getTimeLord(); - UnitAlgebra tb = timelord->getTimeBase(); - auto tmp = tb * latency[index]; - return tmp.toStringBestSI(); -} - -void -ConfigLink::setAsNonLocal(int which_local, RankInfo remote_rank_info) -{ - // First, if which_local != 0, we need to swap the data for index - // 0 and 1 - if ( which_local == 1 ) { - std::swap(component[0], component[1]); - std::swap(port[0], port[1]); - std::swap(latency[0], latency[1]); - } - - // Now add remote annotations. Rank goes in component[1], thread - // goes in latency[1], port[1] is not needed - component[1] = remote_rank_info.rank; - latency[1] = remote_rank_info.thread; - port[1].clear(); - - nonlocal = true; -} - -void -ConfigLink::updateLatencies() -{ - // Need to clean up some elements before we can test for zero latency - if ( order >= 1 ) { - latency[0] = ConfigLink::getLatencyFromIndex(latency[0]); - } - // If this is nonlocal, latency[1] holds the remote thread instead of the latency - if ( order >= 2 && !nonlocal ) { - latency[1] = ConfigLink::getLatencyFromIndex(latency[1]); - } -} - -void -ConfigStatistic::addParameter(const std::string& key, const std::string& value, bool overwrite) -{ - bool bk = params.enableVerify(false); - params.insert(key, value, overwrite); - params.enableVerify(bk); -} - -bool -ConfigStatGroup::addComponent(ComponentId_t id) -{ - if ( std::find(components.begin(), components.end(), id) == components.end() ) { - components.push_back(id); - } - return true; -} - -bool -ConfigStatGroup::addStatistic(const std::string& name, Params& p) -{ - statMap[name] = p; - if ( outputFrequency.getValue() == 0 ) { - /* aka, not yet really set to anything other than 0 */ - setFrequency(p.find("rate", "0ns")); - } - return true; -} - -bool -ConfigStatGroup::setOutput(size_t id) -{ - outputID = id; - return true; -} - -bool -ConfigStatGroup::setFrequency(const std::string& freq) -{ - UnitAlgebra uaFreq(freq); - if ( uaFreq.hasUnits("s") || uaFreq.hasUnits("hz") ) { - outputFrequency = uaFreq; - return true; - } - return false; -} - -std::pair -ConfigStatGroup::verifyStatsAndComponents(const ConfigGraph* graph) -{ - for ( auto id : components ) { - const ConfigComponent* comp = graph->findComponent(id); - if ( !comp ) { - std::stringstream ss; - ss << "Component id " << id << " is not a valid component"; - return std::make_pair(false, ss.str()); - } - for ( auto& statKV : statMap ) { - - bool ok = Factory::getFactory()->GetStatisticValidityAndEnableLevel(comp->type, statKV.first) != 255; - - if ( !ok ) { - std::stringstream ss; - ss << "Component " << comp->name << " does not support statistic " << statKV.first; - return std::make_pair(false, ss.str()); - } - } - } - - return std::make_pair(true, ""); -} - -void -ConfigPortModule::addParameter(const std::string& key, const std::string& value) -{ - params.insert(key, value); -} - -void -ConfigPortModule::addSharedParamSet(const std::string& set) -{ - params.addSharedParamSet(set); -} - -void -ConfigPortModule::setStatisticLoadLevel(const uint8_t level) -{ - stat_load_level = level; -} - -void -ConfigPortModule::enableAllStatistics(const SST::Params& params) -{ - all_stat_config.insert(params); -} - -void -ConfigPortModule::enableStatistic(const std::string& statistic_name, const SST::Params& params) -{ - auto iter = per_stat_configs.find(statistic_name); - if ( iter == per_stat_configs.end() ) { - per_stat_configs[statistic_name] = params; - } - else { - per_stat_configs[statistic_name].insert(params); - } -} - -void -ConfigComponent::print(std::ostream& os) const -{ - os << "Component " << name << " (id = " << std::hex << id << std::dec << ")" << std::endl; - os << " slot_num = " << slot_num << std::endl; - os << " type = " << type << std::endl; - os << " weight = " << weight << std::endl; - os << " rank = " << rank.rank << std::endl; - os << " thread = " << rank.thread << std::endl; - os << " Links:" << std::endl; - for ( size_t i = 0; i != links.size(); ++i ) { - os << " " << links[i]; - } - os << std::endl; - os << " Params:" << std::endl; - params.print_all_params(os, " "); - os << " statLoadLevel = " << (uint32_t)statLoadLevel << std::endl; - os << " enabledAllStats = " << enabledAllStats << std::endl; - os << " Params:" << std::endl; - allStatConfig.params.print_all_params(os, " "); - os << " Statistics:" << std::endl; - for ( auto& pair : enabledStatNames ) { - os << " " << pair.first << std::endl; - os << " Params:" << std::endl; - auto iter = statistics_.find(pair.second); - iter->second.params.print_all_params(os, " "); - } - os << " SubComponents:\n"; - for ( auto* sc : subComponents ) { - sc->print(os); - } -} - -ConfigComponent* -ConfigComponent::cloneWithoutLinks(ConfigGraph* new_graph) const -{ - ConfigComponent* ret = new ConfigComponent(); - ret->id = id; - ret->name = name; - ret->slot_num = slot_num; - ret->type = type; - ret->weight = weight; - ret->rank = rank; - ret->params = params; - ret->statLoadLevel = statLoadLevel; - ret->statistics_ = statistics_; - ret->enabledStatNames = enabledStatNames; - ret->enabledAllStats = enabledAllStats; - ret->allStatConfig = allStatConfig; - ret->coords = coords; - ret->nextSubID = nextSubID; - ret->graph = new_graph; - for ( auto* i : subComponents ) { - ret->subComponents.emplace_back(i->cloneWithoutLinks(new_graph)); - } - return ret; -} - -ConfigComponent* -ConfigComponent::cloneWithoutLinksOrParams(ConfigGraph* new_graph) const -{ - ConfigComponent* ret = new ConfigComponent(); - ret->id = id; - ret->name = name; - ret->slot_num = slot_num; - ret->type = type; - ret->weight = weight; - ret->rank = rank; - ret->statLoadLevel = statLoadLevel; - ret->coords = coords; - ret->nextSubID = nextSubID; - ret->graph = new_graph; - for ( auto* i : subComponents ) { - ret->subComponents.emplace_back(i->cloneWithoutLinksOrParams(new_graph)); - } - return ret; -} - -void -ConfigComponent::setConfigGraphPointer(ConfigGraph* graph_ptr) -{ - graph = graph_ptr; - for ( auto* x : subComponents ) { - x->setConfigGraphPointer(graph_ptr); - } -} - -ComponentId_t -ConfigComponent::getNextSubComponentID() -{ - // If we are the ultimate component, get nextSubID and increment - // for next time - if ( id == COMPONENT_ID_MASK(id) ) { - uint16_t subid = nextSubID; - nextSubID++; - return SUBCOMPONENT_ID_CREATE(id, subid); - } - else { - // Get the ultimate parent and call getNextSubComponentID on - // it - return graph->findComponent(COMPONENT_ID_MASK(id))->getNextSubComponentID(); - } -} - -StatisticId_t -ConfigComponent::getNextStatisticID() -{ - uint16_t statId = nextStatID++; - return STATISTIC_ID_CREATE(id, statId); -} - -ConfigComponent* -ConfigComponent::getParent() const -{ - if ( id == COMPONENT_ID_MASK(id) ) { - return nullptr; - } - return graph->findComponent((((ComponentId_t)nextSubID) << COMPONENT_ID_BITS) | COMPONENT_ID_MASK(id)); -} - -std::string -ConfigComponent::getFullName() const -{ - if ( id == COMPONENT_ID_MASK(id) ) { - // We are a component - return name; - } - - // Get full name of parent - std::string parent_name = getParent()->getFullName(); - - // For ConfigComponent, we will always put in [] for the slot number. - return parent_name + ":" + name + "[" + std::to_string(slot_num) + "]"; -} - -void -ConfigComponent::setRank(RankInfo r) -{ - rank = r; - for ( auto* i : subComponents ) { - i->setRank(r); - } + links_.clear(); + comps_.clear(); + // Init the statistic output settings + stats_config_ = new StatsConfig(); + stats_config_->load_level = STATISTICSDEFAULTLOADLEVEL; + stats_config_->outputs.emplace_back(STATISTICSDEFAULTOUTPUTNAME); + // Output is only used for warnings or fatal that should go to stderr + Output& o = Output::getDefaultObject(); + output.init(o.getPrefix(), o.getVerboseLevel(), o.getVerboseMask(), Output::STDERR); } -void -ConfigComponent::setWeight(double w) -{ - weight = w; - for ( auto* i : subComponents ) { - i->setWeight(w); - } -} - -void -ConfigComponent::setCoordinates(const std::vector& c) -{ - coords = c; - /* Maintain minimum of 3D information */ - while ( coords.size() < 3 ) - coords.push_back(0.0); -} - -void -ConfigComponent::addParameter(const std::string& key, const std::string& value, bool overwrite) -{ - bool bk = params.enableVerify(false); - params.insert(key, value, overwrite); - params.enableVerify(bk); -} - -ConfigStatistic* -ConfigComponent::createStatistic() -{ - StatisticId_t stat_id = getNextStatisticID(); - - auto* parent = getParent(); - ConfigStatistic* cs = nullptr; - if ( parent ) { - cs = parent->insertStatistic(stat_id); - } - else { - cs = &statistics_[stat_id]; - } - cs->id = stat_id; - return cs; -} - -ConfigStatistic* -ConfigComponent::enableStatistic(const std::string& statisticName, const SST::Params& params, bool recursively) -{ - // NOTE: For every statistic in the statistics List, there must be - // a corresponding params entry in enabledStatParams list. The two - // lists will always be the same size. - if ( recursively ) { - for ( auto* sc : subComponents ) { - sc->enableStatistic(statisticName, params, true); - } - } - StatisticId_t stat_id; - if ( statisticName == STATALLFLAG ) { - // Special sentinel id for enable all - // The ConfigStatistic object for STATALLFLAG is not an entry of the statistics - // It has its own ConfigStatistic as a member variable of ConfigComponent which must be used - // in case of enabledAllStats == true. - enabledAllStats = true; - allStatConfig.id = STATALL_ID; - allStatConfig.params.insert(params); - return &allStatConfig; - } - else { - // this is a valid statistic - auto iter = enabledStatNames.find(statisticName); - if ( iter == enabledStatNames.end() ) { - // this is the first time being enabled - stat_id = getNextStatisticID(); - enabledStatNames[statisticName] = stat_id; - auto* parent = getParent(); - if ( parent ) { - ConfigStatistic* cs = parent->insertStatistic(stat_id); - cs->id = stat_id; - cs->params.insert(params); - return cs; - } - } - else { - // this was already enabled - stat_id = iter->second; - } - } - - ConfigStatistic& cs = statistics_[stat_id]; - cs.id = stat_id; - cs.params.insert(params); - return &cs; -} - -bool -ConfigComponent::reuseStatistic(const std::string& statisticName, StatisticId_t sid) -{ - if ( statisticName == STATALLFLAG ) { - // We cannot use reuseStatistic with STATALLFLAG - Output::getDefaultObject().fatal(CALL_INFO, 1, "Cannot reuse a Statistic with STATALLFLAG as parameter"); - return false; - } - - auto* comp = this; - while ( comp->getParent() != nullptr ) { - comp = comp->getParent(); - } - - if ( !Factory::getFactory()->DoesComponentInfoStatisticNameExist(type, statisticName) ) { - Output::getDefaultObject().fatal(CALL_INFO, 1, - "Failed to create statistic '%s' on '%s' of type '%s' - this is not a valid statistic\n", - statisticName.c_str(), name.c_str(), type.c_str()); - return false; - } - - auto iter = comp->statistics_.find(sid); - if ( iter == comp->statistics_.end() ) { - Output::getDefaultObject().fatal(CALL_INFO, 1, "Cannot reuse a statistic that doesn't exist for the parent"); - return false; - } - else { - enabledStatNames[statisticName] = sid; - return true; - } -} - -void -ConfigComponent::addStatisticParameter( - const std::string& statisticName, const std::string& param, const std::string& value, bool recursively) -{ - // NOTE: For every statistic in the statistics map, there must be - // a corresponding params entry in enabledStatParams list. The two - // lists will always be the same size. - if ( recursively ) { - for ( auto* sc : subComponents ) { - sc->addStatisticParameter(statisticName, param, value, true); - } - } - - ConfigStatistic* cs = nullptr; - if ( statisticName == STATALLFLAG ) { - cs = &allStatConfig; - } - else { - cs = findStatistic(statisticName); - } - if ( !cs ) { - Output::getDefaultObject().fatal( - CALL_INFO, 1, "cannot add parameter '%s' to unknown statistic '%s'", param.c_str(), statisticName.c_str()); - } - cs->params.insert(param, value); -} - -void -ConfigComponent::setStatisticParameters(const std::string& statisticName, const Params& params, bool recursively) -{ - if ( recursively ) { - for ( auto* sc : subComponents ) { - sc->setStatisticParameters(statisticName, params, true); - } - } - - if ( statisticName == STATALLFLAG ) { - allStatConfig.params.insert(params); - ; - } - else { - findStatistic(statisticName)->params.insert(params); - } -} - -void -ConfigComponent::setStatisticLoadLevel(uint8_t level, bool recursively) -{ - statLoadLevel = level; - - if ( recursively ) { - for ( auto* sc : subComponents ) { - sc->setStatisticLoadLevel(level, true); - } - } -} - -ConfigComponent* -ConfigComponent::addSubComponent(const std::string& name, const std::string& type, int slot_num) -{ - ComponentId_t sid = getNextSubComponentID(); - /* Check for existing subComponent with this name */ - for ( auto* i : subComponents ) { - if ( i->name == name && i->slot_num == slot_num ) return nullptr; - } - - uint16_t parent_sub_id = SUBCOMPONENT_ID_MASK(id); - - subComponents.push_back( - new ConfigComponent(sid, graph, parent_sub_id, name, slot_num, type, this->weight, this->rank)); - - return subComponents.back(); -} - -ConfigComponent* -ConfigComponent::findSubComponent(ComponentId_t sid) +ConfigGraph::~ConfigGraph() { - return const_cast(const_cast(this)->findSubComponent(sid)); -} - -const ConfigComponent* -ConfigComponent::findSubComponent(ComponentId_t sid) const -{ - if ( sid == this->id ) return this; - - for ( auto* s : subComponents ) { - const ConfigComponent* res = s->findSubComponent(sid); - if ( res != nullptr ) return res; - } - - return nullptr; -} - -ConfigComponent* -ConfigComponent::findSubComponentByName(const std::string& name) -{ - size_t colon_index = name.find(":"); - std::string slot = name.substr(0, colon_index); - - // Get the slot number - int slot_num = 0; - size_t bracket_index = slot.find("["); - if ( bracket_index == std::string::npos ) { - // No brackets, slot_num 0 - slot_num = 0; - } - else { - size_t close_index = slot.find("]"); - size_t length = close_index - bracket_index - 1; - slot_num = Core::from_string(slot.substr(bracket_index + 1, length)); - slot = slot.substr(0, bracket_index); - } - - // Now, see if we have something in this slot and slot_num - for ( auto* sc : subComponents ) { - if ( sc->name == slot && sc->slot_num == slot_num ) { - // Found the subcomponent - if ( colon_index == std::string::npos ) { - // Last level of hierarchy - return sc; - } - else { - return sc->findSubComponentByName(name.substr(colon_index + 1, std::string::npos)); - } - } + for ( auto comp : comps_ ) { + delete comp; } - return nullptr; -} -ConfigStatistic* -ConfigComponent::insertStatistic(StatisticId_t sid) -{ - ConfigComponent* parent = getParent(); - if ( parent ) { - return parent->insertStatistic(sid); - } - else { - return &statistics_[sid]; - } + if ( stats_config_ ) delete stats_config_; } -ConfigStatistic* -ConfigComponent::findStatistic(const std::string& name) const +std::vector& +ConfigGraph::getStatOutputs() { - auto iter = enabledStatNames.find(name); - if ( iter != enabledStatNames.end() ) { - StatisticId_t id = iter->second; - return findStatistic(id); - } - else { - return nullptr; - } + return stats_config_->outputs; } -ConfigStatistic* -ConfigComponent::findStatistic(StatisticId_t sid) const +const ConfigStatOutput& +ConfigGraph::getStatOutput(size_t index) const { - auto* parent = getParent(); - if ( parent ) { - return parent->findStatistic(sid); - } - else { - auto iter = statistics_.find(sid); - if ( iter == statistics_.end() ) { - return nullptr; - } - else { - // I hate that I have to do this - return const_cast(&iter->second); - } - } + return stats_config_->outputs[index]; } -size_t -ConfigComponent::addPortModule(const std::string& port, const std::string& type, const Params& params) +long +ConfigGraph::getStatLoadLevel() const { - port_modules[port].emplace_back(type, params); - return port_modules.size() - 1; + return stats_config_->load_level; } -std::vector -ConfigComponent::allLinks() const +const std::map& +ConfigGraph::getStatGroups() const { - std::vector res; - res.insert(res.end(), links.begin(), links.end()); - for ( auto* sc : subComponents ) { - std::vector s = sc->allLinks(); - res.insert(res.end(), s.begin(), s.end()); - } - return res; + return stats_config_->groups; } -std::vector -ConfigComponent::clearAllLinks() +ConfigStatGroup* +ConfigGraph::getStatGroup(const std::string& name) { - std::vector res; - res.insert(res.end(), links.begin(), links.end()); - links.clear(); - for ( auto* sc : subComponents ) { - std::vector s = sc->clearAllLinks(); - res.insert(res.end(), s.begin(), s.end()); + auto found = stats_config_->groups.find(name); + if ( found == stats_config_->groups.end() ) { + bool ok; + std::tie(found, ok) = stats_config_->groups.emplace(name, name); } - return res; + return &(found->second); } -void -ConfigComponent::checkPorts() const -{ - std::map ports; - - auto& graph_links = graph->getLinkMap(); - - // Loop over all the links - for ( unsigned int i = 0; i < links.size(); i++ ) { - const ConfigLink* link = graph_links[links[i]]; - for ( int j = 0; j < 2; j++ ) { - - if ( link->component[j] == id ) { - // If port is not found, print an error - if ( !Factory::getFactory()->isPortNameValid(type, link->port[j]) ) { - // For now this is not a fatal error - // found_error = true; - Output::getDefaultObject().fatal(CALL_INFO, 1, - "ERROR: Attempting to connect to unknown port: %s, " - "in component %s of type %s.\n", - link->port[j].c_str(), name.c_str(), type.c_str()); - } - - // Check for multiple links hooked to port - auto ret = ports.insert(std::make_pair(link->port[j], link->name)); - if ( !ret.second ) { - // Check to see if this is a loopback link - if ( ret.first->second != link->name ) - // Not a loopback link, fatal... - Output::getDefaultObject().fatal(CALL_INFO, 1, - "ERROR: Port %s of Component %s connected to two links: %s, %s.\n", link->port[j].c_str(), - name.c_str(), link->name.c_str(), ret.first->second.c_str()); - } - } - } - } - - // Now loop over all subcomponents and call the check function - for ( auto* subcomp : subComponents ) { - subcomp->checkPorts(); - } -} size_t ConfigGraph::getNumComponentsInMPIRank(uint32_t rank) @@ -1251,8 +612,6 @@ ConfigGraph::splitGraph(const std::set& orig_rank_set, const std::set< // However, for now, we need to leave all stat group information on rank 0 so that all statgroups get checkpointed // (only rank 0 adds statgroups to the checkpoint) - // for ( auto& kv : this->statGroups ) { - bool orig_includes_zero = orig_rank_set.count(0); bool new_includes_zero = new_rank_set.count(0); for ( auto it = this->stats_config_->groups.begin(); it != this->stats_config_->groups.end(); diff --git a/src/sst/core/model/configGraph.h b/src/sst/core/model/configGraph.h new file mode 100644 index 000000000..a680b2b11 --- /dev/null +++ b/src/sst/core/model/configGraph.h @@ -0,0 +1,324 @@ +// -*- c++ -*- + +// Copyright 2009-2025 NTESS. Under the terms +// of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Copyright (c) 2009-2025, NTESS +// All rights reserved. +// +// This file is part of the SST software package. For license +// information, see the LICENSE file in the top level directory of the +// distribution. + +#ifndef SST_CORE_MODEL_CONFIGGRAPH_H +#define SST_CORE_MODEL_CONFIGGRAPH_H + +#include "sst/core/model/configComponent.h" +#include "sst/core/model/configLink.h" +#include "sst/core/model/configStatistic.h" +#include "sst/core/params.h" +#include "sst/core/rankInfo.h" +#include "sst/core/serialization/serializable.h" +#include "sst/core/sparseVectorMap.h" +#include "sst/core/sst_types.h" +#include "sst/core/statapi/statbase.h" +#include "sst/core/statapi/statoutput.h" +#include "sst/core/timeConverter.h" +#include "sst/core/unitAlgebra.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace SST::Statistics; + +namespace SST { + +class Simulation_impl; + +class Config; +class TimeLord; +struct StatsConfig; +class ConfigComponent; + +using ComponentIdMap_t = SparseVectorMap; +using LinkIdMap_t = std::vector; + +class ConfigLink; + + +using ConfigLinkMap_t = SparseVectorMap; + +/** Map names to Links */ +/** Map IDs to Components */ +using ConfigComponentMap_t = SparseVectorMap; +/** Map names to Components */ +using ConfigComponentNameMap_t = std::map; +/** Map names to Parameter Sets: XML only */ +using ParamsMap_t = std::map; +/** Map names to variable values: XML only */ +using VariableMap_t = std::map; + +class PartitionGraph; + + +/** A Configuration Graph + * A graph representing Components and Links + */ +class ConfigGraph : public SST::Core::Serialization::serializable +{ +public: + /** Print the configuration graph */ + void print(std::ostream& os) const + { + os << "Printing graph" << std::endl; + os << "Components:" << std::endl; + for ( ConfigComponentMap_t::const_iterator i = comps_.begin(); i != comps_.end(); ++i ) { + (*i)->print(os); + } + os << "Links:" << std::endl; + for ( auto i = links_.begin(); i != links_.end(); ++i ) { + (*i)->print(os); + } + } + + ConfigGraph(); + ~ConfigGraph(); + + size_t getNumComponents() { return comps_.data.size(); } + + size_t getNumComponentsInMPIRank(uint32_t rank); + + /** Helper function to set all the ranks to the same value */ + void setComponentRanks(RankInfo rank); + /** Checks to see if rank contains at least one component */ + bool containsComponentInRank(RankInfo rank); + /** Verify that all components have valid Ranks assigned */ + bool checkRanks(RankInfo ranks); + + // API for programmatic initialization + /** Create a new component */ + ComponentId_t addComponent(const std::string& name, const std::string& type); + + /** Add a parameter to a shared param set */ + void addSharedParam(const std::string& shared_set, const std::string& key, const std::string& value); + + [[deprecated("addGlobalParam() has been deprecated and will be removed in SST 16. Please use addSharedParam()")]] + void addGlobalParam(const std::string& shared_set, const std::string& key, const std::string& value); + + /** Set the statistic output module */ + void setStatisticOutput(const std::string& name); + + /** Add parameter to the statistic output module */ + void addStatisticOutputParameter(const std::string& param, const std::string& value); + + /** Set a set of parameter to the statistic output module */ + void setStatisticOutputParams(const Params& p); + + /** Set the statistic system load level */ + void setStatisticLoadLevel(uint8_t loadLevel); + + std::vector& getStatOutputs(); + + const ConfigStatOutput& getStatOutput(size_t index = 0) const; + + long getStatLoadLevel() const; + + /** + Create link and return it's ID. The provided name is not + checked against existing links + */ + LinkId_t createLink(const char* name, const char* latency = nullptr); + + /** Add a Link to a Component on a given Port */ + void addLink(ComponentId_t comp_id, LinkId_t link_id, const char* port, const char* latency_str); + + /** + Adds the remote rank info for nonlocal links + */ + void addNonLocalLink(LinkId_t link_id, int rank, int thread); + + /** Set a Link to be no-cut */ + void setLinkNoCut(LinkId_t link_name); + + /** Perform any post-creation cleanup processes */ + void postCreationCleanup(); + + /** Check the graph for Structural errors */ + bool checkForStructuralErrors(); + + // Temporary until we have a better API + /** Return the map of components */ + ConfigComponentMap_t& getComponentMap() { return comps_; } + + const std::map& getStatGroups() const; + ConfigStatGroup* getStatGroup(const std::string& name); + + bool containsComponent(ComponentId_t id) const; + ConfigComponent* findComponent(ComponentId_t); + ConfigComponent* findComponentByName(const std::string& name); + const ConfigComponent* findComponent(ComponentId_t) const; + + ConfigStatistic* findStatistic(StatisticId_t) const; + + /** Return the map of links */ + ConfigLinkMap_t& getLinkMap() { return links_; } + + ConfigGraph* splitGraph(const std::set& orig_rank_set, const std::set& new_rank_set); + void reduceGraphToSingleRank(uint32_t rank); + + SimTime_t getMinimumPartitionLatency(); + + PartitionGraph* getPartitionGraph(); + PartitionGraph* getCollapsedPartitionGraph(); + void annotateRanks(PartitionGraph* graph); + void getConnectedNoCutComps(ComponentId_t start, std::set& group); + StatsConfig* getStatsConfig() { return stats_config_; } + StatsConfig* takeStatsConfig() + { + auto* ret = stats_config_; + stats_config_ = nullptr; + return ret; + } + + void setComponentConfigGraphPointers(); + void serialize_order(SST::Core::Serialization::serializer& ser) override + { + SST_SER(links_); + SST_SER(comps_); + SST_SER(stats_config_); + if ( ser.mode() == SST::Core::Serialization::serializer::UNPACK ) { + // Need to reinitialize the ConfigGraph ptrs in the + // ConfigComponents + setComponentConfigGraphPointers(); + } + + SST_SER(cpt_ranks); + SST_SER(cpt_currentSimCycle); + SST_SER(cpt_currentPriority); + SST_SER(cpt_minPart); + SST_SER(cpt_minPartTC); + SST_SER(cpt_max_event_id); + + SST_SER(*(cpt_libnames.get())); + SST_SER(*(cpt_shared_objects.get())); + SST_SER(*(cpt_stats_config.get())); + } + + void restoreRestartData(); + + /********* vv Variables used on restarts only vv ***********/ + RankInfo cpt_ranks; + SimTime_t cpt_currentSimCycle = 0; + int cpt_currentPriority = 0; + SimTime_t cpt_minPart = std::numeric_limits::max(); + TimeConverter cpt_minPartTC; + uint64_t cpt_max_event_id = 0; + + std::shared_ptr> cpt_libnames = std::make_shared>(); + std::shared_ptr> cpt_shared_objects = std::make_shared>(); + std::shared_ptr> cpt_stats_config = std::make_shared>(); + + /********* ^^ Variables used on restarts only ^^ ***********/ + + +private: + friend class Simulation_impl; + + Output output; + + ComponentId_t nextComponentId; + + ConfigLinkMap_t links_; // SparseVectorMap + ConfigComponentMap_t comps_; // SparseVectorMap + ConfigComponentNameMap_t comps_by_name_; // std::map + + std::map link_names_; + + StatsConfig* stats_config_; + + ImplementSerializable(SST::ConfigGraph) + + // Filter class + class GraphFilter + { + ConfigGraph* ograph_; + ConfigGraph* ngraph_; + const std::set& oset_; + const std::set& nset_; + + public: + GraphFilter(ConfigGraph* original_graph, ConfigGraph* new_graph, const std::set& original_rank_set, + const std::set& new_rank_set); + + ConfigLink* operator()(ConfigLink* link); + ConfigComponent* operator()(ConfigComponent* comp); + }; +}; + +class PartitionComponent +{ +public: + ComponentId_t id; + float weight; + RankInfo rank; + LinkIdMap_t links; + + ComponentIdMap_t group; + + explicit PartitionComponent(const ConfigComponent* cc) + { + id = cc->id; + weight = cc->weight; + rank = cc->rank; + } + + explicit PartitionComponent(LinkId_t id) : + id(id), + weight(0), + rank(RankInfo(RankInfo::UNASSIGNED, 0)) + {} + + // PartitionComponent(ComponentId_t id, ConfigGraph* graph, const ComponentIdMap_t& group); + void print(std::ostream& os, const PartitionGraph* graph) const; + + inline ComponentId_t key() const { return id; } +}; + +using PartitionComponentMap_t = SparseVectorMap; +using PartitionLinkMap_t = SparseVectorMap; + +class PartitionGraph +{ +private: + PartitionComponentMap_t comps_; + PartitionLinkMap_t links_; + +public: + /** Print the configuration graph */ + void print(std::ostream& os) const + { + os << "Printing graph" << std::endl; + for ( PartitionComponentMap_t::const_iterator i = comps_.begin(); i != comps_.end(); ++i ) { + (*i)->print(os, this); + } + } + + PartitionComponentMap_t& getComponentMap() { return comps_; } + PartitionLinkMap_t& getLinkMap() { return links_; } + + const PartitionLink& getLink(LinkId_t id) const { return links_[id]; } + + size_t getNumComponents() { return comps_.size(); } +}; + +} // namespace SST + +#endif // SST_CORE_MODEL_CONFIGGRAPH_H diff --git a/src/sst/core/model/configLink.cc b/src/sst/core/model/configLink.cc new file mode 100644 index 000000000..1ecb3da0e --- /dev/null +++ b/src/sst/core/model/configLink.cc @@ -0,0 +1,104 @@ +// Copyright 2009-2025 NTESS. Under the terms +// of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Copyright (c) 2009-2025, NTESS +// All rights reserved. +// +// This file is part of the SST software package. For license +// information, see the LICENSE file in the top level directory of the +// distribution. + +#include "sst_config.h" + +#include "sst/core/model/configLink.h" + +#include "sst/core/simulation_impl.h" +#include "sst/core/timeLord.h" +#include "sst/core/warnmacros.h" + +#include +#include +#include +#include +#include + +namespace SST { +std::map ConfigLink::lat_to_index; + +uint32_t +ConfigLink::getIndexForLatency(const char* latency) +{ + std::string lat(latency); + uint32_t& index = lat_to_index[lat]; + if ( index == 0 ) { + // Wasn't there, set it to lat_to_index.size(), which is the + // next index (skipping zero as that is the check for a new + // entry) + index = lat_to_index.size(); + } + return index; +} + +std::vector +ConfigLink::initializeLinkLatencyVector() +{ + TimeLord* timeLord = Simulation_impl::getTimeLord(); + std::vector vec; + vec.resize(lat_to_index.size() + 1); + for ( auto& [lat, index] : lat_to_index ) { + vec[index] = timeLord->getSimCycles(lat, __FUNCTION__); + } + return vec; +} + +SimTime_t +ConfigLink::getLatencyFromIndex(uint32_t index) +{ + static std::vector vec = initializeLinkLatencyVector(); + return vec[index]; +} + +std::string +ConfigLink::latency_str(uint32_t index) const +{ + static TimeLord* timelord = Simulation_impl::getTimeLord(); + UnitAlgebra tb = timelord->getTimeBase(); + auto tmp = tb * latency[index]; + return tmp.toStringBestSI(); +} + +void +ConfigLink::setAsNonLocal(int which_local, RankInfo remote_rank_info) +{ + // First, if which_local != 0, we need to swap the data for index + // 0 and 1 + if ( which_local == 1 ) { + std::swap(component[0], component[1]); + std::swap(port[0], port[1]); + std::swap(latency[0], latency[1]); + } + + // Now add remote annotations. Rank goes in component[1], thread + // goes in latency[1], port[1] is not needed + component[1] = remote_rank_info.rank; + latency[1] = remote_rank_info.thread; + port[1].clear(); + + nonlocal = true; +} + +void +ConfigLink::updateLatencies() +{ + // Need to clean up some elements before we can test for zero latency + if ( order >= 1 ) { + latency[0] = ConfigLink::getLatencyFromIndex(latency[0]); + } + // If this is nonlocal, latency[1] holds the remote thread instead of the latency + if ( order >= 2 && !nonlocal ) { + latency[1] = ConfigLink::getLatencyFromIndex(latency[1]); + } +} + +} // namespace SST diff --git a/src/sst/core/model/configLink.h b/src/sst/core/model/configLink.h new file mode 100644 index 000000000..df4ca5058 --- /dev/null +++ b/src/sst/core/model/configLink.h @@ -0,0 +1,290 @@ +// -*- c++ -*- + +// Copyright 2009-2025 NTESS. Under the terms +// of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Copyright (c) 2009-2025, NTESS +// All rights reserved. +// +// This file is part of the SST software package. For license +// information, see the LICENSE file in the top level directory of the +// distribution. + +#ifndef SST_CORE_MODEL_CONFIGLINK_H +#define SST_CORE_MODEL_CONFIGLINK_H + +#include "sst/core/rankInfo.h" +#include "sst/core/sst_types.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace SST { +namespace Core::Serialization { +class serializer; +} + +/** Represents the configuration of a generic Link */ +class ConfigLink +{ + // Static data structures to map latency string to an index that + // will hold the SimTime_t for the latency once the atomic + // timebase has been set. + static std::map lat_to_index; + + static uint32_t getIndexForLatency(const char* latency); + static std::vector initializeLinkLatencyVector(); + SimTime_t getLatencyFromIndex(uint32_t index); + + /********* vv Member variables vv ***********/ + +public: + /** + Components that are connected to this link. They are filled in + the order they are attached in. If the link is marked as + non-local, then component[1] holds the rank of the remote + component. + */ + ComponentId_t component[2] = { 0, 0 }; /*!< IDs of the connected components */ + + /** + This is a dual purpose data member. + + Graph construction - during graph construction, it holds the + index into the LinkLatencyVector, which maps the stored index + to the actual latency string. This is done to reduce memory + usage because we assume there will be a small number of + different latencies specified. + + Post graph construction - after graph construction, the latency + index is replaced with the SimTime_t value representing the + specified latency that will be used by the link to add the + specified latency to the event. + + In both cases, the indices match the indices found in the + component array, and represent the latency of the link for + events sent from the corresponding component. + + If the link is marked as non-local, then latency[1] holds the + thread of the remote component. + */ + SimTime_t latency[2] = { 0, 0 }; + + /** + Name of the link. This is used in three cases: + + Errors - if an error is found in the graph construction, the + name is used to report the error to the user + + Link ordering - the event ordering for links is based on the + alphabetized name of the links. The links are sorted by name + and order is assigned linearly starting at 1 + + Parallel load - for parallel load, links that cross partition + boundaries are connected by matching link names + + Link names are not carried over to the simulation objects + */ + std::string name; + + /** + id of the link. This is used primarily to find the link in ConfigGraph::links. For parallel loads, the link ID + is only unique on a given rank, not globally. + + The ID's are not carried over to the simulation objects + */ + LinkId_t id = 0; + + /** + This is a dual purpose data member. During graph construction, + it counts the number of components currently referencing this + link. After graph construction, it is assigned the value used + to enforce ordering of events based on the links they were sent + on. + + @see Activity::setOrderTag, Link::tag + */ + LinkId_t order = 0; + + /** + Name of the ports the link is connected to. The indices match + the ones used in the component array + */ + std::string port[2]; + + /** + Whether or not this link is set to be no-cut + */ + bool no_cut = false; + + /** + Whether this link crosses the graph boundary and is connected + on one end to a non-local component. If set to true, there + will only be one component connected (information in index 0 + for the arrays) and the rank for the remote component will be + stored in component[1] and the thread in latency[1]. + */ + bool nonlocal = false; + + /** + Set to true if this is a cross rank link + */ + bool cross_rank = false; + + /** + Set to true if this is a cross thread link on same rank + */ + bool cross_thread = false; + + /********* ^^ Member variables ^^ ***********/ + + + /** + Function used when storing ConfigLinks in a SparseVectorMap + */ + inline LinkId_t key() const { return id; } + + /** + Return the minimum latency of this link (from both sides). For non local links, it will return the local latency + */ + SimTime_t getMinLatency() const + { + if ( nonlocal ) return latency[0]; + if ( latency[0] < latency[1] ) return latency[0]; + return latency[1]; + } + + /** + Gets the latency as a string from the id stored in latency[]. This is only allowed to be called during graph + construction. After post-graph construction checks, the latency[] array no longer hold indices to the strings. + + @see latency + */ + std::string latency_str(uint32_t index) const; + + /** + Sets the link as a non-local link. After the call, the local information will be held in index 0 of the various + arrays, regardless of which component index holds the local information before the call. + + @param which_local specifies which index is for the local side of the link + + @param remote_rank_info Rank of the remote side of the link + */ + void setAsNonLocal(int which_local, RankInfo remote_rank_info); + + /** + Print the Link information + */ + void print(std::ostream& os) const + { + os << "Link " << name << " (id = " << id << ")" << std::endl; + os << " nonlocal = " << nonlocal << std::endl; + os << " component[0] = " << component[0] << std::endl; + os << " port[0] = " << port[0] << std::endl; + os << " latency[0] = " << latency[0] << std::endl; + os << " component[1] = " << component[1] << std::endl; + os << " port[1] = " << port[1] << std::endl; + os << " latency[1] = " << latency[1] << std::endl; + } + + /* Do not use. For serialization only */ + ConfigLink() {} + + /** + Serializes the ConfigLink + */ + void serialize_order(SST::Core::Serialization::serializer& ser) /*override*/ + { + SST_SER(id); + SST_SER(name); + SST_SER(component[0]); + SST_SER(component[1]); + SST_SER(port[0]); + SST_SER(port[1]); + SST_SER(latency[0]); + SST_SER(latency[1]); + SST_SER(order); + SST_SER(nonlocal); + SST_SER(no_cut); + SST_SER(cross_rank); + SST_SER(cross_thread); + } + +private: + friend class ConfigGraph; + explicit ConfigLink(LinkId_t id) : + id(id), + no_cut(false) + { + order = 0; + + // Initialize the component data items + component[0] = ULONG_MAX; + component[1] = ULONG_MAX; + } + + ConfigLink(LinkId_t id, const std::string& n) : + id(id), + no_cut(false) + { + order = 0; + name = n; + + // Initialize the component data items + component[0] = ULONG_MAX; + component[1] = ULONG_MAX; + } + + void updateLatencies(); +}; + + +class PartitionLink +{ +public: + LinkId_t id; + ComponentId_t component[2]; + SimTime_t latency[2]; + bool no_cut; + + PartitionLink(const ConfigLink& cl) + { + id = cl.id; + component[0] = cl.component[0]; + component[1] = cl.component[1]; + latency[0] = cl.latency[0]; + latency[1] = cl.latency[1]; + no_cut = cl.no_cut; + } + + inline LinkId_t key() const { return id; } + + /** Return the minimum latency of this link (from both sides) */ + SimTime_t getMinLatency() const + { + if ( latency[0] < latency[1] ) return latency[0]; + return latency[1]; + } + + /** Print the Link information */ + void print(std::ostream& os) const + { + os << " Link " << id << std::endl; + os << " component[0] = " << component[0] << std::endl; + os << " latency[0] = " << latency[0] << std::endl; + os << " component[1] = " << component[1] << std::endl; + os << " latency[1] = " << latency[1] << std::endl; + } +}; + +} // namespace SST + +#endif // SST_CORE_MODEL_CONFIGLINK_H diff --git a/src/sst/core/model/configStatistic.cc b/src/sst/core/model/configStatistic.cc new file mode 100644 index 000000000..5410aff25 --- /dev/null +++ b/src/sst/core/model/configStatistic.cc @@ -0,0 +1,104 @@ +// Copyright 2009-2025 NTESS. Under the terms +// of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Copyright (c) 2009-2025, NTESS +// All rights reserved. +// +// This file is part of the SST software package. For license +// information, see the LICENSE file in the top level directory of the +// distribution. + +#include "sst_config.h" + +#include "sst/core/config.h" + +#include "sst/core/component.h" +#include "sst/core/factory.h" +#include "sst/core/from_string.h" +#include "sst/core/model/configComponent.h" +#include "sst/core/model/configGraph.h" +#include "sst/core/namecheck.h" +#include "sst/core/simulation_impl.h" +#include "sst/core/timeLord.h" +#include "sst/core/warnmacros.h" + +#include +#include +#include +#include +#include + +namespace SST { + +void +ConfigStatistic::addParameter(const std::string& key, const std::string& value, bool overwrite) +{ + bool bk = params.enableVerify(false); + params.insert(key, value, overwrite); + params.enableVerify(bk); +} + +bool +ConfigStatGroup::addComponent(ComponentId_t id) +{ + if ( std::find(components.begin(), components.end(), id) == components.end() ) { + components.push_back(id); + } + return true; +} + +bool +ConfigStatGroup::addStatistic(const std::string& name, Params& p) +{ + statMap[name] = p; + if ( outputFrequency.getValue() == 0 ) { + /* aka, not yet really set to anything other than 0 */ + setFrequency(p.find("rate", "0ns")); + } + return true; +} + +bool +ConfigStatGroup::setOutput(size_t id) +{ + outputID = id; + return true; +} + +bool +ConfigStatGroup::setFrequency(const std::string& freq) +{ + UnitAlgebra uaFreq(freq); + if ( uaFreq.hasUnits("s") || uaFreq.hasUnits("hz") ) { + outputFrequency = uaFreq; + return true; + } + return false; +} + +std::pair +ConfigStatGroup::verifyStatsAndComponents(const ConfigGraph* graph) +{ + for ( auto id : components ) { + const ConfigComponent* comp = graph->findComponent(id); + if ( !comp ) { + std::stringstream ss; + ss << "Component id " << id << " is not a valid component"; + return std::make_pair(false, ss.str()); + } + for ( auto& statKV : statMap ) { + + bool ok = Factory::getFactory()->GetStatisticValidityAndEnableLevel(comp->type, statKV.first) != 255; + + if ( !ok ) { + std::stringstream ss; + ss << "Component " << comp->name << " does not support statistic " << statKV.first; + return std::make_pair(false, ss.str()); + } + } + } + + return std::make_pair(true, ""); +} +} // namespace SST diff --git a/src/sst/core/model/configStatistic.h b/src/sst/core/model/configStatistic.h new file mode 100644 index 000000000..9538ab932 --- /dev/null +++ b/src/sst/core/model/configStatistic.h @@ -0,0 +1,158 @@ +// -*- c++ -*- + +// Copyright 2009-2025 NTESS. Under the terms +// of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Copyright (c) 2009-2025, NTESS +// All rights reserved. +// +// This file is part of the SST software package. For license +// information, see the LICENSE file in the top level directory of the +// distribution. + +#ifndef SST_CORE_CONFIGCSTATISTIC_H +#define SST_CORE_CONFIGCSTATISTIC_H + +#include "sst/core/params.h" +#include "sst/core/serialization/serializable.h" +#include "sst/core/sst_types.h" +#include "sst/core/statapi/statbase.h" +#include "sst/core/statapi/statoutput.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace SST::Statistics; + +namespace SST { + +class ConfigGraph; +class ConfigLink; + +class ConfigStatistic : public SST::Core::Serialization::serializable +{ +public: + StatisticId_t id; /*!< Unique ID of this statistic */ + Params params; + bool shared = false; + std::string name; + + ConfigStatistic(StatisticId_t _id, bool _shared = false, std::string _name = "") : + id(_id), + shared(_shared), + name(_name) + {} + + ConfigStatistic() : + id(stat_null_id) + {} + + ConfigStatistic(const ConfigStatistic&) = default; + ConfigStatistic(ConfigStatistic&&) = default; + ConfigStatistic& operator=(const ConfigStatistic&) = default; + ConfigStatistic& operator=(ConfigStatistic&&) = default; + ~ConfigStatistic() override = default; + + inline const StatisticId_t& getId() const { return id; } + + void addParameter(const std::string& key, const std::string& value, bool overwrite); + + void serialize_order(SST::Core::Serialization::serializer& ser) override + { + SST_SER(id); + SST_SER(shared); + SST_SER(name); + SST_SER(params); + } + + ImplementSerializable(ConfigStatistic) + + static constexpr StatisticId_t stat_null_id = std::numeric_limits::max(); +}; + +class ConfigStatGroup : public SST::Core::Serialization::serializable +{ +public: + std::string name; + std::map statMap; + std::vector components; + size_t outputID; + UnitAlgebra outputFrequency; + + explicit ConfigStatGroup(const std::string& name) : + name(name), + outputID(0) + {} + ConfigStatGroup() {} /* Do not use */ + + bool addComponent(ComponentId_t id); + bool addStatistic(const std::string& name, Params& p); + bool setOutput(size_t id); + bool setFrequency(const std::string& freq); + + /** + * Checks to make sure that all components in the group support all + * of the statistics as configured in the group. + * @return pair of: bool for OK, string for error message (if any) + */ + std::pair verifyStatsAndComponents(const ConfigGraph* graph); + + void serialize_order(SST::Core::Serialization::serializer& ser) override + { + SST_SER(name); + SST_SER(statMap); + SST_SER(components); + SST_SER(outputID); + SST_SER(outputFrequency); + } + + ImplementSerializable(SST::ConfigStatGroup) +}; + +class ConfigStatOutput : public SST::Core::Serialization::serializable +{ +public: + std::string type; + Params params; + + explicit ConfigStatOutput(const std::string& type) : + type(type) + {} + ConfigStatOutput() {} + + void addParameter(const std::string& key, const std::string& val) { params.insert(key, val); } + + void serialize_order(SST::Core::Serialization::serializer& ser) override + { + SST_SER(type); + SST_SER(params); + } + + ImplementSerializable(SST::ConfigStatOutput) +}; + +struct StatsConfig +{ + std::map groups; + std::vector outputs; // [0] is default group + uint8_t load_level; + + void serialize_order(SST::Core::Serialization::serializer& ser) + { + SST_SER(groups); + SST_SER(outputs); + SST_SER(load_level); + } +}; + +} // namespace SST + +#endif // SST_CORE_CONFIGCOMPONENT_H diff --git a/src/sst/core/model/json/jsonmodel.h b/src/sst/core/model/json/jsonmodel.h index cb531145e..c61b43e1c 100644 --- a/src/sst/core/model/json/jsonmodel.h +++ b/src/sst/core/model/json/jsonmodel.h @@ -16,10 +16,10 @@ #include "sst/core/component.h" #include "sst/core/config.h" -#include "sst/core/configGraph.h" #include "sst/core/cputimer.h" #include "sst/core/factory.h" #include "sst/core/memuse.h" +#include "sst/core/model/configGraph.h" #include "sst/core/model/sstmodel.h" #include "sst/core/output.h" #include "sst/core/rankInfo.h" diff --git a/src/sst/core/model/python/pymodel.cc b/src/sst/core/model/python/pymodel.cc index 3c8baa3ac..277f297f8 100644 --- a/src/sst/core/model/python/pymodel.cc +++ b/src/sst/core/model/python/pymodel.cc @@ -16,11 +16,11 @@ #include "sst/core/model/python/pymodel.h" #include "sst/core/component.h" -#include "sst/core/configGraph.h" #include "sst/core/cputimer.h" #include "sst/core/factory.h" #include "sst/core/from_string.h" #include "sst/core/memuse.h" +#include "sst/core/model/configGraph.h" #include "sst/core/model/element_python.h" #include "sst/core/model/python/pymacros.h" #include "sst/core/model/python/pymodel_comp.h" diff --git a/src/sst/core/model/python/pymodel.h b/src/sst/core/model/python/pymodel.h index 771a4f719..39c7b0c47 100644 --- a/src/sst/core/model/python/pymodel.h +++ b/src/sst/core/model/python/pymodel.h @@ -19,7 +19,7 @@ // #ifdef SST_CONFIG_HAVE_PYTHON #include "sst/core/config.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/model/sstmodel.h" #include "sst/core/output.h" #include "sst/core/rankInfo.h" diff --git a/src/sst/core/model/python/pymodel_comp.cc b/src/sst/core/model/python/pymodel_comp.cc index e566fdbc8..8ca6ec0d0 100644 --- a/src/sst/core/model/python/pymodel_comp.cc +++ b/src/sst/core/model/python/pymodel_comp.cc @@ -17,7 +17,7 @@ #include "sst/core/component.h" #include "sst/core/componentInfo.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/model/python/pymacros.h" #include "sst/core/model/python/pymodel.h" #include "sst/core/model/python/pymodel_link.h" diff --git a/src/sst/core/model/python/pymodel_link.cc b/src/sst/core/model/python/pymodel_link.cc index fa2fddae3..82e8292ae 100644 --- a/src/sst/core/model/python/pymodel_link.cc +++ b/src/sst/core/model/python/pymodel_link.cc @@ -16,7 +16,7 @@ #include "sst/core/model/python/pymodel_link.h" #include "sst/core/component.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/model/python/pymacros.h" #include "sst/core/model/python/pymodel.h" #include "sst/core/model/python/pymodel_comp.h" diff --git a/src/sst/core/model/python/pymodel_portmodule.cc b/src/sst/core/model/python/pymodel_portmodule.cc index 32fe43a14..1d764d1e8 100644 --- a/src/sst/core/model/python/pymodel_portmodule.cc +++ b/src/sst/core/model/python/pymodel_portmodule.cc @@ -15,7 +15,7 @@ #include "sst/core/model/python/pymodel_portmodule.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/model/python/pymacros.h" #include "sst/core/model/python/pymodel.h" #include "sst/core/model/python/pymodel_stat.h" diff --git a/src/sst/core/model/python/pymodel_stat.cc b/src/sst/core/model/python/pymodel_stat.cc index 3f95d6501..2cd098a94 100644 --- a/src/sst/core/model/python/pymodel_stat.cc +++ b/src/sst/core/model/python/pymodel_stat.cc @@ -15,7 +15,7 @@ #include "sst/core/model/python/pymodel_stat.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/model/python/pymacros.h" #include "sst/core/model/python/pymodel.h" #include "sst/core/sst_types.h" diff --git a/src/sst/core/model/python/pymodel_statgroup.cc b/src/sst/core/model/python/pymodel_statgroup.cc index 5b7150e44..65e74d5b6 100644 --- a/src/sst/core/model/python/pymodel_statgroup.cc +++ b/src/sst/core/model/python/pymodel_statgroup.cc @@ -16,7 +16,7 @@ #include "sst/core/model/python/pymodel_statgroup.h" #include "sst/core/component.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/model/python/pymacros.h" #include "sst/core/model/python/pymodel.h" #include "sst/core/model/python/pymodel_comp.h" diff --git a/src/sst/core/model/restart/sstcptmodel.h b/src/sst/core/model/restart/sstcptmodel.h index caf05ccaa..b39d9e002 100644 --- a/src/sst/core/model/restart/sstcptmodel.h +++ b/src/sst/core/model/restart/sstcptmodel.h @@ -15,7 +15,7 @@ #define SST_CORE_MODEL_RESTART_SSTCPTMODEL_H #include "sst/core/config.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/model/sstmodel.h" #include "sst/core/output.h" #include "sst/core/rankInfo.h" diff --git a/src/sst/core/portModule.cc b/src/sst/core/portModule.cc index 028209be6..1c1f86df6 100644 --- a/src/sst/core/portModule.cc +++ b/src/sst/core/portModule.cc @@ -14,7 +14,7 @@ #include "sst/core/portModule.h" #include "sst/core/baseComponent.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/simulation_impl.h" #include "sst/core/stringize.h" #include "sst/core/warnmacros.h" diff --git a/src/sst/core/simulation.cc b/src/sst/core/simulation.cc index b056c8825..7c9f50c9f 100644 --- a/src/sst/core/simulation.cc +++ b/src/sst/core/simulation.cc @@ -17,7 +17,6 @@ #include "sst/core/checkpointAction.h" #include "sst/core/clock.h" #include "sst/core/config.h" -#include "sst/core/configGraph.h" #include "sst/core/exit.h" #include "sst/core/factory.h" #include "sst/core/heartbeat.h" @@ -25,6 +24,7 @@ #include "sst/core/interactiveConsole.h" #include "sst/core/linkMap.h" #include "sst/core/linkPair.h" +#include "sst/core/model/configGraph.h" #include "sst/core/output.h" #include "sst/core/profile/clockHandlerProfileTool.h" #include "sst/core/profile/eventHandlerProfileTool.h" diff --git a/src/sst/core/statapi/statengine.cc b/src/sst/core/statapi/statengine.cc index 2ab600acd..3a634fd0d 100644 --- a/src/sst/core/statapi/statengine.cc +++ b/src/sst/core/statapi/statengine.cc @@ -14,10 +14,10 @@ #include "sst/core/statapi/statengine.h" #include "sst/core/baseComponent.h" -#include "sst/core/configGraph.h" #include "sst/core/eli/elementinfo.h" #include "sst/core/factory.h" #include "sst/core/impl/oneshotManager.h" +#include "sst/core/model/configGraph.h" #include "sst/core/output.h" #include "sst/core/simulation_impl.h" #include "sst/core/statapi/statbase.h" diff --git a/src/sst/core/statapi/statgroup.cc b/src/sst/core/statapi/statgroup.cc index 2e9554bd9..4e2d03673 100644 --- a/src/sst/core/statapi/statgroup.cc +++ b/src/sst/core/statapi/statgroup.cc @@ -14,7 +14,7 @@ #include "sst/core/statapi/statgroup.h" #include "sst/core/baseComponent.h" -#include "sst/core/configGraph.h" +#include "sst/core/model/configGraph.h" #include "sst/core/output.h" #include "sst/core/simulation_impl.h" #include "sst/core/statapi/statbase.h"