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