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