SST  15.1.0
StructuralSimulationToolkit
baseComponent.h
1 // Copyright 2009-2025 NTESS. Under the terms
2 // of Contract DE-NA0003525 with NTESS, the U.S.
3 // Government retains certain rights in this software.
4 //
5 // Copyright (c) 2009-2025, NTESS
6 // All rights reserved.
7 //
8 // This file is part of the SST software package. For license
9 // information, see the LICENSE file in the top level directory of the
10 // distribution.
11 
12 #ifndef SST_CORE_BASECOMPONENT_H
13 #define SST_CORE_BASECOMPONENT_H
14 
15 #include "sst/core/clock.h"
16 #include "sst/core/componentInfo.h"
17 #include "sst/core/eli/elementinfo.h"
18 #include "sst/core/event.h"
19 #include "sst/core/factory.h"
20 #include "sst/core/portModule.h"
21 #include "sst/core/profile/componentProfileTool.h"
22 #include "sst/core/serialization/serializable_base.h"
23 #include "sst/core/serialization/serialize.h"
24 #include "sst/core/sst_types.h"
25 #include "sst/core/statapi/statbase.h"
26 #include "sst/core/statapi/statengine.h"
27 #include "sst/core/warnmacros.h"
28 
29 #include <cstdint>
30 #include <functional>
31 #include <map>
32 #include <set>
33 #include <string>
34 #include <type_traits>
35 #include <utility>
36 #include <vector>
37 
38 using namespace SST::Statistics;
39 
40 namespace SST {
41 
42 class Component;
43 class ComponentExtension;
44 class Clock;
45 class Link;
46 class LinkMap;
47 class Module;
48 class Params;
49 class Simulation;
50 class Simulation_impl;
51 class SubComponent;
52 class SubComponentSlotInfo;
53 class TimeConverter;
54 class UnitAlgebra;
55 class WatchPoint;
56 
57 namespace Core::Serialization::pvt {
58 class SerializeBaseComponentHelper;
59 }
60 
61 /**
62  * Main component object for the simulation.
63  */
65 {
66 
67  friend class Component;
68  friend class ComponentExtension;
69  friend class ComponentInfo;
70  friend class SubComponent;
71  friend class SubComponentSlotInfo;
72  friend class PortModule;
73 
74 protected:
75  using StatCreateFunction = std::function<Statistics::StatisticBase*(BaseComponent*,
76  Statistics::StatisticProcessingEngine*, const std::string& /*name*/, const std::string& /*sub_id*/, Params&)>;
77 
78  BaseComponent() = default; // For serialization only
79 
80 public:
81  explicit BaseComponent(ComponentId_t id);
82  virtual ~BaseComponent();
83 
84  BaseComponent(const BaseComponent&) = delete;
85  BaseComponent& operator=(const BaseComponent&) = delete;
86 
87  const std::string& getType() const { return my_info_->getType(); }
88 
89  /** Returns unique component ID */
90  inline ComponentId_t getId() const { return my_info_->id_; }
91 
92  /** Returns Component Statistic load level */
93  inline uint8_t getStatisticLoadLevel() const { return my_info_->statLoadLevel; }
94 
95  /** Called when SIGINT or SIGTERM has been seen.
96  * Allows components opportunity to clean up external state.
97  */
98  virtual void emergencyShutdown() {}
99 
100  /** Returns Component/SubComponent Name */
101  inline const std::string& getName() const { return my_info_->getName(); }
102 
103  /** Returns the name of the parent Component, or, if called on a
104  * Component, the name of that Component. */
105  inline const std::string& getParentComponentName() const { return my_info_->getParentComponentName(); }
106 
107  /** Used during the init phase. The method will be called each
108  phase of initialization. Initialization ends when no components
109  have sent any data. */
110  virtual void init(unsigned int UNUSED(phase)) {}
111  /** Used during the complete phase after the end of simulation.
112  The method will be called each phase of complete. Complete phase
113  ends when no components have sent any data. */
114  virtual void complete(unsigned int UNUSED(phase)) {}
115  /** Called after all components have been constructed and
116  initialization has completed, but before simulation time has
117  begun. */
118  virtual void setup() {}
119  /** Called after complete phase, but before objects are
120  destroyed. A good place to print out statistics. */
121  virtual void finish() {}
122 
123  /** Currently unused function */
124  virtual bool Status() { return 0; }
125 
126  /**
127  * Called by the Simulation to request that the component
128  * print it's current status. Useful for debugging.
129  * @param out The Output class which should be used to print component status.
130  */
131  virtual void printStatus(Output& UNUSED(out)) { return; }
132 
133  /** Get the core timebase */
134  UnitAlgebra getCoreTimeBase() const;
135  /** Return the current simulation time as a cycle count*/
136  SimTime_t getCurrentSimCycle() const;
137  /** Return the current priority */
138  int getCurrentPriority() const;
139  /** Return the elapsed simulation time as a time */
140  UnitAlgebra getElapsedSimTime() const;
141  /** Return the end simulation time as a cycle count*/
142  SimTime_t getEndSimCycle() const;
143  /** Return the end simulation time as a time */
144  UnitAlgebra getEndSimTime() const;
145  /** Get this instance's parallel rank */
146  RankInfo getRank() const;
147  /** Get the number of parallel ranks in the simulation */
148  RankInfo getNumRanks() const;
149  /** Return the base simulation Output class instance */
150  Output& getSimulationOutput() const;
151 
152  /**
153  Return the simulated time since the simulation began in units specified by
154  the parameter.
155 
156  @param tc TimeConverter specifying the units
157  */
158  [[deprecated("Use of shared TimeConverter objects is deprecated. Use 'getCurrentSimTime(TimeConverter tc)' "
159  "(i.e., no pointer) instead.")]]
160  SimTime_t getCurrentSimTime(TimeConverter* tc) const;
161  SimTime_t getCurrentSimTime(TimeConverter tc) const;
162 
163  /**
164  Return the simulated time since the simulation began in the
165  default timebase
166  */
167  inline SimTime_t getCurrentSimTime() const { return getCurrentSimTime(my_info_->defaultTimeBase); }
168 
169  /**
170  Return the simulated time since the simulation began in
171  timebase specified
172 
173  @param base Timebase frequency in SI Units
174  */
175  SimTime_t getCurrentSimTime(const std::string& base) const;
176 
177  /** Utility function to return the time since the simulation began in nanoseconds */
178  SimTime_t getCurrentSimTimeNano() const;
179  /** Utility function to return the time since the simulation began in microseconds */
180  SimTime_t getCurrentSimTimeMicro() const;
181  /** Utility function to return the time since the simulation began in milliseconds */
182  SimTime_t getCurrentSimTimeMilli() const;
183 
184  /** Get the amount of real-time spent executing the run phase of
185  * the simulation.
186  *
187  * @return real-time in seconds spent executing the run phase
188  */
189  double getRunPhaseElapsedRealTime() const;
190 
191  /** Get the amount of real-time spent executing the init phase of
192  * the simulation.
193  *
194  * @return real-time in seconds spent executing the init phase
195  */
196  double getInitPhaseElapsedRealTime() const;
197 
198  /** Get the amount of real-time spent executing the complete phase of
199  * the simulation.
200  *
201  * @return real-time in seconds spent executing the complete phase
202  */
203  double getCompletePhaseElapsedRealTime() const;
204 
205 
206  /** Add a watch point to all handlers in the Component Tree
207  */
208  void addWatchPoint(WatchPoint* pt);
209 
210  /** Remove a watch point from all handlers in the Component Tree
211  */
212  void removeWatchPoint(WatchPoint* pt);
213 
214 
215 private:
216  /** Recursively add Watch point to myself and all my children
217  */
218  void addWatchPointRecursive(WatchPoint* pt);
219 
220  /** Recursively removes a Watch point from myself and all my
221  * children
222  */
223  void removeWatchPointRecursive(WatchPoint* pt);
224 
225 protected:
226  /** Check to see if the run mode was set to INIT
227  @return true if simulation run mode is set to INIT
228  */
229  bool isSimulationRunModeInit() const;
230 
231  /** Check to see if the run mode was set to RUN
232  @return true if simulation run mode is set to RUN
233  */
234  bool isSimulationRunModeRun() const;
235 
236  /** Check to see if the run mode was set to BOTH
237  @return true if simulation run mode is set to BOTH
238  */
239  bool isSimulationRunModeBoth() const;
240 
241  /** Returns the output directory of the simulation
242  * @return Directory in which simulation outputs should be
243  * placed. Returns empty string if output directory not set by
244  * user.
245  */
246  std::string& getOutputDirectory() const;
247 
248  /** Signifies that a library is required for this simulation.
249  * Causes the Factory to verify that the required library is
250  * loaded.
251  *
252  * NOTE: This function should rarely be required, as most
253  * dependencies are automatically detected in the simulator core.
254  * However, if the component uses an event from another library
255  * that is not wholly defined in a header file, this call may be
256  * required to ensure that all the code from the event is loaded.
257  * Similarly, if you use a class from another library that does
258  * not have ELI information, this call may also be required to
259  * make sure all dependencies are loaded.
260  *
261  * @param name Name of library this BaseComponent depends on
262  */
263  void requireLibrary(const std::string& name);
264 
265 
266  /** Determine if a port name is connected to any links */
267  bool isPortConnected(const std::string& name) const;
268 
269  /** Configure a Link
270  * @param name - Port Name on which the link to configure is attached.
271  * @param time_base - Time Base of the link. If nullptr is passed in, then it
272  * will use the Component defaultTimeBase
273  * @param handler - Optional Handler to be called when an Event is received
274  * @return A pointer to the configured link, or nullptr if an error occured.
275  */
276 
277  [[deprecated(
278  "Use of shared TimeConverter objects is deprecated. Use 'configureLink(const std::string& name, TimeConverter "
279  "time_base, EventHandlerBase* handler)' (i.e., no TimeConverter pointer) instead.")]]
280  Link* configureLink(const std::string& name, TimeConverter* time_base, Event::HandlerBase* handler = nullptr);
281  Link* configureLink(const std::string& name, TimeConverter time_base, Event::HandlerBase* handler = nullptr);
282  /** Configure a Link
283  * @param name - Port Name on which the link to configure is attached.
284  * @param time_base - Time Base of the link as a string
285  * @param handler - Optional Handler to be called when an Event is received
286  * @return A pointer to the configured link, or nullptr if an error occured.
287  */
288  Link* configureLink(const std::string& name, const std::string& time_base, Event::HandlerBase* handler = nullptr);
289  /** Configure a Link
290  * @param name - Port Name on which the link to configure is attached.
291  * @param time_base - Time Base of the link as a UnitAlgebra
292  * @param handler - Optional Handler to be called when an Event is received
293  * @return A pointer to the configured link, or nullptr if an error occured.
294  */
295  Link* configureLink(const std::string& name, const UnitAlgebra& time_base, Event::HandlerBase* handler = nullptr);
296  /** Configure a Link
297  * @param name - Port Name on which the link to configure is attached.
298  * @param handler - Optional Handler to be called when an Event is received
299  * @return A pointer to the configured link, or nullptr if an error occured.
300  */
301  Link* configureLink(const std::string& name, Event::HandlerBase* handler = nullptr);
302 
303  /** Configure a SelfLink (Loopback link)
304  * @param name - Name of the self-link port
305  * @param time_base - Time Base of the link. If nullptr is passed in, then it
306  * will use the Component defaultTimeBase
307  * @param handler - Optional Handler to be called when an Event is received
308  * @return A pointer to the configured link, or nullptr if an error occured.
309  */
310  [[deprecated("Use of shared TimeConverter objects is deprecated. Use 'configureSelfLink(const std::string& name, "
311  "TimeConverter time_base, EventHandlerBase* handler)' (i.e., no TimeConverter pointer) instead.")]]
312  Link* configureSelfLink(const std::string& name, TimeConverter* time_base, Event::HandlerBase* handler = nullptr);
313  Link* configureSelfLink(const std::string& name, TimeConverter time_base, Event::HandlerBase* handler = nullptr);
314 
315  /** Configure a SelfLink (Loopback link)
316  * @param name - Name of the self-link port
317  * @param time_base - Time Base of the link as a string
318  * @param handler - Optional Handler to be called when an Event is received
319  * @return A pointer to the configured link, or nullptr if an error occured.
320  */
321  Link* configureSelfLink(
322  const std::string& name, const std::string& time_base, Event::HandlerBase* handler = nullptr);
323  /** Configure a SelfLink (Loopback link)
324  * @param name - Name of the self-link port
325  * @param time_base - Time Base of the link as a UnitAlgebra
326  * @param handler - Optional Handler to be called when an Event is received
327  * @return A pointer to the configured link, or nullptr if an error occured.
328  */
329  Link* configureSelfLink(
330  const std::string& name, const UnitAlgebra& time_base, Event::HandlerBase* handler = nullptr);
331  /** Configure a SelfLink (Loopback link)
332  * @param name - Name of the self-link port
333  * @param handler - Optional Handler to be called when an Event is received
334  * @return A pointer to the configured link, or nullptr if an error occured.
335  */
336  Link* configureSelfLink(const std::string& name, Event::HandlerBase* handler = nullptr);
337 
338  /** Registers a clock for this component.
339  @param freq Frequency for the clock in SI units
340  @param handler Pointer to Clock::HandlerBase which is to be invoked
341  at the specified interval
342  @param regAll Should this clock period be used as the default
343  time base for all of the links connected to this component
344  @return the TimeConverter object representing the clock frequency
345  */
346  TimeConverter* registerClock(const std::string& freq, Clock::HandlerBase* handler, bool regAll = true);
347 
348  /** Registers a clock for this component.
349  @param freq Frequency for the clock as a UnitAlgebra object
350  @param handler Pointer to Clock::HandlerBase which is to be invoked
351  at the specified interval
352  @param regAll Should this clock period be used as the default
353  time base for all of the links connected to this component
354  @return the TimeConverter object representing the clock frequency
355  */
356  TimeConverter* registerClock(const UnitAlgebra& freq, Clock::HandlerBase* handler, bool regAll = true);
357 
358  /** Registers a clock for this component.
359  @param tc TimeConverter object specifying the clock frequency
360  @param handler Pointer to Clock::HandlerBase which is to be invoked
361  at the specified interval
362  @param regAll Should this clock period be used as the default
363  time base for all of the links connected to this component
364  @return the TimeConverter object representing the clock frequency
365  */
366  [[deprecated(
367  "Use of shared TimeConverter objects is deprecated. Use 'registerClock(TimeConverter tc, Clock::HandlerBase* "
368  "handler, bool regAll)' (i.e., no TimeConverter pointer) instead.")]]
369  TimeConverter* registerClock(TimeConverter* tc, Clock::HandlerBase* handler, bool regAll = true);
370  TimeConverter* registerClock(TimeConverter tc, Clock::HandlerBase* handler, bool regAll = true);
371 
372  /** Removes a clock handler from the component */
373  [[deprecated("Use of shared TimeConverter objects is deprecated. Use 'unregisterClock(TimeConverter tc, "
374  "Clock::HandlerBase* handler)' (i.e., no TimeConverter pointer) instead.")]]
375  void unregisterClock(TimeConverter* tc, Clock::HandlerBase* handler);
376  void unregisterClock(TimeConverter tc, Clock::HandlerBase* handler);
377 
378  /** Reactivates an existing Clock and Handler
379  * @return time of next time clock handler will fire
380  *
381  * Note: If called after the simulation run loop (e.g., in finish() or complete()),
382  * will return the next time of the clock past when the simulation ended. There can
383  * be a small lag between simulation end and detection of simulation end during which
384  * clocks can run a few extra cycles. As a result, the return value just prior to
385  * simulation end may be greater than the value returned after simulation end.
386  */
387  [[deprecated("Use of shared TimeConverter objects is deprecated. Use 'reregisterClock(TimeConverter freq, "
388  "Clock::HandlerBase* handler)' (i.e., no TimeConverter pointer) instead.")]]
389  Cycle_t reregisterClock(TimeConverter* freq, Clock::HandlerBase* handler);
390  Cycle_t reregisterClock(TimeConverter freq, Clock::HandlerBase* handler);
391 
392  /** Returns the next Cycle that the TimeConverter would fire
393  If called prior to the simulation run loop, next Cycle is 0.
394  If called after the simulation run loop completes (e.g., during
395  complete() or finish()), next Cycle is one past the end time of
396  the simulation. See Note in reregisterClock() for additional guidance
397  when calling this function after simulation ends.
398  */
399  [[deprecated(
400  "Use of shared TimeConverter objects is deprecated. Use 'getNextClockCycle(TimeConverter freq)' (i.e., "
401  "no TimeConverter pointer) instead.")]]
402  Cycle_t getNextClockCycle(TimeConverter* freq);
403  Cycle_t getNextClockCycle(TimeConverter freq);
404 
405  /** Registers a default time base for the component and optionally
406  sets the the component's links to that timebase. Useful for
407  components which do not have a clock, but would like a default
408  timebase.
409  @param base Frequency for the clock in SI units
410  @param regAll Should this clock period be used as the default
411  time base for all of the links connected to this component
412  */
413  TimeConverter* registerTimeBase(const std::string& base, bool regAll = true);
414 
415  TimeConverter* getTimeConverter(const std::string& base) const;
416  TimeConverter* getTimeConverter(const UnitAlgebra& base) const;
417 
418  bool isStatisticShared(const std::string& stat_name, bool include_me = false)
419  {
420  if ( include_me ) {
421  if ( getStatisticValidityAndLevel(stat_name) != 255 ) {
422  return true;
423  }
424  }
425  if ( my_info_->sharesStatistics() ) {
426  return my_info_->parent_info->component->isStatisticShared(stat_name, true);
427  }
428  else {
429  return false;
430  }
431  }
432 
433  void initiateInteractive(const std::string& msg);
434 
435 private:
436  ImplementSerializable(SST::BaseComponent)
437  void serialize_order(SST::Core::Serialization::serializer& ser) override;
438 
439 
440  /**
441  Handles the profile points, default time base, handler tracking
442  and checkpointing.
443  */
444  void registerClock_impl(TimeConverter* tc, Clock::HandlerBase* handler, bool regAll);
445 
446  /**
447  Handles default timebase setup
448  */
449  Link* configureLink_impl(const std::string& name, SimTime_t time_base, Event::HandlerBase* handler = nullptr);
450 
451  /**
452  * @brief createStatistic Helper function used to create an enabled statistic. For explicitly-enabled
453  * statistics, this must be called on the parent component. For enable-all, it can be called on the enabling
454  * component.
455  * @param cpp_params Any parameters given in C++ specific to this statistic
456  * @param name The name (different from type) for this statistic
457  * @param stat_sub_id An optional sub ID for this statistic to differentiate instances of the same stat
458  * @return The statistic created
459  */
460  template <typename T>
461  Statistics::Statistic<T>* createStatistic(
462  SST::Params& params, StatisticId_t id, const std::string& name, const std::string& stat_sub_id)
463  {
464  /* I would prefer to avoid this std::function with dynamic cast,
465  * but the code is just a lot cleaner and avoids many unnecessary template instantiations
466  * doing it this way. At some point in the future, we would need to clean up
467  * the rule around enabling all statistics to make this better
468  *
469  * Even if we moved the logic around, we'd still have to dyncast anything coming out of
470  * the stat data structures.
471  */
472  StatCreateFunction create = [=](BaseComponent* comp, Statistics::StatisticProcessingEngine* engine,
473  const std::string& name, const std::string& sub_id,
474  SST::Params& params) -> Statistics::StatisticBase* {
475  return engine->createStatistic<T>(comp, name, sub_id, params);
476  };
477 
478  // We follow two distinct paths depending on if it is enable all, versus explicitly enabled
479  // Enable all is "scoped" to the (sub)component
480  // Explicitly enabled stats are assigned component-unique IDs and can be shared across subcomponents
481  // so creation and management happens in the parent component
482  Statistics::StatisticBase* base_stat =
483  id == STATALL_ID ? createEnabledAllStatistic(params, name, stat_sub_id, std::move(create))
484  : getParentComponent()->createExplicitlyEnabledStatistic(
485  params, id, name, stat_sub_id, std::move(create));
486 
487  // Ugh, dynamic casts hurt my eyes, but I must do this
488  auto* statistic = dynamic_cast<Statistics::Statistic<T>*>(base_stat);
489  if ( statistic ) {
490  return statistic;
491  }
492  else {
493  fatal(__LINE__, __FILE__, "createStatistic", 1, "failed to cast created statistic '%s' to expected type",
494  name.c_str());
495  }
496  }
497 
498  /**
499  * Internal registration function for statistics. Determines if a statistic is enabled or not.
500  * It first locates the component that should "own" the stat based on both ELI and statistic enable parameters.
501  * If enabled, it calls createStatistic<T> on the owning component.
502  * If disabled, it returns a disabled statistic from the statistic engine.
503  */
504  template <typename T>
505  Statistics::Statistic<T>* registerStatistic_impl(
506  SST::Params& params, const std::string& stat_name, const std::string& stat_sub_id, uint8_t level = 255)
507  {
508  if ( level == 255 ) { // Stat has not yet been found in ELI, search this component's ELI
509  level = getStatisticValidityAndLevel(stat_name);
510  }
511 
512  if ( level == 255 ) {
513  // If level is still 255, stat has not been found in any ELI yet, need to check if parent shares their ELI
514  if ( my_info_->parent_info && my_info_->sharesStatistics() ) {
515  return my_info_->parent_info->component->registerStatistic_impl<T>(params, stat_name, stat_sub_id);
516  }
517  else {
518  // not a valid stat and I won't be able to share my parent's statistic
519  fatal(__LINE__, __FILE__, "registerStatistic", 1,
520  "attempting to register a statistic '%s' that is not found in ELI", stat_name.c_str());
521  }
522  }
523 
524  // Path 1: Explicitly enabled statistic
525  if ( my_info_->enabled_stat_names_ ) {
526  auto iter = my_info_->enabled_stat_names_->find(stat_name);
527  if ( iter != my_info_->enabled_stat_names_->end() ) {
528  // valid, enabled statistic
529  // During initialization, the component should have assigned a mapping between
530  // the local name and globally unique stat ID
531  StatisticId_t id = iter->second;
532  return getParentComponent()->createStatistic<T>(params, id, stat_name, stat_sub_id);
533  }
534  }
535 
536  // Path 2: Enabled all statistic
537  if ( my_info_->enabled_all_stats_ ) { // I enabled this stat and it is valid
538  if ( level > getStatisticLoadLevel() ) {
539  return getStatEngine()->createDisabledStatistic<T>();
540  }
541  return createStatistic<T>(params, STATALL_ID, stat_name, stat_sub_id);
542  }
543  else if ( my_info_->parent_info && my_info_->canInsertStatistics() ) {
544  // I did not enable all but my parent may have and will accept my statistics
545  return my_info_->parent_info->component->registerStatistic_impl<T>(params, stat_name, stat_sub_id, level);
546  }
547  else {
548  // Not enabled
549  return getStatEngine()->createDisabledStatistic<T>();
550  }
551  }
552 
553 protected:
554  /** Registers a statistic.
555  If Statistic is allowed to run (controlled by Python runtime parameters),
556  then a statistic will be created and returned. If not allowed to run,
557  then a NullStatistic will be returned. In either case, the returned
558  value should be used for all future Statistic calls. The type of
559  Statistic and the Collection Rate is set by Python runtime parameters.
560  If no type is defined, then an Accumulator Statistic will be provided
561  by default. If rate set to 0 or not provided, then the statistic will
562  output results only at end of sim (if output is enabled).
563  @param params Parameter set to be passed to the statistic constructor.
564  @param stat_name Primary name of the statistic. This name must match the
565  defined ElementInfoStatistic in the component, and must also
566  be enabled in the Python input file.
567  @param stat_sub_id An additional sub name for the statistic
568  @return Either a created statistic of desired type or a NullStatistic
569  depending upon runtime settings.
570  */
571  template <typename T>
573  SST::Params& params, const std::string& stat_name, const std::string& stat_sub_id = "")
574  {
575  return registerStatistic_impl<T>(params, stat_name, stat_sub_id);
576  }
577 
578  template <typename T>
579  Statistics::Statistic<T>* registerStatistic(const std::string& stat_name, const std::string& stat_sub_id = "")
580  {
581  SST::Params empty {};
582  return registerStatistic_impl<T>(empty, stat_name, stat_sub_id);
583  }
584 
585  template <typename... Args>
586  Statistics::Statistic<std::tuple<Args...>>* registerMultiStatistic(
587  const std::string& stat_name, const std::string& stat_sub_id = "")
588  {
589  SST::Params empty {};
590  return registerStatistic_impl<std::tuple<Args...>>(empty, stat_name, stat_sub_id);
591  }
592 
593  template <typename... Args>
594  Statistics::Statistic<std::tuple<Args...>>* registerMultiStatistic(
595  SST::Params& params, const std::string& stat_name, const std::string& stat_sub_id = "")
596  {
597  return registerStatistic_impl<std::tuple<Args...>>(params, stat_name, stat_sub_id);
598  }
599 
600  template <typename T>
601  Statistics::Statistic<T>* registerStatistic(const char* stat_name, const char* stat_sub_id = "")
602  {
603  return registerStatistic<T>(std::string(stat_name), std::string(stat_sub_id));
604  }
605 
606  /** Called by the Components and Subcomponent to perform a statistic Output.
607  * @param stat - Pointer to the statistic.
608  */
609  void performStatisticOutput(Statistics::StatisticBase* stat);
610 
611  /** Performs a global statistic Output.
612  * This routine will force ALL Components and Subcomponents to output their statistic information.
613  * This may lead to unexpected results if the statistic counts or data is reset on output.
614  * NOTE: Currently, this function will only output statistics that are on the same rank.
615  */
616  void performGlobalStatisticOutput();
617 
618  /** Registers a profiling point.
619  This function will register a profiling point.
620  @param point Point to resgister
621  @return Either a pointer to a created T::ProfilePoint or nullptr if not enabled.
622  */
623  template <typename T>
624  typename T::ProfilePoint* registerProfilePoint(const std::string& pointName)
625  {
626  std::string full_point_name = getType() + "." + pointName;
627  auto tools = getComponentProfileTools(full_point_name);
628  if ( tools.size() == 0 ) return nullptr;
629 
630  typename T::ProfilePoint* ret = new typename T::ProfilePoint();
631  for ( auto* x : tools ) {
632  T* tool = dynamic_cast<T*>(x);
633  if ( nullptr == tool ) {
634  // Not the right type, fatal
635  fatal(CALL_INFO_LONG, 1, "ERROR: wrong type of profiling tool for profiling point %s)\n",
636  pointName.c_str());
637  }
638  ret->registerProfilePoint(tool, pointName, getId(), getName(), getType());
639  }
640  return ret;
641  }
642 
643  /** Loads a module from an element Library
644  * @param type Fully Qualified library.moduleName
645  * @param params Parameters the module should use for configuration
646  * @return handle to new instance of module, or nullptr on failure.
647  */
648  template <class T, class... ARGS>
649  T* loadModule(const std::string& type, Params& params, ARGS... args)
650  {
651  // Check to see if this can be loaded with new API or if we have to fallback to old
652  return Factory::getFactory()->CreateWithParams<T>(type, params, params, args...);
653  }
654 
655 protected:
656  // When you direct load, the ComponentExtension does not need any
657  // ELI information and if it has any, it will be ignored. The
658  // extension will be loaded as if it were part of the parent
659  // BaseComponent and will share all that components ELI
660  // information.
661  template <class T, class... ARGS>
662  T* loadComponentExtension(ARGS... args)
663  {
664  ComponentExtension* ret = new T(my_info_->id_, args...);
665  return static_cast<T*>(ret);
666  }
667 
668  /**
669  Check to see if a given element type is loadable with a particular API
670 
671  @param name - Name of element to check in lib.name format
672  @return True if loadable as the API specified as the template parameter
673  */
674  template <class T>
675  bool isSubComponentLoadableUsingAPI(const std::string& type)
676  {
677  return Factory::getFactory()->isSubComponentLoadableUsingAPI<T>(type);
678  }
679 
680  /**
681  Check to see if the element type loaded by the user into the.
682  specified slot is loadable with a particular API. This will
683  only check slot index 0. If you need to check other slots,
684  please use the SubComponentSlotInfo.
685 
686  @param slot_name - Name of slot to check
687  @return True if loadable as the API specified as the template parameter
688  */
689  template <class T>
690  bool isUserSubComponentLoadableUsingAPI(const std::string& slot_name)
691  {
692  // Get list of ComponentInfo objects and make sure that there is
693  // only one SubComponent put into this slot
694  // const std::vector<ComponentInfo>& subcomps = my_info_->getSubComponents();
695  const std::map<ComponentId_t, ComponentInfo>& subcomps = my_info_->getSubComponents();
696  int sub_count = 0;
697  int index = -1;
698  for ( auto& ci : subcomps ) {
699  if ( ci.second.getSlotName() == slot_name ) {
700  index = ci.second.getSlotNum();
701  sub_count++;
702  }
703  }
704 
705  if ( sub_count > 1 ) {
706  SST::Output outXX("SubComponentSlotWarning: ", 0, 0, Output::STDERR);
707  outXX.fatal(CALL_INFO, 1,
708  "Error: ComponentSlot \"%s\" in component \"%s\" only allows for one SubComponent, %d provided.\n",
709  slot_name.c_str(), my_info_->getType().c_str(), sub_count);
710  }
711 
712  return isUserSubComponentLoadableUsingAPIByIndex<T>(slot_name, index);
713  }
714 
715  /**
716  Loads an anonymous subcomponent (not defined in input file to
717  SST run).
718 
719  @param type tyupe of subcomponent to load in lib.name format
720  @param slot_name name of the slot to load subcomponent into
721  @param slot_num index of the slot to load subcomponent into
722  @param share_flags Share flags to be used by subcomponent
723  @param params Params object to be passed to subcomponent
724  @param args Arguments to be passed to constructor. This
725  signature is defined in the API definition
726 
727  For ease in backward compatibility to old API, this call will
728  try to load using new API and will fallback to old if
729  unsuccessful.
730  */
731  template <class T, class... ARGS>
732  T* loadAnonymousSubComponent(const std::string& type, const std::string& slot_name, int slot_num,
733  uint64_t share_flags, Params& params, ARGS... args)
734  {
735 
736  share_flags = share_flags & ComponentInfo::USER_FLAGS;
737  ComponentId_t cid = my_info_->addAnonymousSubComponent(my_info_, type, slot_name, slot_num, share_flags);
738  ComponentInfo* sub_info = my_info_->findSubComponent(cid);
739 
740  // This shouldn't happen since we just put it in, but just in case
741  if ( sub_info == nullptr ) return nullptr;
742 
743  // Check to see if this can be loaded with new API or if we have to fallback to old
744  if ( isSubComponentLoadableUsingAPI<T>(type) ) {
745  auto ret = Factory::getFactory()->CreateWithParams<T>(type, params, sub_info->id_, params, args...);
746  return ret;
747  }
748  return nullptr;
749  }
750 
751  /**
752  Loads a user defined subcomponent (defined in input file to SST
753  run). This version does not allow share flags (set to
754  SHARE_NONE) or constructor arguments.
755 
756  @param slot_name name of the slot to load subcomponent into
757 
758  For ease in backward compatibility to old API, this call will
759  try to load using new API and will fallback to old if
760  unsuccessful.
761  */
762  template <class T>
763  T* loadUserSubComponent(const std::string& slot_name)
764  {
765  return loadUserSubComponent<T>(slot_name, ComponentInfo::SHARE_NONE);
766  }
767 
768  /**
769  Loads a user defined subcomponent (defined in input file to SST
770  run).
771 
772  @param slot_name name of the slot to load subcomponent into
773  @param share_flags Share flags to be used by subcomponent
774  @param args Arguments to be passed to constructor. This
775  signature is defined in the API definition
776 
777  For ease in backward compatibility to old API, this call will
778  try to load using new API and will fallback to old if
779  unsuccessful.
780  */
781  template <class T, class... ARGS>
782  T* loadUserSubComponent(const std::string& slot_name, uint64_t share_flags, ARGS... args)
783  {
784 
785  // Get list of ComponentInfo objects and make sure that there is
786  // only one SubComponent put into this slot
787  // const std::vector<ComponentInfo>& subcomps = my_info_->getSubComponents();
788  const std::map<ComponentId_t, ComponentInfo>& subcomps = my_info_->getSubComponents();
789  int sub_count = 0;
790  int index = -1;
791  for ( auto& ci : subcomps ) {
792  if ( ci.second.getSlotName() == slot_name ) {
793  index = ci.second.getSlotNum();
794  sub_count++;
795  }
796  }
797 
798  if ( sub_count > 1 ) {
799  SST::Output outXX("SubComponentSlotWarning: ", 0, 0, Output::STDERR);
800  outXX.fatal(CALL_INFO, 1,
801  "Error: ComponentSlot \"%s\" in component \"%s\" only allows for one SubComponent, %d provided.\n",
802  slot_name.c_str(), my_info_->getType().c_str(), sub_count);
803  }
804 
805  return loadUserSubComponentByIndex<T, ARGS...>(slot_name, index, share_flags, args...);
806  }
807 
808  /** Convenience function for reporting fatal conditions. The
809  function will create a new Output object and call fatal()
810  using the supplied parameters. Before calling
811  Output::fatal(), the function will also print other
812  information about the (sub)component that called fatal and
813  about the simulation state.
814 
815  From Output::fatal: Message will be sent to the output
816  location and to stderr. The output will be prepended with the
817  expanded prefix set in the object.
818  NOTE: fatal() will call MPI_Abort(exit_code) to terminate simulation.
819 
820  @param line Line number of calling function (use CALL_INFO macro)
821  @param file File name calling function (use CALL_INFO macro)
822  @param func Function name calling function (use CALL_INFO macro)
823  @param exit_code The exit code used for termination of simulation.
824  will be passed to MPI_Abort()
825  @param format Format string. All valid formats for printf are available.
826  @param ... Arguments for format.
827  */
828  [[noreturn]]
829  void fatal(uint32_t line, const char* file, const char* func, int exit_code, const char* format, ...) const
830  __attribute__((format(printf, 6, 7)));
831 
832  /** Convenience function for testing for and reporting fatal
833  conditions. If the condition holds, fatal() will be called,
834  otherwise, the function will return. The function will create
835  a new Output object and call fatal() using the supplied
836  parameters. Before calling Output::fatal(), the function will
837  also print other information about the (sub)component that
838  called fatal and about the simulation state.
839 
840  From Output::fatal: Message will be sent to the output
841  location and to stderr. The output will be prepended with the
842  expanded prefix set in the object.
843  NOTE: fatal() will call MPI_Abort(exit_code) to terminate simulation.
844 
845  @param condition on which to call fatal(); fatal() is called
846  if the bool is false.
847  @param line Line number of calling function (use CALL_INFO macro)
848  @param file File name calling function (use CALL_INFO macro)
849  @param func Function name calling function (use CALL_INFO macro)
850  @param exit_code The exit code used for termination of simulation.
851  will be passed to MPI_Abort()
852  @param format Format string. All valid formats for printf are available.
853  @param ... Arguments for format.
854  */
855  void sst_assert(bool condition, uint32_t line, const char* file, const char* func, int exit_code,
856  const char* format, ...) const __attribute__((format(printf, 7, 8)));
857 
858 private:
859  SimTime_t processCurrentTimeWithUnderflowedBase(const std::string& base) const;
860 
861  /**
862  * @brief findExplicitlyEnabledStatistic
863  * @param params
864  * @param id
865  * @param name
866  * @param stat_sub_id
867  * @return that matching stat if the stat already was created for the given ID, otherwise nullptr
868  */
869  Statistics::StatisticBase* createExplicitlyEnabledStatistic(SST::Params& params, StatisticId_t id,
870  const std::string& name, const std::string& stat_sub_id, StatCreateFunction create);
871 
872  Statistics::StatisticBase* createEnabledAllStatistic(
873  SST::Params& params, const std::string& name, const std::string& stat_sub_id, StatCreateFunction create);
874 
875  void setDefaultTimeBaseForLinks(TimeConverter tc);
876 
877  void pushValidParams(Params& params, const std::string& type);
878 
879  template <class T, class... ARGS>
880  T* loadUserSubComponentByIndex(const std::string& slot_name, int slot_num, int share_flags, ARGS... args)
881  {
882 
883  share_flags = share_flags & ComponentInfo::USER_FLAGS;
884 
885  // Check to see if the slot exists
886  ComponentInfo* sub_info = my_info_->findSubComponent(slot_name, slot_num);
887  if ( sub_info == nullptr ) return nullptr;
888  sub_info->share_flags = share_flags;
889  sub_info->parent_info = my_info_;
890 
891  if ( isSubComponentLoadableUsingAPI<T>(sub_info->type) ) {
892  auto ret = Factory::getFactory()->CreateWithParams<T>(
893  sub_info->type, *sub_info->params, sub_info->id_, *sub_info->params, args...);
894  return ret;
895  }
896  return nullptr;
897  }
898 
899  template <class T>
900  bool isUserSubComponentLoadableUsingAPIByIndex(const std::string& slot_name, int slot_num)
901  {
902  // Check to see if the slot exists
903  ComponentInfo* sub_info = my_info_->findSubComponent(slot_name, slot_num);
904  if ( sub_info == nullptr ) return false;
905 
906  return isSubComponentLoadableUsingAPI<T>(sub_info->type);
907  }
908 
909  // Utility function used by fatal and sst_assert
910  [[noreturn]]
911  void vfatal(uint32_t line, const char* file, const char* func, int exit_code, const char* format, va_list arg) const
912  __attribute__((format(printf, 6, 0)));
913 
914  // Get the statengine from Simulation_impl
915  StatisticProcessingEngine* getStatEngine();
916 
917 public:
918  SubComponentSlotInfo* getSubComponentSlotInfo(const std::string& name, bool fatalOnEmptyIndex = false);
919 
920  /** Retrieve the X,Y,Z coordinates of this component */
921  const std::vector<double>& getCoordinates() const { return my_info_->coordinates; }
922 
923 protected:
925  friend class SST::Statistics::StatisticBase;
926 
927  bool isAnonymous() { return my_info_->isAnonymous(); }
928 
929  bool isUser() { return my_info_->isUser(); }
930 
931  /** Manually set the default defaultTimeBase */
932  [[deprecated("Use of shared TimeConverter objects is deprecated. Use 'setDefaultTimeBase(TimeConverter tc)' "
933  "(i.e., no TimeConverter pointer) instead.")]]
935  {
936  my_info_->defaultTimeBase = tc;
937  }
938 
939  /** Manually set the default defaultTimeBase */
940  void setDefaultTimeBase(TimeConverter tc) { my_info_->defaultTimeBase = tc; }
941 
942  // Can change this back to inline once we move completely away
943  // from TimeConverter*
944  TimeConverter* getDefaultTimeBase(); // { return my_info_->defaultTimeBase; }
945  const TimeConverter* getDefaultTimeBase() const; // { return my_info_->defaultTimeBase; }
946 
947  bool doesSubComponentExist(const std::string& type);
948 
949  // Does the statisticName exist in the ElementInfoStatistic and if so, what is its enable level
950  uint8_t getStatisticValidityAndLevel(const std::string& statisticName) const;
951 
952  std::vector<Profile::ComponentProfileTool*> getComponentProfileTools(const std::string& point);
953 
954  /**** Primary Component API ****/
955 
956  /**
957  Register as a primary component, which allows the component to
958  specify when it is and is not OK to end simulation. The
959  simulator will not end simulation through use of the Exit
960  object while any primary component has specified
961  primaryComponentDoNotEndSim(). However, it is still possible
962  for Actions other than Exit to end simulation. Once all
963  primary components have specified primaryComponentOKToEndSim(),
964  the Exit object will trigger and end simulation.
965 
966  This must be called during simulation wireup (i.e during the
967  constructor for the component), or a fatal error will occur.
968 
969  If no component registers as a primary component, then the Exit
970  object will not be used for that simulation and simulation
971  termination must be accomplished through some other mechanism
972  (e.g. --stopAt flag, or some other Action object).
973 
974  @sa BaseComponent::primaryComponentDoNotEndSim()
975  @sa BaseComponent::primaryComponentOKToEndSim()
976  */
977  void registerAsPrimaryComponent();
978 
979  /**
980  Tells the simulation that it should not exit. The component
981  will remain in this state until a call to
982  primaryComponentOKToEndSim(). A component may reenter the DoNotEndSime state
983  by calling this function after calling
984  primaryComponentOKToEndSim(), in which case, another call to
985  primaryComponentOKToEndSim() will need to be called to end the
986  simulation.
987 
988  Calls to this function when already in the DoNotEndSime state,
989  will be functionally ignored, but will generate a warning if
990  verbose is turned on.
991 
992  Calls to this function on non-primary components will be
993  ignored and will generate a warning if verbose is turned on.
994 
995  @sa BaseComponent::registerAsPrimaryComponent()
996  @sa BaseComponent::primaryComponentOKToEndSim()
997  */
998  void primaryComponentDoNotEndSim();
999 
1000  /**
1001  Tells the simulation that it is now OK to end simulation.
1002  Simulation will not end until all primary components that have
1003  called primaryComponentDoNotEndSim() have called this function.
1004 
1005  Calls to this function when already in the OKToEndSim state,
1006  will be functionally ignored, but will generate a warning if
1007  verbose is turned on.
1008 
1009  Calls to this function on non-primary components will be
1010  ignored and will generate a warning if verbose is turned on.
1011 
1012  @sa BaseComponent::registerAsPrimaryComponent()
1013  @sa BaseComponent::primaryComponentDoNotEndSim()
1014  */
1015  void primaryComponentOKToEndSim();
1016 
1017 
1018 private:
1019  enum class ComponentState : uint8_t {
1020  // Primary States
1021  None = 0,
1022  Primary = 1 << 0,
1023  DoNotEndSim = 1 << 1,
1024  OKToEndSim = 1 << 2,
1025 
1026  // Whether this is an extension
1027  Extension = 1 << 3,
1028  };
1029 
1030  /**
1031  Check for Primary state
1032 
1033  @return true if component_state_ includes Primary, false otherwise
1034  */
1035  bool isStatePrimary()
1036  {
1037  return static_cast<uint8_t>(component_state_) & static_cast<uint8_t>(ComponentState::Primary);
1038  }
1039 
1040  /**
1041  Check for DoNotEndSim state. This state is mutually exclusive with OKToEndSim
1042 
1043  @return true if component_state_ includes DoNotEndSim, false otherwise
1044  */
1045  bool isStateDoNotEndSim()
1046  {
1047  return static_cast<uint8_t>(component_state_) & static_cast<uint8_t>(ComponentState::DoNotEndSim);
1048  }
1049 
1050  /**
1051  Check for OKToEndSim state. This state is mutually exclusive with DoNotEndSim
1052 
1053  @return true if component_state_ includes OKToEndSim
1054  */
1055  bool isStateOKToEndSim()
1056  {
1057  return static_cast<uint8_t>(component_state_) & static_cast<uint8_t>(ComponentState::OKToEndSim);
1058  }
1059 
1060  /**
1061  Check for Extension state
1062 
1063  @return true if component_state_ includes Extension, false otherwise
1064  */
1065  bool isExtension()
1066  {
1067  return static_cast<uint8_t>(component_state_) & static_cast<uint8_t>(ComponentState::Extension);
1068  }
1069 
1070 
1071  /**
1072  Adds Primary to the component_state_
1073 
1074  NOTE: This function does not check to see if the component is
1075  in the proper stage of simulation, that check should be done
1076  before calling this function.
1077  */
1078  void setStateAsPrimary()
1079  {
1080  component_state_ = static_cast<ComponentState>(
1081  static_cast<uint8_t>(component_state_) | static_cast<uint8_t>(ComponentState::Primary));
1082  }
1083 
1084  /**
1085  Adds DoNotEndSim and removes OKToEndSim to/from the
1086  component_state_
1087 
1088  NOTE: This function does not check to see if
1089  registerAsPrimaryComponent() has been properly called, that
1090  check should be done before calling this function.
1091  */
1092  void setStateDoNotEndSim()
1093  {
1094  component_state_ = static_cast<ComponentState>(
1095  static_cast<uint8_t>(component_state_) | static_cast<uint8_t>(ComponentState::DoNotEndSim));
1096  component_state_ = static_cast<ComponentState>(
1097  static_cast<uint8_t>(component_state_) & ~static_cast<uint8_t>(ComponentState::OKToEndSim));
1098  }
1099 
1100  /**
1101  Adds OKToEndSim and removes DoNotEndSim to/from the
1102  component_state_
1103 
1104  NOTE: This function does not check to see if
1105  registerAsPrimaryComponent() has been properly called, that
1106  check should be done before calling this function.
1107  */
1108  void setStateOKToEndSim()
1109  {
1110  component_state_ = static_cast<ComponentState>(
1111  static_cast<uint8_t>(component_state_) | static_cast<uint8_t>(ComponentState::OKToEndSim));
1112  component_state_ = static_cast<ComponentState>(
1113  static_cast<uint8_t>(component_state_) & ~static_cast<uint8_t>(ComponentState::DoNotEndSim));
1114  }
1115 
1116  /**
1117  Adds Extension to the component_state_
1118  */
1119  void setAsExtension()
1120  {
1121  component_state_ = static_cast<ComponentState>(
1122  static_cast<uint8_t>(component_state_) | static_cast<uint8_t>(ComponentState::Extension));
1123  }
1124 
1125 
1126  friend class Core::Serialization::pvt::SerializeBaseComponentHelper;
1127 
1128 
1129  ComponentInfo* my_info_ = nullptr;
1130  Simulation_impl* sim_ = nullptr;
1131 
1132  // component_state_ is intialized as NotPrimary and !Extension
1133  ComponentState component_state_ = ComponentState::None;
1134  // bool isExtension = false;
1135 
1136  // Need to track clock handlers for checkpointing. We need to
1137  // know what clock handlers we have registered with the core
1138  std::vector<Clock::HandlerBase*> clock_handlers_;
1139  std::set<SimTime_t> registered_clocks_;
1140 
1141  void addSelfLink(const std::string& name);
1142  Link* getLinkFromParentSharedPort(const std::string& port, std::vector<ConfigPortModule>& port_modules);
1143 
1144  using StatNameMap = std::map<std::string, std::map<std::string, Statistics::StatisticBase*>>;
1145 
1146  ConfigPortModule& getPortModuleConfig(PortModuleId_t);
1147 
1148  static thread_local std::pair<ComponentId_t, PortModuleId_t> port_module_id_;
1149 
1150  std::vector<PortModule*> port_modules_;
1151 
1152  std::map<StatisticId_t, Statistics::StatisticBase*>
1153  explicitly_enabled_shared_stats_; // Lookup structure to determine if an explicitly enabled shared stat has
1154  // already been registered. In this context, a shared stat is one that has
1155  // been piped to a different user-defined name in the config.
1156  std::map<StatisticId_t, StatNameMap>
1157  explicitly_enabled_unique_stats_; // Lookup structure to determine if an explicitly enabled non-shared stat has
1158  // been registered.
1159  StatNameMap enabled_all_stats_;
1160 
1161  BaseComponent* getParentComponent()
1162  {
1163  ComponentInfo* base_info = my_info_;
1164  while ( base_info->parent_info ) {
1165  base_info = base_info->parent_info;
1166  }
1167  return base_info->component;
1168  }
1169 };
1170 
1171 /**
1172  Used to load SubComponents when multiple SubComponents are loaded
1173  into a single slot (will also also work when a single SubComponent
1174  is loaded).
1175  */
1177 {
1178 
1179  BaseComponent* comp;
1180  std::string slot_name;
1181  int max_slot_index;
1182 
1183 public:
1184  ~SubComponentSlotInfo() {}
1185 
1186  SubComponentSlotInfo(BaseComponent* comp, const std::string& slot_name) :
1187  comp(comp),
1188  slot_name(slot_name)
1189  {
1190  const std::map<ComponentId_t, ComponentInfo>& subcomps = comp->my_info_->getSubComponents();
1191 
1192  // Look for all subcomponents with the right slot name
1193  max_slot_index = -1;
1194  for ( auto& ci : subcomps ) {
1195  if ( ci.second.getSlotName() == slot_name ) {
1196  if ( ci.second.getSlotNum() > static_cast<int>(max_slot_index) ) {
1197  max_slot_index = ci.second.getSlotNum();
1198  }
1199  }
1200  }
1201  }
1202 
1203  const std::string& getSlotName() const { return slot_name; };
1204 
1205  bool isPopulated(int slot_num) const
1206  {
1207  if ( slot_num > max_slot_index ) return false;
1208  if ( comp->my_info_->findSubComponent(slot_name, slot_num) == nullptr ) return false;
1209  return true;
1210  }
1211 
1212  bool isAllPopulated() const
1213  {
1214  for ( int i = 0; i < max_slot_index; ++i ) {
1215  if ( comp->my_info_->findSubComponent(slot_name, i) == nullptr ) return false;
1216  }
1217  return true;
1218  }
1219 
1220  int getMaxPopulatedSlotNumber() const { return max_slot_index; }
1221 
1222  /**
1223  Check to see if the element type loaded by the user into the
1224  specified slot index is loadable with a particular API.
1225 
1226  @param slot_num Slot index to check
1227  @return True if loadable as the API specified as the template parameter
1228  */
1229  template <class T>
1230  bool isLoadableUsingAPI(int slot_num)
1231  {
1232  return comp->isUserSubComponentLoadableUsingAPIByIndex<T>(slot_name, slot_num);
1233  }
1234 
1235  // Create functions that support the new API
1236 
1237  /**
1238  Create a user defined subcomponent (defined in input file to
1239  SST run). This call will pass SHARE_NONE to the new
1240  subcomponent and will not take constructor arguments. If
1241  constructor arguments are needed for the API that is being
1242  loaded, the full call to create will need to be used
1243  create(slot_num, share_flags, args...).
1244 
1245  @param slot_num Slot index from which to load subcomponent
1246 
1247  This function supports the new API, but is identical to an
1248  existing API call. It will try to load using new API and will
1249  fallback to old if unsuccessful.
1250  */
1251  template <typename T>
1252  T* create(int slot_num) const
1253  {
1254  Params empty;
1255  return comp->loadUserSubComponentByIndex<T>(slot_name, slot_num, ComponentInfo::SHARE_NONE);
1256  // return private_create<T>(slot_num, empty);
1257  }
1258 
1259  /**
1260  Create a user defined subcomponent (defined in input file to SST
1261  run).
1262 
1263  @param slot_num Slot index from which to load subcomponent
1264  @param share_flags Share flags to be used by subcomponent
1265  @param args Arguments to be passed to constructor. This
1266  signature is defined in the API definition
1267 
1268  For ease in backward compatibility to old API, this call will
1269  try to load using new API and will fallback to old if
1270  unsuccessful.
1271  */
1272  template <class T, class... ARGS>
1273  T* create(int slot_num, uint64_t share_flags, ARGS... args) const
1274  {
1275  return comp->loadUserSubComponentByIndex<T, ARGS...>(slot_name, slot_num, share_flags, args...);
1276  }
1277 
1278  /**
1279  Create all user defined subcomponents (defined in input file to SST
1280  run) for the slot.
1281 
1282  @param vec Vector of T* that will hold the pointers to the new
1283  subcomponents. If an index is not occupied, a nullptr will be
1284  put in it's place. All components will be added to the end of
1285  the vector, so index N will be at vec.length() + N, where
1286  vec.length() is the length of the vector when it is passed to
1287  the call.
1288  @param share_flags Share flags to be used by subcomponent
1289  @param args Arguments to be passed to constructor. This
1290  signature is defined in the API definition
1291 
1292  For ease in backward compatibility to old API, this call will
1293  try to load using new API and will fallback to old if
1294  unsuccessful.
1295  */
1296  template <typename T, class... ARGS>
1297  void createAll(std::vector<T*>& vec, uint64_t share_flags, ARGS... args) const
1298  {
1299  for ( int i = 0; i <= getMaxPopulatedSlotNumber(); ++i ) {
1300  T* sub = create<T>(i, share_flags, args...);
1301  vec.push_back(sub);
1302  }
1303  }
1304 
1305  /**
1306  Create all user defined subcomponents (defined in input file to SST
1307  run) for the slot.
1308 
1309  @param vec Vector of pair<int,T*> that will hold the pointers
1310  to the new subcomponents. The int will hold the index from
1311  which the subcomponent wass loaded. Unoccupied indexes will be
1312  skipped. All components will be added to the end of the
1313  vector.
1314  @param share_flags Share flags to be used by subcomponent
1315  @param args Arguments to be passed to constructor. This
1316  signature is defined in the API definition
1317 
1318  For ease in backward compatibility to old API, this call will
1319  try to load using new API and will fallback to old if
1320  unsuccessful.
1321  */
1322  template <typename T, class... ARGS>
1323  void createAllSparse(std::vector<std::pair<int, T*>>& vec, uint64_t share_flags, ARGS... args) const
1324  {
1325  for ( int i = 0; i <= getMaxPopulatedSlotNumber(); ++i ) {
1326  T* sub = create<T>(i, share_flags, args...);
1327  if ( sub != nullptr ) vec.push_back(i, sub);
1328  }
1329  }
1330 
1331  /**
1332  Create all user defined subcomponents (defined in input file to SST
1333  run) for the slot.
1334 
1335  @param vec Vector of T* that will hold the pointers
1336  to the new subcomponents. Unoccupied indexes will be
1337  skipped. All components will be added to the end of the
1338  vector.
1339  @param share_flags Share flags to be used by subcomponent
1340  @param args Arguments to be passed to constructor. This
1341  signature is defined in the API definition
1342 
1343  For ease in backward compatibility to old API, this call will
1344  try to load using new API and will fallback to old if
1345  unsuccessful.
1346  */
1347  template <typename T, class... ARGS>
1348  void createAllSparse(std::vector<T*>& vec, uint64_t share_flags, ARGS... args) const
1349  {
1350  for ( int i = 0; i <= getMaxPopulatedSlotNumber(); ++i ) {
1351  T* sub = create<T>(i, share_flags, args...);
1352  if ( sub != nullptr ) vec.push_back(sub);
1353  }
1354  }
1355 };
1356 
1357 namespace Core::Serialization {
1358 
1359 namespace pvt {
1361 {
1362 public:
1363  static void size_basecomponent(serializable_base* s, serializer& ser);
1364 
1365  static void pack_basecomponent(serializable_base* s, serializer& ser);
1366 
1367  static void unpack_basecomponent(serializable_base*& s, serializer& ser);
1368 
1369  static void map_basecomponent(serializable_base*& s, serializer& ser, const std::string& name);
1370 };
1371 
1372 } // namespace pvt
1373 
1374 
1375 template <class T>
1376 class serialize_impl<T*, std::enable_if_t<std::is_base_of_v<SST::BaseComponent, T>>>
1377 {
1378  void operator()(T*& s, serializer& ser, ser_opt_t UNUSED(options))
1379  {
1380  serializable_base* sp = static_cast<serializable_base*>(s);
1381  switch ( ser.mode() ) {
1382  case serializer::SIZER:
1383  pvt::SerializeBaseComponentHelper::size_basecomponent(sp, ser);
1384  break;
1385  case serializer::PACK:
1386  pvt::SerializeBaseComponentHelper::pack_basecomponent(sp, ser);
1387  break;
1388  case serializer::UNPACK:
1389  pvt::SerializeBaseComponentHelper::unpack_basecomponent(sp, ser);
1390  break;
1391  case serializer::MAP:
1392  pvt::SerializeBaseComponentHelper::map_basecomponent(sp, ser, ser.getMapName());
1393  break;
1394  }
1395  s = static_cast<T*>(sp);
1396  }
1397 
1398  SST_FRIEND_SERIALIZE();
1399 };
1400 
1401 } // namespace Core::Serialization
1402 
1403 } // namespace SST
1404 
1405 #endif // SST_CORE_BASECOMPONENT_H
Output object provides consistent method for outputting data to stdout, stderr and/or sst debug file...
Definition: output.h:57
ComponentId_t getId() const
Returns unique component ID.
Definition: baseComponent.h:90
virtual void complete(unsigned int UNUSED(phase))
Used during the complete phase after the end of simulation.
Definition: baseComponent.h:114
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:42
Base template for handlers which take a class defined argument.
Definition: ssthandler.h:109
const std::string & getParentComponentName() const
Returns the name of the parent Component, or, if called on a Component, the name of that Component...
Definition: baseComponent.h:105
void fatal(uint32_t line, const char *file, const char *func, int exit_code, const char *format,...) const
Output the fatal message with formatting as specified by the format parameter.
Definition: output.cc:156
virtual void printStatus(Output &UNUSED(out))
Called by the Simulation to request that the component print it&#39;s current status. ...
Definition: baseComponent.h:131
bool isSubComponentLoadableUsingAPI(const std::string &type)
Check to see if a given element type is loadable with a particular API.
Definition: baseComponent.h:675
T::ProfilePoint * registerProfilePoint(const std::string &pointName)
Registers a profiling point.
Definition: baseComponent.h:624
SSTHandlerBase< bool, Cycle_t > HandlerBase
Base handler for clock functions.
Definition: clock.h:43
SSTHandlerBase< void, Event * > HandlerBase
Base handler for event delivery.
Definition: event.h:48
A class to convert between a component&#39;s view of time and the core&#39;s view of time.
Definition: timeConverter.h:27
Main component object for the simulation.
Definition: component.h:30
virtual void finish()
Called after complete phase, but before objects are destroyed.
Definition: baseComponent.h:121
T * create(int slot_num, uint64_t share_flags, ARGS... args) const
Create a user defined subcomponent (defined in input file to SST run).
Definition: baseComponent.h:1273
T * loadUserSubComponent(const std::string &slot_name)
Loads a user defined subcomponent (defined in input file to SST run).
Definition: baseComponent.h:763
Base serialize class.
Definition: serialize.h:113
Forms the base class for statistics gathering within SST.
Definition: statbase.h:49
ComponentExtension is a class that can be loaded using loadComponentExtension<T>(...).
Definition: componentExtension.h:28
Definition: action.cc:18
virtual void emergencyShutdown()
Called when SIGINT or SIGTERM has been seen.
Definition: baseComponent.h:98
Forms the template defined base class for statistics gathering within SST.
Definition: elementinfo.h:46
virtual void setup()
Called after all components have been constructed and initialization has completed, but before simulation time has begun.
Definition: baseComponent.h:118
bool isUserSubComponentLoadableUsingAPI(const std::string &slot_name)
Check to see if the element type loaded by the user into the.
Definition: baseComponent.h:690
void createAll(std::vector< T *> &vec, uint64_t share_flags, ARGS... args) const
Create all user defined subcomponents (defined in input file to SST run) for the slot.
Definition: baseComponent.h:1297
Definition: serializable_base.h:119
Definition: rankInfo.h:23
T * loadModule(const std::string &type, Params &params, ARGS... args)
Loads a module from an element Library.
Definition: baseComponent.h:649
T * loadAnonymousSubComponent(const std::string &type, const std::string &slot_name, int slot_num, uint64_t share_flags, Params &params, ARGS... args)
Loads an anonymous subcomponent (not defined in input file to SST run).
Definition: baseComponent.h:732
Main component object for the simulation.
Definition: baseComponent.h:64
Definition: output.h:65
bool isLoadableUsingAPI(int slot_num)
Check to see if the element type loaded by the user into the specified slot index is loadable with a ...
Definition: baseComponent.h:1230
void createAllSparse(std::vector< std::pair< int, T *>> &vec, uint64_t share_flags, ARGS... args) const
Create all user defined subcomponents (defined in input file to SST run) for the slot.
Definition: baseComponent.h:1323
Statistics::Statistic< T > * registerStatistic(SST::Params &params, const std::string &stat_name, const std::string &stat_sub_id="")
Registers a statistic.
Definition: baseComponent.h:572
SimTime_t getCurrentSimTime() const
Return the simulated time since the simulation began in the default timebase.
Definition: baseComponent.h:167
virtual bool Status()
Currently unused function.
Definition: baseComponent.h:124
Parameter store.
Definition: params.h:63
void setDefaultTimeBase(TimeConverter tc)
Manually set the default defaultTimeBase.
Definition: baseComponent.h:940
T * loadUserSubComponent(const std::string &slot_name, uint64_t share_flags, ARGS... args)
Loads a user defined subcomponent (defined in input file to SST run).
Definition: baseComponent.h:782
T * create(int slot_num) const
Create a user defined subcomponent (defined in input file to SST run).
Definition: baseComponent.h:1252
Definition: componentInfo.h:44
Used to load SubComponents when multiple SubComponents are loaded into a single slot (will also also ...
Definition: baseComponent.h:1176
void createAllSparse(std::vector< T *> &vec, uint64_t share_flags, ARGS... args) const
Create all user defined subcomponents (defined in input file to SST run) for the slot.
Definition: baseComponent.h:1348
uint8_t getStatisticLoadLevel() const
Returns Component Statistic load level.
Definition: baseComponent.h:93
Definition: elementinfo.h:44
Class that can attach to Clock and Event Handlers to monitor the state of variables.
Definition: watchPoint.h:27
An SST core component that handles timing and event processing informing all registered Statistics to...
Definition: statengine.h:54
Performs Unit math in full precision.
Definition: unitAlgebra.h:105
PortModules are modules that can be attached to the send and/or receive side of ports.
Definition: portModule.h:50
void setDefaultTimeBase(TimeConverter *tc)
Manually set the default defaultTimeBase.
Definition: baseComponent.h:934
SubComponent is a class loadable through the factory which allows dynamic functionality to be added t...
Definition: subcomponent.h:28
const std::vector< double > & getCoordinates() const
Retrieve the X,Y,Z coordinates of this component.
Definition: baseComponent.h:921
const std::string & getName() const
Returns Component/SubComponent Name.
Definition: baseComponent.h:101
virtual void init(unsigned int UNUSED(phase))
Used during the init phase.
Definition: baseComponent.h:110