SST  15.1.0
StructuralSimulationToolkit
factory.h
1 // Copyright 2009-2025 NTESS. Under the terms
2 // of Contract DE-NA0003525 with NTESS, the U.S.
3 // Government retains certain rights in this software.
4 //
5 // Copyright (c) 2009-2025, NTESS
6 // All rights reserved.
7 //
8 // This file is part of the SST software package. For license
9 // information, see the LICENSE file in the top level directory of the
10 // distribution.
11 
12 #ifndef SST_CORE_FACTORY_H
13 #define SST_CORE_FACTORY_H
14 
15 #include "sst/core/eli/elementinfo.h"
16 #include "sst/core/output.h"
17 #include "sst/core/params.h"
18 #include "sst/core/sst_types.h"
19 #include "sst/core/sstpart.h"
20 
21 #include <cstdint>
22 #include <iostream>
23 #include <mutex>
24 #include <set>
25 #include <sstream>
26 #include <stdio.h>
27 #include <string>
28 #include <tuple>
29 #include <utility>
30 #include <vector>
31 
32 /* Forward declare for Friendship */
33 extern int main(int argc, char** argv);
34 
35 namespace SST {
36 namespace Statistics {
37 class StatisticOutput;
38 class StatisticBase;
39 } // namespace Statistics
40 
41 class Config;
42 class Module;
43 class Component;
44 class BaseComponent;
45 class SubComponent;
46 class ElemLoader;
47 class SSTElementPythonModule;
48 class SSTModelDescription;
49 
50 /**
51  * Class for instantiating Components, Links and the like out
52  * of element libraries.
53  */
54 class Factory
55 {
56 public:
57  static Factory* getFactory() { return instance; }
58 
59  static Factory* createFactory(const std::string& searchPaths);
60 
61  /**
62  Update the search paths
63  @param searchPaths New search paths to use
64  */
65  void updateSearchPaths(const std::string& paths);
66 
67 
68  /** Get a list of allowed ports for a given component type.
69  * @param type - Name of component in lib.name format
70  * @return True if this is a valid portname
71  */
72  bool isPortNameValid(const std::string& type, const std::string& port_name);
73 
74  /** Get a list of allowed param keys for a given component type.
75  * @param type - Name of component in lib.name format
76  * @return Allowed parameter names
77  */
78  const std::vector<std::string>& getParamNames(const std::string& type);
79 
80  /** Attempt to create a new Component instantiation
81  * @param id - The unique ID of the component instantiation
82  * @param componentname - The fully qualified elementlibname.componentname type of component
83  * @param params - The params to pass to the component's constructor
84  * @return Newly created component
85  */
86  Component* CreateComponent(ComponentId_t id, const std::string& componentname, Params& params);
87 
88  /** Ensure that an element library containing the required event is loaded
89  * @param eventname - The fully qualified elementlibname.eventname type
90  */
91  void RequireEvent(const std::string& eventname);
92 
93  bool doesSubComponentExist(const std::string& type);
94 
95  /** Return partitioner function
96  * @param name - Fully qualified elementlibname.partitioner type name
97  */
99  const std::string& name, RankInfo total_ranks, RankInfo my_rank, int verbosity);
100 
101  /**
102  Check to see if a given element type is loadable with a particular API
103  @param name - Name of element to check in lib.name format
104  @return True if loadable as the API specified as the template parameter
105  */
106  template <class Base>
107  bool isSubComponentLoadableUsingAPI(const std::string& type)
108  {
109  std::string elemlib, elem;
110  std::tie(elemlib, elem) = parseLoadName(type);
111 
112  requireLibrary(elemlib);
113  std::lock_guard<std::recursive_mutex> lock(factoryMutex);
114 
115  auto* lib = ELI::InfoDatabase::getLibrary<Base>(elemlib);
116  if ( lib ) {
117  auto map = lib->getMap();
118  auto* info = lib->getInfo(elem);
119  if ( info ) {
120  auto* builderLib = Base::getBuilderLibrary(elemlib);
121  if ( builderLib ) {
122  auto* fact = builderLib->getBuilder(elem);
123  if ( fact ) {
124  return true;
125  }
126  }
127  }
128  }
129  return false;
130  }
131 
132  template <class Base, int index, class InfoType>
133  const InfoType& getSimpleInfo(const std::string& type)
134  {
135  static InfoType invalid_ret;
136  std::string elemlib, elem;
137  std::tie(elemlib, elem) = parseLoadName(type);
138 
139  std::stringstream err_os;
140  requireLibrary(elemlib, err_os);
141  std::lock_guard<std::recursive_mutex> lock(factoryMutex);
142 
143  auto* lib = ELI::InfoDatabase::getLibrary<Base>(elemlib);
144  if ( lib ) {
145  auto* info = lib->getInfo(elem);
146  if ( info ) {
147  // Need to cast this to a ProvidesSimpleInfo to get
148  // the templated data
149  auto* cast_info = dynamic_cast<ELI::ProvidesSimpleInfo<index, InfoType>*>(info);
150  if ( cast_info ) {
151  return cast_info->getSimpleInfo();
152  }
153  }
154  }
155  // notFound(Base::ELI_baseName(), type, err_os.str());
156  return invalid_ret;
157  }
158 
159  /**
160  * General function to create a given base class.
161  *
162  * @param type
163  * @param params
164  * @param args Constructor arguments
165  */
166  template <class Base, class... CtorArgs>
167  Base* Create(const std::string& type, CtorArgs&&... args)
168  {
169  std::string elemlib, elem;
170  std::tie(elemlib, elem) = parseLoadName(type);
171 
172  std::stringstream err_os;
173  requireLibrary(elemlib, err_os);
174  std::lock_guard<std::recursive_mutex> lock(factoryMutex);
175 
176  auto* lib = ELI::InfoDatabase::getLibrary<Base>(elemlib);
177  if ( lib ) {
178  auto* info = lib->getInfo(elem);
179  if ( info ) {
180  auto* builderLib = Base::getBuilderLibrary(elemlib);
181  if ( builderLib ) {
182  auto* fact = builderLib->getBuilder(elem);
183  if ( fact ) {
184  Base* ret = fact->create(std::forward<CtorArgs>(args)...);
185  return ret;
186  }
187  }
188  }
189  }
190  notFound(Base::ELI_baseName(), type, err_os.str());
191  return nullptr;
192  }
193 
194  template <class T, class... ARGS>
195  T* CreateProfileTool(const std::string& type, ARGS... args)
196  {
197  return Factory::getFactory()->Create<T>(type, args...);
198  }
199 
200  /**
201  * General function to create a given base class. This version
202  * should be used if a Params object is being passed in and you
203  * need the system to populate the allowed keys for the object.
204  * If you don't need the allowed keys to be populated, just use
205  * the Create() bunction.
206  *
207  * @param type
208  * @param params
209  * @param args Constructor arguments
210  */
211  template <class Base, class... CtorArgs>
212  Base* CreateWithParams(const std::string& type, SST::Params& params, CtorArgs&&... args)
213  {
214  std::string elemlib, elem;
215  std::tie(elemlib, elem) = parseLoadName(type);
216 
217  std::stringstream err_os;
218  requireLibrary(elemlib, err_os);
219  std::lock_guard<std::recursive_mutex> lock(factoryMutex);
220 
221  auto* lib = ELI::InfoDatabase::getLibrary<Base>(elemlib);
222  if ( lib ) {
223  auto map = lib->getMap();
224  auto* info = lib->getInfo(elem);
225  if ( info ) {
226  auto* builderLib = Base::getBuilderLibrary(elemlib);
227  if ( builderLib ) {
228  auto* fact = builderLib->getBuilder(elem);
229  if ( fact ) {
230  params.pushAllowedKeys(info->getParamNames());
231  Base* ret = fact->create(std::forward<CtorArgs>(args)...);
232  params.popAllowedKeys();
233  return ret;
234  }
235  }
236  }
237  }
238  notFound(Base::ELI_baseName(), type, err_os.str());
239  return nullptr;
240  }
241 
242  /** Instantiate a new Statistic
243  * @param comp - Owning component
244  * @param type - Fully qualified elementlibname.statisticname type
245  * @param statName - Name of the statistic
246  * @param statSubId - Name of the sub statistic
247  * @param params - Parameters to pass to the Statistics's constructor
248  * @param fieldType - Type of data stored in statistic
249  */
250  template <class T, class... Args>
251  Statistics::Statistic<T>* CreateStatistic(const std::string& type, BaseComponent* comp, const std::string& statName,
252  const std::string& stat, Params& params, Args... args)
253  {
254  std::string elemlib, elem;
255  std::tie(elemlib, elem) = parseLoadName(type);
256  // ensure library is already loaded...
257  std::stringstream sstr;
258  requireLibrary(elemlib, sstr);
259 
260  auto* lib = ELI::BuilderDatabase::getLibrary<Statistics::Statistic<T>, Args...>(elemlib);
261  if ( lib ) {
262  auto* fact = lib->getFactory(elem);
263  if ( fact ) {
264  return fact->create(comp, statName, stat, params, std::forward<Args>(args)...);
265  }
266  }
267  // If we make it to here, statistic not found
268  out.fatal(CALL_INFO, -1, "can't find requested statistic %s.\n%s\n", type.c_str(), sstr.str().c_str());
269  return nullptr;
270  }
271 
272  /** Return Python Module creation function
273  * @param name - Fully qualified elementlibname.pythonModName type name
274  */
275  SSTElementPythonModule* getPythonModule(const std::string& name);
276 
277  /**
278  * @brief hasLibrary Checks to see if library exists and can be loaded
279  * @param elemlib
280  * @param err_os Stream to print error messages to
281  * @return whether the library was found
282  */
283  bool hasLibrary(const std::string& elemlib, std::ostream& err_os);
284  void requireLibrary(const std::string& elemlib, std::ostream& err_os);
285  /**
286  * @brief requireLibrary Throws away error messages
287  * @param elemlib
288  */
289  void requireLibrary(const std::string& elemlib);
290 
291  void getLoadedLibraryNames(std::set<std::string>& lib_names);
292  void loadUnloadedLibraries(const std::set<std::string>& lib_names);
293 
294  const std::string& getSearchPaths();
295 
296  /** Determine if a SubComponentSlot is defined in a components ElementInfoSubComponentSlot
297  * @param type - The name of the component/subcomponent
298  * @param slotName - The name of the SubComponentSlot
299  * @return True if the SubComponentSlot is defined in the component's ELI
300  */
301  bool DoesSubComponentSlotExist(const std::string& type, const std::string& slotName);
302 
303  /** Determine if a statistic is defined in a components ElementInfoStatistic
304  * @param type - The name of the component
305  * @param statistic_name - The name of the statistic
306  * @return True if the statistic is defined in the component's ElementInfoStatistic
307  */
308  bool DoesComponentInfoStatisticNameExist(const std::string& type, const std::string& statistic_name);
309 
310  /** Get the units of a statistic defined in the component's ElementInfoStatistic
311  * @param type - The name of the component
312  * @param statistic_name - The name of the statistic
313  * @return The units string of the statistic from the ElementInfoStatistic
314  */
315  std::string GetComponentInfoStatisticUnits(const std::string& type, const std::string& statistic_name);
316 
317  uint8_t GetStatisticValidityAndEnableLevel(const std::string& type, const std::string& statistic_name);
318 
319  /** Get a list of allowed ports for a given component type.
320  * @param type - Type of component in lib.name format
321  * @param point = Profile point to check
322  * @return True if this is a valid profile point
323  */
324  bool isProfilePointValid(const std::string& type, const std::string& point);
325 
326  static SSTModelDescription* createModelDescription(
327  const std::string& type, const std::string& input_file, int verbose, Config& cfg, double start_time);
328 
329  explicit Factory(const std::string& searchPaths);
330 
331 private:
332  friend int ::main(int argc, char** argv);
333 
334  [[noreturn]]
335  void notFound(const std::string& baseName, const std::string& type, const std::string& errorMsg);
336 
337  ~Factory();
338 
339  Factory(const Factory&) = delete; // Don't Implement
340  Factory& operator=(const Factory&) = delete; // Don't Implement
341 
342  static Factory* instance;
343 
344  // find library information for name
345  bool findLibrary(const std::string& name, std::ostream& err_os = std::cerr);
346  // handle low-level loading of name
347  bool loadLibrary(const std::string& name, std::ostream& err_os = std::cerr);
348 
349  std::set<std::string> loaded_libraries;
350 
351  std::string searchPaths;
352 
353  ElemLoader* loader;
354  std::string loadingComponentType;
355 
356  static std::pair<std::string, std::string> parseLoadName(const std::string& wholename);
357 
358  std::recursive_mutex factoryMutex;
359 
360 protected:
361  static Output out;
362 };
363 
364 } // namespace SST
365 
366 #endif // SST_CORE_FACTORY_H
Output object provides consistent method for outputting data to stdout, stderr and/or sst debug file...
Definition: output.h:57
void fatal(uint32_t line, const char *file, const char *func, int exit_code, const char *format,...) const
Output the fatal message with formatting as specified by the format parameter.
Definition: output.cc:156
bool DoesComponentInfoStatisticNameExist(const std::string &type, const std::string &statistic_name)
Determine if a statistic is defined in a components ElementInfoStatistic.
Definition: factory.cc:360
Class to contain SST Simulation Configuration variables.
Definition: config.h:51
bool isSubComponentLoadableUsingAPI(const std::string &type)
Check to see if a given element type is loadable with a particular API.
Definition: factory.h:107
Main component object for the simulation.
Definition: component.h:30
SSTElementPythonModule * getPythonModule(const std::string &name)
Return Python Module creation function.
Definition: factory.cc:572
Definition: action.cc:18
Statistics::Statistic< T > * CreateStatistic(const std::string &type, BaseComponent *comp, const std::string &statName, const std::string &stat, Params &params, Args... args)
Instantiate a new Statistic.
Definition: factory.h:251
Forms the template defined base class for statistics gathering within SST.
Definition: elementinfo.h:46
Definition: simpleInfo.h:87
bool hasLibrary(const std::string &elemlib, std::ostream &err_os)
hasLibrary Checks to see if library exists and can be loaded
Definition: factory.cc:598
Class to load Element Libraries.
Definition: elemLoader.h:23
Component * CreateComponent(ComponentId_t id, const std::string &componentname, Params &params)
Attempt to create a new Component instantiation.
Definition: factory.cc:215
Partition::SSTPartitioner * CreatePartitioner(const std::string &name, RankInfo total_ranks, RankInfo my_rank, int verbosity)
Return partitioner function.
Definition: factory.cc:538
Base * CreateWithParams(const std::string &type, SST::Params &params, CtorArgs &&... args)
General function to create a given base class.
Definition: factory.h:212
void pushAllowedKeys(const std::vector< std::string > &keys)
Definition: params.cc:242
void RequireEvent(const std::string &eventname)
Ensure that an element library containing the required event is loaded.
Definition: factory.cc:527
bool isProfilePointValid(const std::string &type, const std::string &point)
Get a list of allowed ports for a given component type.
Definition: factory.cc:458
Definition: rankInfo.h:23
Main component object for the simulation.
Definition: baseComponent.h:64
Base class for Partitioning graphs.
Definition: sstpart.h:31
Parameter store.
Definition: params.h:63
void popAllowedKeys()
Removes the most recent set of keys considered allowed.
Definition: params.cc:252
Base class for Model Generation.
Definition: sstmodel.h:29
Class for instantiating Components, Links and the like out of element libraries.
Definition: factory.h:54
Base class for python modules in element libraries.
Definition: element_python.h:132
std::string GetComponentInfoStatisticUnits(const std::string &type, const std::string &statistic_name)
Get the units of a statistic defined in the component&#39;s ElementInfoStatistic.
Definition: factory.cc:408
void updateSearchPaths(const std::string &paths)
Update the search paths.
Definition: factory.cc:76
Base * Create(const std::string &type, CtorArgs &&... args)
General function to create a given base class.
Definition: factory.h:167
const std::vector< std::string > & getParamNames(const std::string &type)
Get a list of allowed param keys for a given component type.
Definition: factory.cc:174
bool isPortNameValid(const std::string &type, const std::string &port_name)
Get a list of allowed ports for a given component type.
Definition: factory.cc:117
bool DoesSubComponentSlotExist(const std::string &type, const std::string &slotName)
Determine if a SubComponentSlot is defined in a components ElementInfoSubComponentSlot.
Definition: factory.cc:253