SST  12.0.1
StructuralSimulationToolkit
baseComponent.h
1 // Copyright 2009-2022 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-2022, 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/oneshot.h"
20 #include "sst/core/simulation.h"
21 #include "sst/core/sst_types.h"
22 #include "sst/core/statapi/statbase.h"
23 #include "sst/core/statapi/statengine.h"
24 #include "sst/core/warnmacros.h"
25 
26 #include <map>
27 #include <string>
28 
29 using namespace SST::Statistics;
30 
31 namespace SST {
32 
33 class Component;
34 class ComponentExtension;
35 class Clock;
36 class Link;
37 class LinkMap;
38 class Module;
39 class Params;
40 class Simulation_impl;
41 class SubComponent;
42 class SubComponentSlotInfo;
43 class TimeConverter;
44 class UnitAlgebra;
45 
46 /**
47  * Main component object for the simulation.
48  */
50 {
51 
52  friend class ComponentExtension;
53  friend class ComponentInfo;
54  friend class SubComponent;
55  friend class SubComponentSlotInfo;
56 
57 protected:
58  using StatCreateFunction = std::function<Statistics::StatisticBase*(
59  BaseComponent*, Statistics::StatisticProcessingEngine*, const std::string& /*type*/,
60  const std::string& /*name*/, const std::string& /*subId*/, Params&)>;
61 
62 public:
63  BaseComponent(ComponentId_t id);
64  virtual ~BaseComponent();
65 
66  const std::string& getType() const { return my_info->getType(); }
67 
68  /** Returns unique component ID */
69  inline ComponentId_t getId() const { return my_info->id; }
70 
71  /** Returns Component Statistic load level */
72  inline uint8_t getStatisticLoadLevel() const { return my_info->statLoadLevel; }
73 
74  /** Called when SIGINT or SIGTERM has been seen.
75  * Allows components opportunity to clean up external state.
76  */
77  virtual void emergencyShutdown(void) {}
78 
79  /** Returns Component/SubComponent Name */
80  inline const std::string& getName() const { return my_info->getName(); }
81 
82  /** Returns the name of the parent Component, or, if called on a
83  * Component, the name of that Component. */
84  inline const std::string& getParentComponentName() const { return my_info->getParentComponentName(); }
85 
86  /** Used during the init phase. The method will be called each
87  phase of initialization. Initialization ends when no components
88  have sent any data. */
89  virtual void init(unsigned int UNUSED(phase)) {}
90  /** Used during the complete phase after the end of simulation.
91  The method will be called each phase of complete. Complete phase
92  ends when no components have sent any data. */
93  virtual void complete(unsigned int UNUSED(phase)) {}
94  /** Called after all components have been constructed and
95  initialization has completed, but before simulation time has
96  begun. */
97  virtual void setup() {}
98  /** Called after complete phase, but before objects are
99  destroyed. A good place to print out statistics. */
100  virtual void finish() {}
101 
102  /** Currently unused function */
103  virtual bool Status() { return 0; }
104 
105  /**
106  * Called by the Simulation to request that the component
107  * print it's current status. Useful for debugging.
108  * @param out The Output class which should be used to print component status.
109  */
110  virtual void printStatus(Output& UNUSED(out)) { return; }
111 
112  /** Get the core timebase */
113  UnitAlgebra getCoreTimeBase() const;
114  /** Return the current simulation time as a cycle count*/
115  SimTime_t getCurrentSimCycle() const;
116  /** Return the current priority */
117  int getCurrentPriority() const;
118  /** Return the elapsed simulation time as a time */
119  UnitAlgebra getElapsedSimTime() const;
120  /** Return the end simulation time as a cycle count*/
121  SimTime_t getEndSimCycle() const;
122  /** Return the end simulation time as a time */
123  UnitAlgebra getEndSimTime() const;
124  /** Return the end simulation time as a time */
125  UnitAlgebra getFinalSimTime() const
126  __attribute__((deprecated("getFinalSimTime() has been deprecated and will be removed in SST 13. It has been "
127  "replaced by getEndSimTime().")));
128  /** Get this instance's parallel rank */
129  RankInfo getRank() const;
130  /** Get the number of parallel ranks in the simulation */
131  RankInfo getNumRanks() const;
132  /** Return the base simulation Output class instance */
133  Output& getSimulationOutput() const;
134 
135  /** return the time since the simulation began in units specified by
136  the parameter.
137  @param tc TimeConverter specifying the units */
138  SimTime_t getCurrentSimTime(TimeConverter* tc) const;
139  /** return the time since the simulation began in the default timebase */
140  inline SimTime_t getCurrentSimTime() const { return getCurrentSimTime(my_info->defaultTimeBase); }
141  /** return the time since the simulation began in timebase specified
142  @param base Timebase frequency in SI Units */
143  SimTime_t getCurrentSimTime(const std::string& base) const;
144 
145  /** Utility function to return the time since the simulation began in nanoseconds */
146  SimTime_t getCurrentSimTimeNano() const;
147  /** Utility function to return the time since the simulation began in microseconds */
148  SimTime_t getCurrentSimTimeMicro() const;
149  /** Utility function to return the time since the simulation began in milliseconds */
150  SimTime_t getCurrentSimTimeMilli() const;
151 
152  /** Get the amount of real-time spent executing the run phase of
153  * the simulation.
154  *
155  * @return real-time in seconds spent executing the run phase
156  */
157  double getRunPhaseElapsedRealTime() const;
158 
159  /** Get the amount of real-time spent executing the init phase of
160  * the simulation.
161  *
162  * @return real-time in seconds spent executing the init phase
163  */
164  double getInitPhaseElapsedRealTime() const;
165 
166  /** Get the amount of real-time spent executing the complete phase of
167  * the simulation.
168  *
169  * @return real-time in seconds spent executing the complete phase
170  */
171  double getCompletePhaseElapsedRealTime() const;
172 
173 
174 protected:
175  /** Check to see if the run mode was set to INIT
176  @return true if simulation run mode is set to INIT
177  */
178  bool isSimulationRunModeInit() const;
179 
180  /** Check to see if the run mode was set to RUN
181  @return true if simulation run mode is set to RUN
182  */
183  bool isSimulationRunModeRun() const;
184 
185  /** Check to see if the run mode was set to BOTH
186  @return true if simulation run mode is set to BOTH
187  */
188  bool isSimulationRunModeBoth() const;
189 
190  /** Returns the output directory of the simulation
191  * @return Directory in which simulation outputs should be
192  * placed. Returns empty string if output directory not set by
193  * user.
194  */
195  std::string& getOutputDirectory() const;
196 
197  /** Signifies that a library is required for this simulation.
198  * Causes the Factory to verify that the required library is
199  * loaded.
200  *
201  * NOTE: This function should rarely be required, as most
202  * dependencies are automatically detected in the simulator core.
203  * However, if the component uses an event from another library
204  * that is not wholly defined in a header file, this call may be
205  * required to ensure that all the code from the event is loaded.
206  * Similarly, if you use a class from another library that does
207  * not have ELI information, this call may also be required to
208  * make sure all dependencies are loaded.
209  *
210  * @param name Name of library this BaseComponent depends on
211  */
212  void requireLibrary(const std::string& name);
213 
214 
215  /** Determine if a port name is connected to any links */
216  bool isPortConnected(const std::string& name) const;
217 
218  /** Configure a Link
219  * @param name - Port Name on which the link to configure is attached.
220  * @param time_base - Time Base of the link. If nullptr is passed in, then it
221  * will use the Component defaultTimeBase
222  * @param handler - Optional Handler to be called when an Event is received
223  * @return A pointer to the configured link, or nullptr if an error occured.
224  */
225  Link* configureLink(const std::string& name, TimeConverter* time_base, Event::HandlerBase* handler = nullptr);
226  /** Configure a Link
227  * @param name - Port Name on which the link to configure is attached.
228  * @param time_base - Time Base of the link as a string
229  * @param handler - Optional Handler to be called when an Event is received
230  * @return A pointer to the configured link, or nullptr if an error occured.
231  */
232  Link* configureLink(const std::string& name, const std::string& time_base, Event::HandlerBase* handler = nullptr);
233  /** Configure a Link
234  * @param name - Port Name on which the link to configure is attached.
235  * @param time_base - Time Base of the link as a UnitAlgebra
236  * @param handler - Optional Handler to be called when an Event is received
237  * @return A pointer to the configured link, or nullptr if an error occured.
238  */
239  Link* configureLink(const std::string& name, const UnitAlgebra& time_base, Event::HandlerBase* handler = nullptr);
240  /** Configure a Link
241  * @param name - Port Name on which the link to configure is attached.
242  * @param handler - Optional Handler to be called when an Event is received
243  * @return A pointer to the configured link, or nullptr if an error occured.
244  */
245  Link* configureLink(const std::string& name, Event::HandlerBase* handler = nullptr);
246 
247  /** Configure a SelfLink (Loopback link)
248  * @param name - Name of the self-link port
249  * @param time_base - Time Base of the link. If nullptr is passed in, then it
250  * will use the Component defaultTimeBase
251  * @param handler - Optional Handler to be called when an Event is received
252  * @return A pointer to the configured link, or nullptr if an error occured.
253  */
254  Link* configureSelfLink(const std::string& name, TimeConverter* time_base, Event::HandlerBase* handler = nullptr);
255  /** Configure a SelfLink (Loopback link)
256  * @param name - Name of the self-link port
257  * @param time_base - Time Base of the link as a string
258  * @param handler - Optional Handler to be called when an Event is received
259  * @return A pointer to the configured link, or nullptr if an error occured.
260  */
261  Link*
262  configureSelfLink(const std::string& name, const std::string& time_base, Event::HandlerBase* handler = nullptr);
263  /** Configure a SelfLink (Loopback link)
264  * @param name - Name of the self-link port
265  * @param time_base - Time Base of the link as a UnitAlgebra
266  * @param handler - Optional Handler to be called when an Event is received
267  * @return A pointer to the configured link, or nullptr if an error occured.
268  */
269  Link*
270  configureSelfLink(const std::string& name, const UnitAlgebra& time_base, Event::HandlerBase* handler = nullptr);
271  /** Configure a SelfLink (Loopback link)
272  * @param name - Name of the self-link port
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  Link* configureSelfLink(const std::string& name, Event::HandlerBase* handler = nullptr);
277 
278  /** Registers a clock for this component.
279  @param freq Frequency for the clock in SI units
280  @param handler Pointer to Clock::HandlerBase which is to be invoked
281  at the specified interval
282  @param regAll Should this clock period be used as the default
283  time base for all of the links connected to this component
284  @return the TimeConverter object representing the clock frequency
285  */
286  TimeConverter* registerClock(const std::string& freq, Clock::HandlerBase* handler, bool regAll = true);
287 
288  /** Registers a clock for this component.
289  @param freq Frequency for the clock as a UnitAlgebra object
290  @param handler Pointer to Clock::HandlerBase which is to be invoked
291  at the specified interval
292  @param regAll Should this clock period be used as the default
293  time base for all of the links connected to this component
294  @return the TimeConverter object representing the clock frequency
295  */
296  TimeConverter* registerClock(const UnitAlgebra& freq, Clock::HandlerBase* handler, bool regAll = true);
297 
298  /** Registers a clock for this component.
299  @param tc TimeConverter object specifying the clock frequency
300  @param handler Pointer to Clock::HandlerBase which is to be invoked
301  at the specified interval
302  @param regAll Should this clock period be used as the default
303  time base for all of the links connected to this component
304  @return the TimeConverter object representing the clock frequency
305  */
306  TimeConverter* registerClock(TimeConverter* tc, Clock::HandlerBase* handler, bool regAll = true);
307 
308  /** Removes a clock handler from the component */
309  void unregisterClock(TimeConverter* tc, Clock::HandlerBase* handler);
310 
311  /** Reactivates an existing Clock and Handler
312  * @return time of next time clock handler will fire
313  */
314  Cycle_t reregisterClock(TimeConverter* freq, Clock::HandlerBase* handler);
315  /** Returns the next Cycle that the TimeConverter would fire */
316  Cycle_t getNextClockCycle(TimeConverter* freq);
317 
318  /** Registers a default time base for the component and optionally
319  sets the the component's links to that timebase. Useful for
320  components which do not have a clock, but would like a default
321  timebase.
322  @param base Frequency for the clock in SI units
323  @param regAll Should this clock period be used as the default
324  time base for all of the links connected to this component
325  */
326  TimeConverter* registerTimeBase(const std::string& base, bool regAll = true);
327 
328  TimeConverter* getTimeConverter(const std::string& base) const;
329  TimeConverter* getTimeConverter(const UnitAlgebra& base) const;
330 
331  bool isStatisticShared(const std::string& statName, bool include_me = false)
332  {
333  if ( include_me ) {
334  if ( doesComponentInfoStatisticExist(statName) ) { return true; }
335  }
336  if ( my_info->sharesStatistics() ) {
337  return my_info->parent_info->component->isStatisticShared(statName, true);
338  }
339  else {
340  return false;
341  }
342  }
343 
344  template <typename T>
345  Statistics::Statistic<T>*
346  createStatistic(SST::Params& params, StatisticId_t id, const std::string& name, const std::string& statSubId)
347  {
348  /* I would prefer to avoid this std::function with dynamic cast,
349  * but the code is just a lot cleaner and avoids many unnecessary template instantiations
350  * doing it this way. At some point in the future, we would need to clean up
351  * the rule around enabling all statistics to make this better
352  */
353 
354  StatCreateFunction create = [=](BaseComponent* comp, Statistics::StatisticProcessingEngine* engine,
355  const std::string& type, const std::string& name, const std::string& subId,
356  SST::Params& params) -> Statistics::StatisticBase* {
357  return engine->createStatistic<T>(comp, type, name, subId, params);
358  };
359 
360  // We follow two distinct paths depending on if it is enable all, versus explicitly enabled
361  // Enable all is "scoped" to the (sub)component
362  // Explicitly enabled stats are assigned component-unique IDs and can be shared across subcomponents
363  // so creation and management happens in the parent component
364  Statistics::StatisticBase* base_stat =
365  id == STATALL_ID ? createEnabledAllStatistic(params, name, statSubId, std::move(create))
366  : getParentComponent()->createExplicitlyEnabledStatistic(
367  params, id, name, statSubId, std::move(create));
368 
369  // Ugh, dynamic casts hurt my eyes, but I must do this
370  auto* statistic = dynamic_cast<Statistics::Statistic<T>*>(base_stat);
371  if ( statistic ) { return statistic; }
372  else {
373  fatal(
374  __LINE__, __FILE__, "createStatistic", 1, "failed to cast created statistic '%s' to expected type",
375  name.c_str());
376  return nullptr; // avoid compiler warnings
377  }
378  }
379 
380  template <typename T>
381  Statistics::Statistic<T>*
382  createNullStatistic(SST::Params& params, const std::string& name, const std::string& statSubId = "")
383  {
384  auto* engine = Statistics::StatisticProcessingEngine::getInstance();
385  return engine->createStatistic<T>(my_info->component, "sst.NullStatistic", name, statSubId, params);
386  }
387 
388  /** Registers a statistic.
389  If Statistic is allowed to run (controlled by Python runtime parameters),
390  then a statistic will be created and returned. If not allowed to run,
391  then a NullStatistic will be returned. In either case, the returned
392  value should be used for all future Statistic calls. The type of
393  Statistic and the Collection Rate is set by Python runtime parameters.
394  If no type is defined, then an Accumulator Statistic will be provided
395  by default. If rate set to 0 or not provided, then the statistic will
396  output results only at end of sim (if output is enabled).
397  @param statName Primary name of the statistic. This name must match the
398  defined ElementInfoStatistic in the component, and must also
399  be enabled in the Python input file.
400  @param statSubId An additional sub name for the statistic
401  @return Either a created statistic of desired type or a NullStatistic
402  depending upon runtime settings.
403  */
404  template <typename T>
406  SST::Params& params, const std::string& statName, const std::string& statSubId = "", bool inserting = false)
407  {
408  if ( my_info->enabledStatNames ) {
409  auto iter = my_info->enabledStatNames->find(statName);
410  if ( iter != my_info->enabledStatNames->end() ) {
411  // valid, enabled statistic
412  // During initialization, the component should have assigned a mapping between
413  // the local name and globally unique stat ID
414  StatisticId_t id = iter->second;
415  return createStatistic<T>(params, id, statName, statSubId);
416  }
417  }
418 
419  // if we got here, this is not a stat we explicitly enabled
420  if ( inserting || doesComponentInfoStatisticExist(statName) ) {
421  // this is a statistic that I registered
422  if ( my_info->enabledAllStats ) { return createStatistic<T>(params, STATALL_ID, statName, statSubId); }
423  else if ( my_info->parent_info && my_info->canInsertStatistics() ) {
424  // I did not explicitly enable nor enable all
425  // but I can insert statistics into my parent
426  // and my parent may have enabled all
427  return my_info->parent_info->component->registerStatistic<T>(params, statName, statSubId, true);
428  }
429  else {
430  // I did not enable, I cannot insert into parent - so send back null stat
431  return my_info->component->createNullStatistic<T>(params, statName, statSubId);
432  }
433  }
434  else if ( my_info->parent_info && my_info->sharesStatistics() ) {
435  // this is not a statistic that I registered
436  // but my parent can share statistics, maybe they enabled
437  return my_info->parent_info->component->registerStatistic<T>(params, statName, statSubId);
438  }
439  else {
440  // not a valid stat and I won't be able to share my parent's statistic
441  fatal(
442  __LINE__, __FILE__, "registerStatistic", 1, "attempting to register unknown statistic '%s'",
443  statName.c_str());
444  return nullptr; // get rid of warning
445  }
446  }
447 
448  template <typename T>
449  Statistics::Statistic<T>* registerStatistic(const std::string& statName, const std::string& statSubId = "")
450  {
451  SST::Params empty {};
452  return registerStatistic<T>(empty, statName, statSubId);
453  }
454 
455  template <typename... Args>
456  Statistics::Statistic<std::tuple<Args...>>*
457  registerMultiStatistic(const std::string& statName, const std::string& statSubId = "")
458  {
459  SST::Params empty {};
460  return registerStatistic<std::tuple<Args...>>(empty, statName, statSubId);
461  }
462 
463  template <typename... Args>
464  Statistics::Statistic<std::tuple<Args...>>*
465  registerMultiStatistic(SST::Params& params, const std::string& statName, const std::string& statSubId = "")
466  {
467  return registerStatistic<std::tuple<Args...>>(params, statName, statSubId);
468  }
469 
470  template <typename T>
471  Statistics::Statistic<T>* registerStatistic(const char* statName, const char* statSubId = "")
472  {
473  return registerStatistic<T>(std::string(statName), std::string(statSubId));
474  }
475 
476  /** Called by the Components and Subcomponent to perform a statistic Output.
477  * @param stat - Pointer to the statistic.
478  * @param EndOfSimFlag - Indicates that the output is occurring at the end of simulation.
479  */
480  void performStatisticOutput(Statistics::StatisticBase* stat);
481 
482  /** Performs a global statistic Output.
483  * This routine will force ALL Components and Subcomponents to output their statistic information.
484  * This may lead to unexpected results if the statistic counts or data is reset on output.
485  * NOTE: Currently, this function will only output statistics that are on the same rank.
486  */
487  void performGlobalStatisticOutput();
488 
489  /** Loads a module from an element Library
490  * @param type Fully Qualified library.moduleName
491  * @param params Parameters the module should use for configuration
492  * @return handle to new instance of module, or nullptr on failure.
493  */
494  Module* loadModule(const std::string& type, Params& params)
495  __attribute__((deprecated("This version of loadModule() has been deprecated. Please use the new templated "
496  "version that uses Module APIs")));
497 
498  /** Loads a module from an element Library
499  * @param type Fully Qualified library.moduleName
500  * @param params Parameters the module should use for configuration
501  * @return handle to new instance of module, or nullptr on failure.
502  */
503  template <class T, class... ARGS>
504  T* loadModule(const std::string& type, Params& params, ARGS... args)
505  {
506 
507  // Check to see if this can be loaded with new API or if we have to fallback to old
508  return Factory::getFactory()->CreateWithParams<T>(type, params, params, args...);
509  }
510 
511 protected:
512  // When you direct load, the ComponentExtension does not need any
513  // ELI information and if it has any, it will be ignored. The
514  // extension will be loaded as if it were part of the parent
515  // BaseComponent and will share all that components ELI
516  // information.
517  template <class T, class... ARGS>
518  T* loadComponentExtension(ARGS... args)
519  {
520  ComponentExtension* ret = new T(my_info->id, args...);
521  return static_cast<T*>(ret);
522  }
523 
524  /**
525  Check to see if a given element type is loadable with a particular API
526 
527  @param name - Name of element to check in lib.name format
528  @return True if loadable as the API specified as the template parameter
529  */
530  template <class T>
531  bool isSubComponentLoadableUsingAPI(const std::string& type)
532  {
533  return Factory::getFactory()->isSubComponentLoadableUsingAPI<T>(type);
534  }
535 
536  /**
537  Check to see if the element type loaded by the user into the.
538  specified slot is loadable with a particular API. This will
539  only check slot index 0. If you need to check other slots,
540  please use the SubComponentSlotInfo.
541 
542  @param slot_name - Name of slot to check
543  @return True if loadable as the API specified as the template parameter
544  */
545  template <class T>
546  bool isUserSubComponentLoadableUsingAPI(const std::string& slot_name)
547  {
548  // Get list of ComponentInfo objects and make sure that there is
549  // only one SubComponent put into this slot
550  // const std::vector<ComponentInfo>& subcomps = my_info->getSubComponents();
551  const std::map<ComponentId_t, ComponentInfo>& subcomps = my_info->getSubComponents();
552  int sub_count = 0;
553  int index = -1;
554  for ( auto& ci : subcomps ) {
555  if ( ci.second.getSlotName() == slot_name ) {
556  index = ci.second.getSlotNum();
557  sub_count++;
558  }
559  }
560 
561  if ( sub_count > 1 ) {
562  SST::Output outXX("SubComponentSlotWarning: ", 0, 0, Output::STDERR);
563  outXX.fatal(
564  CALL_INFO, 1,
565  "Error: ComponentSlot \"%s\" in component \"%s\" only allows for one SubComponent, %d provided.\n",
566  slot_name.c_str(), my_info->getType().c_str(), sub_count);
567  }
568 
569  return isUserSubComponentLoadableUsingAPIByIndex<T>(slot_name, index);
570  }
571 
572  /**
573  Loads an anonymous subcomponent (not defined in input file to
574  SST run).
575 
576  @param type tyupe of subcomponent to load in lib.name format
577  @param slot_name name of the slot to load subcomponent into
578  @param slot_num index of the slot to load subcomponent into
579  @param share_flags Share flags to be used by subcomponent
580  @param params Params object to be passed to subcomponent
581  @param args Arguments to be passed to constructor. This
582  signature is defined in the API definition
583 
584  For ease in backward compatibility to old API, this call will
585  try to load using new API and will fallback to old if
586  unsuccessful.
587  */
588  template <class T, class... ARGS>
590  const std::string& type, const std::string& slot_name, int slot_num, uint64_t share_flags, Params& params,
591  ARGS... args)
592  {
593 
594  share_flags = share_flags & ComponentInfo::USER_FLAGS;
595  ComponentId_t cid = my_info->addAnonymousSubComponent(my_info, type, slot_name, slot_num, share_flags);
596  ComponentInfo* sub_info = my_info->findSubComponent(cid);
597 
598  // This shouldn't happen since we just put it in, but just in case
599  if ( sub_info == nullptr ) return nullptr;
600 
601  // Check to see if this can be loaded with new API or if we have to fallback to old
602  if ( isSubComponentLoadableUsingAPI<T>(type) ) {
603  auto ret = Factory::getFactory()->CreateWithParams<T>(type, params, sub_info->id, params, args...);
604  return ret;
605  }
606  return nullptr;
607  }
608 
609  /**
610  Loads a user defined subcomponent (defined in input file to SST
611  run). This version does not allow share flags (set to
612  SHARE_NONE) or constructor arguments.
613 
614  @param slot_name name of the slot to load subcomponent into
615 
616  For ease in backward compatibility to old API, this call will
617  try to load using new API and will fallback to old if
618  unsuccessful.
619  */
620  template <class T>
621  T* loadUserSubComponent(const std::string& slot_name)
622  {
623  return loadUserSubComponent<T>(slot_name, ComponentInfo::SHARE_NONE);
624  }
625 
626  /**
627  Loads a user defined subcomponent (defined in input file to SST
628  run).
629 
630  @param slot_name name of the slot to load subcomponent into
631  @param share_flags Share flags to be used by subcomponent
632  @param args Arguments to be passed to constructor. This
633  signature is defined in the API definition
634 
635  For ease in backward compatibility to old API, this call will
636  try to load using new API and will fallback to old if
637  unsuccessful.
638  */
639  template <class T, class... ARGS>
640  T* loadUserSubComponent(const std::string& slot_name, uint64_t share_flags, ARGS... args)
641  {
642 
643  // Get list of ComponentInfo objects and make sure that there is
644  // only one SubComponent put into this slot
645  // const std::vector<ComponentInfo>& subcomps = my_info->getSubComponents();
646  const std::map<ComponentId_t, ComponentInfo>& subcomps = my_info->getSubComponents();
647  int sub_count = 0;
648  int index = -1;
649  for ( auto& ci : subcomps ) {
650  if ( ci.second.getSlotName() == slot_name ) {
651  index = ci.second.getSlotNum();
652  sub_count++;
653  }
654  }
655 
656  if ( sub_count > 1 ) {
657  SST::Output outXX("SubComponentSlotWarning: ", 0, 0, Output::STDERR);
658  outXX.fatal(
659  CALL_INFO, 1,
660  "Error: ComponentSlot \"%s\" in component \"%s\" only allows for one SubComponent, %d provided.\n",
661  slot_name.c_str(), my_info->getType().c_str(), sub_count);
662  }
663 
664  return loadUserSubComponentByIndex<T, ARGS...>(slot_name, index, share_flags, args...);
665  }
666 
667  /** Convenience function for reporting fatal conditions. The
668  function will create a new Output object and call fatal()
669  using the supplied parameters. Before calling
670  Output::fatal(), the function will also print other
671  information about the (sub)component that called fatal and
672  about the simulation state.
673 
674  From Output::fatal: Message will be sent to the output
675  location and to stderr. The output will be prepended with the
676  expanded prefix set in the object.
677  NOTE: fatal() will call MPI_Abort(exit_code) to terminate simulation.
678 
679  @param line Line number of calling function (use CALL_INFO macro)
680  @param file File name calling function (use CALL_INFO macro)
681  @param func Function name calling function (use CALL_INFO macro)
682  @param exit_code The exit code used for termination of simulation.
683  will be passed to MPI_Abort()
684  @param format Format string. All valid formats for printf are available.
685  @param ... Arguments for format.
686  */
687  void fatal(uint32_t line, const char* file, const char* func, int exit_code, const char* format, ...) const
688  __attribute__((format(printf, 6, 7)));
689 
690  /** Convenience function for testing for and reporting fatal
691  conditions. If the condition holds, fatal() will be called,
692  otherwise, the function will return. The function will create
693  a new Output object and call fatal() using the supplied
694  parameters. Before calling Output::fatal(), the function will
695  also print other information about the (sub)component that
696  called fatal and about the simulation state.
697 
698  From Output::fatal: Message will be sent to the output
699  location and to stderr. The output will be prepended with the
700  expanded prefix set in the object.
701  NOTE: fatal() will call MPI_Abort(exit_code) to terminate simulation.
702 
703  @param condition on which to call fatal(); fatal() is called
704  if the bool is false.
705  @param line Line number of calling function (use CALL_INFO macro)
706  @param file File name calling function (use CALL_INFO macro)
707  @param func Function name calling function (use CALL_INFO macro)
708  @param exit_code The exit code used for termination of simulation.
709  will be passed to MPI_Abort()
710  @param format Format string. All valid formats for printf are available.
711  @param ... Arguments for format.
712  */
713  void sst_assert(
714  bool condition, uint32_t line, const char* file, const char* func, int exit_code, const char* format, ...) const
715  __attribute__((format(printf, 7, 8)));
716 
717 private:
718  SimTime_t processCurrentTimeWithUnderflowedBase(const std::string& base) const;
719 
720  void
721  configureCollectionMode(Statistics::StatisticBase* statistic, const SST::Params& params, const std::string& name);
722 
723  /**
724  * @brief findExplicitlyEnabledStatistic
725  * @param params
726  * @param id
727  * @param name
728  * @param statSubId
729  * @return that matching stat if the stat already was created for the given ID, otherwise nullptr
730  */
731  Statistics::StatisticBase* createExplicitlyEnabledStatistic(
732  SST::Params& params, StatisticId_t id, const std::string& name, const std::string& statSubId,
733  StatCreateFunction create);
734 
735  /**
736  * @brief createStatistic Helper function used by both enable all and explicit enable
737  * @param cpp_params Any parameters given in C++ specific to this statistic
738  * @param python_params Any parameters given in Python for this statistic
739  * @param name The name (different from type) for this statistic
740  * @param statSubId An optional sub ID for this statistic if multiple stats might have the same name
741  * @param create A type-erased factory for creating stats of a particulary type T
742  * @return The statistic created
743  */
744  Statistics::StatisticBase* createStatistic(
745  SST::Params& cpp_params, const SST::Params& python_params, const std::string& name,
746  const std::string& statSubId, bool check_load_level, StatCreateFunction create);
747 
748  Statistics::StatisticBase* createEnabledAllStatistic(
749  SST::Params& params, const std::string& name, const std::string& statSubId, StatCreateFunction create);
750 
751  void configureAllowedStatParams(SST::Params& params);
752 
753  void setDefaultTimeBaseForLinks(TimeConverter* tc);
754 
755  void pushValidParams(Params& params, const std::string& type);
756 
757  template <class T, class... ARGS>
758  T* loadUserSubComponentByIndex(const std::string& slot_name, int slot_num, int share_flags, ARGS... args)
759  {
760 
761  share_flags = share_flags & ComponentInfo::USER_FLAGS;
762 
763  // Check to see if the slot exists
764  ComponentInfo* sub_info = my_info->findSubComponent(slot_name, slot_num);
765  if ( sub_info == nullptr ) return nullptr;
766  sub_info->share_flags = share_flags;
767  sub_info->parent_info = my_info;
768 
769  if ( isSubComponentLoadableUsingAPI<T>(sub_info->type) ) {
770  auto ret = Factory::getFactory()->CreateWithParams<T>(
771  sub_info->type, *sub_info->params, sub_info->id, *sub_info->params, args...);
772  return ret;
773  }
774  return nullptr;
775  }
776 
777  template <class T>
778  bool isUserSubComponentLoadableUsingAPIByIndex(const std::string& slot_name, int slot_num)
779  {
780  // Check to see if the slot exists
781  ComponentInfo* sub_info = my_info->findSubComponent(slot_name, slot_num);
782  if ( sub_info == nullptr ) return false;
783 
784  return isSubComponentLoadableUsingAPI<T>(sub_info->type);
785  }
786 
787  // Utility function used by fatal and sst_assert
788  void
789  vfatal(uint32_t line, const char* file, const char* func, int exit_code, const char* format, va_list arg) const;
790 
791 public:
792  SubComponentSlotInfo* getSubComponentSlotInfo(const std::string& name, bool fatalOnEmptyIndex = false);
793 
794  /** Retrieve the X,Y,Z coordinates of this component */
795  const std::vector<double>& getCoordinates() const { return my_info->coordinates; }
796 
797 protected:
799 
800  bool isAnonymous() { return my_info->isAnonymous(); }
801 
802  bool isUser() { return my_info->isUser(); }
803 
804  /** Manually set the default detaulTimeBase */
805  void setDefaultTimeBase(TimeConverter* tc) { my_info->defaultTimeBase = tc; }
806 
807  TimeConverter* getDefaultTimeBase() { return my_info->defaultTimeBase; }
808 
809  const TimeConverter* getDefaultTimeBase() const { return my_info->defaultTimeBase; }
810 
811  bool doesSubComponentExist(const std::string& type);
812 
813  /* Get the Simulation */
814  Simulation* getSimulation() const;
815 
816  // Does the statisticName exist in the ElementInfoStatistic
817  virtual bool doesComponentInfoStatisticExist(const std::string& statisticName) const;
818  // Return the EnableLevel for the statisticName from the ElementInfoStatistic
819  uint8_t getComponentInfoStatisticEnableLevel(const std::string& statisticName) const;
820  // Return the Units for the statisticName from the ElementInfoStatistic
821  // std::string getComponentInfoStatisticUnits(const std::string& statisticName) const;
822 
823 private:
824  ComponentInfo* my_info = nullptr;
825  bool isExtension;
826 
827  void addSelfLink(const std::string& name);
828  Link* getLinkFromParentSharedPort(const std::string& port);
829 
830  using StatNameMap = std::map<std::string, std::map<std::string, Statistics::StatisticBase*>>;
831 
832  std::map<StatisticId_t, Statistics::StatisticBase*> m_explicitlyEnabledSharedStats;
833  std::map<StatisticId_t, StatNameMap> m_explicitlyEnabledUniqueStats;
834  StatNameMap m_enabledAllStats;
835 
836  BaseComponent* getParentComponent()
837  {
838  ComponentInfo* base_info = my_info;
839  while ( base_info->parent_info ) {
840  base_info = base_info->parent_info;
841  }
842  return base_info->component;
843  }
844 };
845 
846 /**
847  Used to load SubComponents when multiple SubComponents are loaded
848  into a single slot (will also also work when a single SubComponent
849  is loaded).
850  */
852 {
853 
854  BaseComponent* comp;
855  std::string slot_name;
856  int max_slot_index;
857 
858 public:
860 
861  SubComponentSlotInfo(BaseComponent* comp, const std::string& slot_name) : comp(comp), slot_name(slot_name)
862  {
863  const std::map<ComponentId_t, ComponentInfo>& subcomps = comp->my_info->getSubComponents();
864 
865  // Look for all subcomponents with the right slot name
866  max_slot_index = -1;
867  for ( auto& ci : subcomps ) {
868  if ( ci.second.getSlotName() == slot_name ) {
869  if ( ci.second.getSlotNum() > static_cast<int>(max_slot_index) ) {
870  max_slot_index = ci.second.getSlotNum();
871  }
872  }
873  }
874  }
875 
876  const std::string& getSlotName() const { return slot_name; };
877 
878  bool isPopulated(int slot_num) const
879  {
880  if ( slot_num > max_slot_index ) return false;
881  if ( comp->my_info->findSubComponent(slot_name, slot_num) == nullptr ) return false;
882  return true;
883  }
884 
885  bool isAllPopulated() const
886  {
887  for ( int i = 0; i < max_slot_index; ++i ) {
888  if ( comp->my_info->findSubComponent(slot_name, i) == nullptr ) return false;
889  }
890  return true;
891  }
892 
893  int getMaxPopulatedSlotNumber() const { return max_slot_index; }
894 
895  /**
896  Check to see if the element type loaded by the user into the
897  specified slot index is loadable with a particular API.
898 
899  @param slot_num Slot index to check
900  @return True if loadable as the API specified as the template parameter
901  */
902  template <class T>
903  bool isLoadableUsingAPI(int slot_num)
904  {
905  return comp->isUserSubComponentLoadableUsingAPIByIndex<T>(slot_name, slot_num);
906  }
907 
908  // Create functions that support the new API
909 
910  /**
911  Create a user defined subcomponent (defined in input file to
912  SST run). This call will pass SHARE_NONE to the new
913  subcomponent and will not take constructor arguments. If
914  constructor arguments are needed for the API that is being
915  loaded, the full call to create will need to be used
916  create(slot_num, share_flags, args...).
917 
918  @param slot_num Slot index from which to load subcomponent
919 
920  This function supports the new API, but is identical to an
921  existing API call. It will try to load using new API and will
922  fallback to old if unsuccessful.
923  */
924  template <typename T>
925  T* create(int slot_num) const
926  {
927  Params empty;
928  return comp->loadUserSubComponentByIndex<T>(slot_name, slot_num, ComponentInfo::SHARE_NONE);
929  // return private_create<T>(slot_num, empty);
930  }
931 
932  /**
933  Create a user defined subcomponent (defined in input file to SST
934  run).
935 
936  @param slot_num Slot index from which to load subcomponent
937  @param share_flags Share flags to be used by subcomponent
938  @param args Arguments to be passed to constructor. This
939  signature is defined in the API definition
940 
941  For ease in backward compatibility to old API, this call will
942  try to load using new API and will fallback to old if
943  unsuccessful.
944  */
945  template <class T, class... ARGS>
946  T* create(int slot_num, uint64_t share_flags, ARGS... args) const
947  {
948  return comp->loadUserSubComponentByIndex<T, ARGS...>(slot_name, slot_num, share_flags, args...);
949  }
950 
951  /**
952  Create all user defined subcomponents (defined in input file to SST
953  run) for the slot.
954 
955  @param vec Vector of T* that will hold the pointers to the new
956  subcomponents. If an index is not occupied, a nullptr will be
957  put in it's place. All components will be added to the end of
958  the vector, so index N will be at vec.length() + N, where
959  vec.length() is the length of the vector when it is passed to
960  the call.
961  @param share_flags Share flags to be used by subcomponent
962  @param args Arguments to be passed to constructor. This
963  signature is defined in the API definition
964 
965  For ease in backward compatibility to old API, this call will
966  try to load using new API and will fallback to old if
967  unsuccessful.
968  */
969  template <typename T, class... ARGS>
970  void createAll(std::vector<T*>& vec, uint64_t share_flags, ARGS... args) const
971  {
972  for ( int i = 0; i <= getMaxPopulatedSlotNumber(); ++i ) {
973  T* sub = create<T>(i, share_flags, args...);
974  vec.push_back(sub);
975  }
976  }
977 
978  /**
979  Create all user defined subcomponents (defined in input file to SST
980  run) for the slot.
981 
982  @param vec Vector of pair<int,T*> that will hold the pointers
983  to the new subcomponents. The int will hold the index from
984  which the subcomponent wass loaded. Unoccupied indexes will be
985  skipped. All components will be added to the end of the
986  vector.
987  @param share_flags Share flags to be used by subcomponent
988  @param args Arguments to be passed to constructor. This
989  signature is defined in the API definition
990 
991  For ease in backward compatibility to old API, this call will
992  try to load using new API and will fallback to old if
993  unsuccessful.
994  */
995  template <typename T, class... ARGS>
996  void createAllSparse(std::vector<std::pair<int, T*>>& vec, uint64_t share_flags, ARGS... args) const
997  {
998  for ( int i = 0; i <= getMaxPopulatedSlotNumber(); ++i ) {
999  T* sub = create<T>(i, share_flags, args...);
1000  if ( sub != nullptr ) vec.push_back(i, sub);
1001  }
1002  }
1003 
1004  /**
1005  Create all user defined subcomponents (defined in input file to SST
1006  run) for the slot.
1007 
1008  @param vec Vector of T* that will hold the pointers
1009  to the new subcomponents. Unoccupied indexes will be
1010  skipped. All components will be added to the end of the
1011  vector.
1012  @param share_flags Share flags to be used by subcomponent
1013  @param args Arguments to be passed to constructor. This
1014  signature is defined in the API definition
1015 
1016  For ease in backward compatibility to old API, this call will
1017  try to load using new API and will fallback to old if
1018  unsuccessful.
1019  */
1020  template <typename T, class... ARGS>
1021  void createAllSparse(std::vector<T*>& vec, uint64_t share_flags, ARGS... args) const
1022  {
1023  for ( int i = 0; i <= getMaxPopulatedSlotNumber(); ++i ) {
1024  T* sub = create<T>(i, share_flags, args...);
1025  if ( sub != nullptr ) vec.push_back(sub);
1026  }
1027  }
1028 };
1029 
1030 } // namespace SST
1031 
1032 #endif // SST_CORE_BASECOMPONENT_H
Output object provides consistent method for outputting data to stdout, stderr and/or sst debug file...
Definition: output.h:51
Statistics::Statistic< T > * registerStatistic(SST::Params &params, const std::string &statName, const std::string &statSubId="", bool inserting=false)
Registers a statistic.
Definition: baseComponent.h:405
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:84
virtual void complete(unsigned int UNUSED(phase))
Used during the complete phase after the end of simulation.
Definition: baseComponent.h:93
Definition: ssthandler.h:100
virtual void printStatus(Output &UNUSED(out))
Called by the Simulation to request that the component print it&#39;s current status. ...
Definition: baseComponent.h:110
bool isSubComponentLoadableUsingAPI(const std::string &type)
Check to see if a given element type is loadable with a particular API.
Definition: baseComponent.h:531
ComponentId_t getId() const
Returns unique component ID.
Definition: baseComponent.h:69
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:946
A class to convert between a component&#39;s view of time and the core&#39;s view of time.
Definition: timeConverter.h:26
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:1021
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:970
virtual void finish()
Called after complete phase, but before objects are destroyed.
Definition: baseComponent.h:100
T * loadUserSubComponent(const std::string &slot_name)
Loads a user defined subcomponent (defined in input file to SST run).
Definition: baseComponent.h:621
Forms the base class for statistics gathering within SST.
Definition: statbase.h:63
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:589
ComponentExtension is a class that can be loaded using loadComponentExtension&lt;T&gt;(...).
Definition: componentExtension.h:28
virtual void emergencyShutdown(void)
Called when SIGINT or SIGTERM has been seen.
Definition: baseComponent.h:77
Forms the template defined base class for statistics gathering within SST.
Definition: elementinfo.h:42
T * loadModule(const std::string &type, Params &params, ARGS...args)
Loads a module from an element Library.
Definition: baseComponent.h:504
uint8_t getStatisticLoadLevel() const
Returns Component Statistic load level.
Definition: baseComponent.h:72
const std::vector< double > & getCoordinates() const
Retrieve the X,Y,Z coordinates of this component.
Definition: baseComponent.h:795
virtual void setup()
Called after all components have been constructed and initialization has completed, but before simulation time has begun.
Definition: baseComponent.h:97
bool isUserSubComponentLoadableUsingAPI(const std::string &slot_name)
Check to see if the element type loaded by the user into the.
Definition: baseComponent.h:546
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:155
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:640
Definition: rankInfo.h:21
Main component object for the simulation.
Definition: baseComponent.h:49
Definition: output.h:59
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:903
virtual bool Status()
Currently unused function.
Definition: baseComponent.h:103
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:996
Parameter store.
Definition: params.h:55
Definition: componentInfo.h:39
Used to load SubComponents when multiple SubComponents are loaded into a single slot (will also also ...
Definition: baseComponent.h:851
T * create(int slot_num) const
Create a user defined subcomponent (defined in input file to SST run).
Definition: baseComponent.h:925
An SST core component that handles timing and event processing informing all registered Statistics to...
Definition: statengine.h:51
const std::string & getName() const
Returns Component/SubComponent Name.
Definition: baseComponent.h:80
Performs Unit math in full precision.
Definition: unitAlgebra.h:106
void setDefaultTimeBase(TimeConverter *tc)
Manually set the default detaulTimeBase.
Definition: baseComponent.h:805
SubComponent is a class loadable through the factory which allows dynamic functionality to be added t...
Definition: subcomponent.h:28
SimTime_t getCurrentSimTime() const
return the time since the simulation began in the default timebase
Definition: baseComponent.h:140
virtual void init(unsigned int UNUSED(phase))
Used during the init phase.
Definition: baseComponent.h:89