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