SST  15.1.0
StructuralSimulationToolkit
portModule.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_PORTMODULE_H
13 #define SST_CORE_PORTMODULE_H
14 
15 #include "sst/core/eli/elementinfo.h"
16 #include "sst/core/event.h"
17 #include "sst/core/link.h"
18 #include "sst/core/statapi/statbase.h"
19 #include "sst/core/statapi/statengine.h"
20 
21 #include <cstdarg>
22 #include <cstdint>
23 #include <string>
24 #include <utility>
25 
26 using namespace SST::Statistics;
27 
28 namespace SST {
29 
30 class BaseComponent;
31 
32 /**
33  PortModules are modules that can be attached to the send and/or
34  receive side of ports. Each PortModule is attached to one port and
35  uses the Event::HandlerBase::InterceptPoint for intercepting
36  incoming events and the Link::AttachPoint to intercept outgoing
37  events. The intercepted events can be inspected, modified and/or
38  canceled. For canceled events, the PortModule is required to delete
39  the event.
40 
41  NOTE: Not Final API - PortModules will continue to be supported in
42  the future, but the API will not be finalized until the SST 15
43  release, so there may be slight changes to the base class.
44 
45  NOTE: Attaching to a port on the send-side has known performance
46  issues, so it is recommended to attach to the input port whenever
47  possible.
48 
49  */
50 class PortModule :
51  public Event::HandlerBase::InterceptPoint,
52  public Link::AttachPoint,
54 {
55 
56 public:
57  SST_ELI_DECLARE_BASE(PortModule)
58  // declare extern to limit compile times
59  SST_ELI_DECLARE_CTOR_EXTERN(SST::Params&)
60  // These categories will print in sst-info in the order they are
61  // listed here
62  SST_ELI_DECLARE_INFO_EXTERN(
66 
67  PortModule();
68  virtual ~PortModule() {};
69 
70  /******* Functions inherited from Link::AttachPoint *******/
71  /**
72  Function that will be called when a PortModule is registered on
73  sends (i.e. installOnSend() returns true). The uintptr_t
74  returned from this function will be passed into the eventSent()
75  function.
76 
77  The default implemenation will just return 0 and only needs to
78  be overwritten if the module needs any of the metadata and/or
79  needs to return a unique key.
80 
81  @param mdata Metadata to be passed into the tool. NOTE: The
82  metadata will be of type EventHandlerMetaData (see
83  sst/core/event.h)
84 
85  @return Opaque key that will be passed back into eventSent() to
86  identify the source of the call
87  */
88  virtual uintptr_t registerLinkAttachTool(const AttachPointMetaData& mdata) override;
89 
90  /**
91  Function that will be called when an event is sent on a
92  link with registered PortModules. If ev is set to
93  nullptr, then the event will not be delivered and the function
94  should delete the original event.
95 
96  NOTE: It is possible to delete the incoming event and replace
97  it with a new event, if this is done, the new event MUST call
98  copyAllDeliveryInfo(ev) or the event will not be properly
99  processed.
100 
101  @param key Opaque key returned from registerLinkAttachTool()
102 
103  @param ev Event to intercept
104  */
105  virtual void eventSent(uintptr_t key, Event*& ev) override = 0;
106 
107 
108  /**
109  Function that will be called to handle the key returned from
110  registerLinkAttachTool, if the AttachPoint tool is
111  serializable. This is needed because the key is opaque to the
112  Link, so it doesn't know how to handle it during serialization.
113  During SIZE and PACK phases of serialization, the tool needs to
114  store out any information that will be needed to recreate data
115  that is reliant on the key. On UNPACK, the function needs to
116  recreate the any state and reinitialize the passed in key
117  reference to the proper state to continue to make valid calls
118  to eventSent().
119 
120  The default implemenation will just set key to 0 on UNPACK and
121  only needs to be overwritten if the module needs to return a
122  unique key from registerLinkAttachTool().
123 
124  @param ser Serializer to use for serialization
125 
126  @param key Key that would be passed into the eventSent() function.
127  */
128  virtual void serializeEventAttachPointKey(SST::Core::Serialization::serializer& ser, uintptr_t& key) override;
129 
130 
131  /******* Functions inherited from Event::HandlerBase::InterceptPoint *******/
132  /**
133  Function that will be called when a handler is registered with
134  recieves (i.e. installOnReceive() returns true). The uintptr_t
135  returned from this function will be passed into the intercept()
136  function.
137 
138  The default implemenation will just return 0 and only needs to
139  be overwritten if the module needs any of the metadata and/or
140  needs to return a unique key.
141 
142  @param mdata Metadata to be passed into the tool. NOTE: The
143  metadata will be of type EventHandlerMetaData (see
144  sst/core/event.h)
145 
146  @return Opaque key that will be passed back into the
147  interceptHandler() calls
148  */
149  virtual uintptr_t registerHandlerIntercept(const AttachPointMetaData& mdata) override;
150 
151 
152  /**
153  Function that will be called before the event handler to let
154  the attach point intercept the data. The data can be modified,
155  and if cancel is set to true, the handler will not be executed.
156  If cancel is set to true, then the function should also delete
157  the event and set data to nullptr.
158 
159  NOTE: It is possible to delete the incoming event and replace
160  the it with a new event, if this is done, the new event MUST
161  call copyAllDeliveryInfo(ev) or the event will not be properly
162  processed.
163 
164  @param key Key returned from registerHandlerIntercept()
165  function
166 
167  @param data Event that is to be passed to the handler
168 
169  @param[out] cancel Set to true if the handler delivery should
170  be cancelled. If set to true, function must also delete the
171  event
172  */
173  virtual void interceptHandler(uintptr_t key, Event*& data, bool& cancel) override = 0;
174 
175  /**
176  Function that will be called to handle the key returned from
177  registerHandlerIntercept, if the AttachPoint tool is
178  serializable. This is needed because the key is opaque to the
179  Link, so it doesn't know how to handle it during serialization.
180  During SIZE and PACK phases of serialization, the tool needs to
181  store out any information that will be needed to recreate data
182  that is reliant on the key. On UNPACK, the function needs to
183  recreate any state and reinitialize the passed in key reference
184  to the proper state to continue to make valid calls to
185  interceptHandler().
186 
187  The default implemenation will just set key to 0 on UNPACK and
188  only needs to be overwritten if the module needs to return a
189  unique key from registerHandlerIntercept().
190 
191  @param ser Serializer to use for serialization
192 
193  @param key Key that would be passed into the interceptHandler() function.
194  */
195  virtual void serializeHandlerInterceptPointKey(SST::Core::Serialization::serializer& ser, uintptr_t& key) override;
196 
197  /*** Functions that control whether module is install on send and/or receive ***/
198  /**
199  Called to determine if the PortModule should be installed on
200  receives
201 
202  @return true if PortModule should be installed on receives
203  */
204  virtual bool installOnReceive() { return false; }
205 
206  /**
207  Called to determine if the PortModule should be installed on
208  sends. NOTE: Installing PortModules on sends will have a
209  noticeable impact on performance, consider architecting things
210  so that you can intercept on receives.
211 
212  @return true if PortModule should be installed on sends
213  */
214  virtual bool installOnSend() { return false; }
215 
216  const std::string& getName() const;
217 
218 protected:
219  void serialize_order(SST::Core::Serialization::serializer& ser) override;
220 
221  /*** Core API functions available to PortModules ***/
222 
223  /** Get the core timebase */
224  UnitAlgebra getCoreTimeBase() const;
225 
226  /** Return the current simulation time as a cycle count*/
227  SimTime_t getCurrentSimCycle() const;
228 
229  /** Return the current priority */
230  int getCurrentPriority() const;
231 
232  /** Return the elapsed simulation time as a time */
233  UnitAlgebra getElapsedSimTime() const;
234 
235  /** Return the base simulation Output class instance */
236  Output& getSimulationOutput() const;
237 
238  /**
239  Return the simulated time since the simulation began in units
240  specified by the parameter.
241 
242  @param tc TimeConverter specifying the units
243  */
244  [[deprecated("Use of shared TimeConverter objects is deprecated. Use 'getCurrentSimTime(TimeConverter& timebase)' "
245  "(i.e., no pointer) instead.")]]
246  SimTime_t getCurrentSimTime(TimeConverter* tc) const;
247  SimTime_t getCurrentSimTime(TimeConverter& tc) const;
248 
249  /**
250  Return the simulated time since the simulation began in
251  timebase specified
252 
253  @param base Timebase frequency in SI Units
254  */
255  SimTime_t getCurrentSimTime(const std::string& base) const;
256 
257  /**
258  Utility function to return the time since the simulation began
259  in nanoseconds
260  */
261  SimTime_t getCurrentSimTimeNano() const;
262 
263  /**
264  Utility function to return the time since the simulation began
265  in microseconds
266  */
267  SimTime_t getCurrentSimTimeMicro() const;
268 
269  /**
270  Utility function to return the time since the simulation began
271  in milliseconds
272  */
273  SimTime_t getCurrentSimTimeMilli() const;
274 
275  /** Convenience function for reporting fatal conditions. The
276  function will create a new Output object and call fatal()
277  using the supplied parameters. Before calling
278  Output::fatal(), the function will also print other
279  information about the (sub)component that called fatal and
280  about the simulation state.
281 
282  From Output::fatal: Message will be sent to the output
283  location and to stderr. The output will be prepended with the
284  expanded prefix set in the object.
285  NOTE: fatal() will call MPI_Abort(exit_code) to terminate simulation.
286 
287  @param line Line number of calling function (use CALL_INFO macro)
288  @param file File name calling function (use CALL_INFO macro)
289  @param func Function name calling function (use CALL_INFO macro)
290  @param exit_code The exit code used for termination of simulation.
291  will be passed to MPI_Abort()
292  @param format Format string. All valid formats for printf are available.
293  @param ... Arguments for format.
294  */
295  [[noreturn]]
296  void fatal(uint32_t line, const char* file, const char* func, int exit_code, const char* format, ...) const
297  __attribute__((format(printf, 6, 7)));
298 
299  /** Convenience function for testing for and reporting fatal
300  conditions. If the condition holds, fatal() will be called,
301  otherwise, the function will return. The function will create
302  a new Output object and call fatal() using the supplied
303  parameters. Before calling Output::fatal(), the function will
304  also print other information about the (sub)component that
305  called fatal and about the simulation state.
306 
307  From Output::fatal: Message will be sent to the output
308  location and to stderr. The output will be prepended with the
309  expanded prefix set in the object.
310  NOTE: fatal() will call MPI_Abort(exit_code) to terminate simulation.
311 
312  @param condition on which to call fatal(); fatal() is called
313  if the bool is false.
314  @param line Line number of calling function (use CALL_INFO macro)
315  @param file File name calling function (use CALL_INFO macro)
316  @param func Function name calling function (use CALL_INFO macro)
317  @param exit_code The exit code used for termination of simulation.
318  will be passed to MPI_Abort()
319  @param format Format string. All valid formats for printf are available.
320  @param ... Arguments for format.
321  */
322  void sst_assert(bool condition, uint32_t line, const char* file, const char* func, int exit_code,
323  const char* format, ...) const __attribute__((format(printf, 7, 8)));
324 
325  /** Registers a statistic.
326  If Statistic is allowed to exist (controlled by Python runtime parameters),
327  then a statistic will be created and returned. If not allowed to exist,
328  then a NullStatistic will be returned. The type of Statistic is set by Python
329  runtime parameters.
330  @param params Additional parameter set to be passed to the statistic constructor.
331  @param stat_name Primary name of the statistic. This name must match the
332  defined ElementInfoStatistic in the component, and must also
333  be enabled in the Python input file.
334  @param stat_sub_id An additional sub name for the statistic
335  @return Either a created statistic or a NullStatistic depending upon runtime settings.
336  */
337  template <typename T>
338  Statistics::Statistic<T>* registerStatistic(
339  SST::Params& params, const std::string& stat_name, const std::string& stat_sub_id = "")
340  {
341  return registerStatistic_impl<T>(params, stat_name, stat_sub_id);
342  }
343 
344  template <typename T>
345  Statistics::Statistic<T>* registerStatistic(const std::string& stat_name, const std::string& stat_sub_id = "")
346  {
347  SST::Params empty {};
348  return registerStatistic_impl<T>(empty, stat_name, stat_sub_id);
349  }
350 
351  virtual std::string getEliType() const { return ""; }
352 
353 private:
354  friend class BaseComponent;
355 
356  /**
357  Component that owns this PortModule
358  */
359  BaseComponent* component_ = nullptr;
360 
361  PortModuleId_t id_; // Together with component_, uniquely identifies a port module
362 
363  std::string name_;
364 
365  // Utility function used by fatal and sst_assert
366  [[noreturn]]
367  void vfatal(uint32_t line, const char* file, const char* func, int exit_code, const char* format, va_list arg) const
368  __attribute__((format(printf, 6, 0)));
369 
370  /**
371  Internal function to manage statistic registration
372  */
373  template <typename T>
374  Statistics::Statistic<T>* registerStatistic_impl(
375  SST::Params& params, const std::string& stat_name, const std::string& stat_sub_id)
376  {
377  // Lookup statistic enable level in ELI; if not present, returns 255
378  uint8_t level = getStatisticValidityAndLevel(stat_name);
379  if ( level == 255 ) {
380  fatal(__LINE__, __FILE__, "registerStatistic", 1,
381  "attempting to register a statistic '%s' that is not found in ELI", stat_name.c_str());
382  }
383 
384  Params cfg_params;
385  bool enabled;
386  std::tie(enabled, cfg_params) = isStatisticEnabled(stat_name, level);
387 
388  if ( enabled ) {
389  cfg_params.insert(params);
390  auto stat = getStatEngine()->createStatistic<T>(component_, stat_name, stat_sub_id, cfg_params);
391  stat->setPortModName(id_.first, id_.second);
392  return stat;
393  }
394  else {
395  return getStatEngine()->createDisabledStatistic<T>();
396  }
397  }
398 
399  /** Helper functions for statistic enablement */
400  /**
401  Returns the local stat engine instance
402  */
403  Statistics::StatisticProcessingEngine* getStatEngine() const;
404 
405  /**
406  Returns the required statistic level if stat exists in ELI, else returns 255
407  */
408  uint8_t getStatisticValidityAndLevel(const std::string& statistic_name) const;
409 
410  /**
411  Returns a pair containing a bool indicating whether the statistic was enabled and a params object with any params
412  the statistic has been given.
413  */
414  std::pair<bool, Params> isStatisticEnabled(const std::string& statistic_name, const uint8_t min_level);
415 };
416 
417 } // namespace SST
418 
419 // Macro used to register PortModules in the ELI database
420 #define SST_ELI_REGISTER_PORTMODULE(cls, lib, name, version, desc) \
421  SST_ELI_REGISTER_DERIVED(SST::PortModule,cls,lib,name,ELI_FORWARD_AS_ONE(version),desc) \
422  std::string getEliType() const override \
423  { \
424  std::string ret(lib); \
425  return ret + "." + name; \
426  }
427 
428 #endif // SST_CORE_PORTMODULE_H
Output object provides consistent method for outputting data to stdout, stderr and/or sst debug file...
Definition: output.h:57
virtual bool installOnSend()
Called to determine if the PortModule should be installed on sends.
Definition: portModule.h:214
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:42
A class to convert between a component&#39;s view of time and the core&#39;s view of time.
Definition: timeConverter.h:27
Definition: statsInfo.h:39
Definition: action.cc:18
Forms the template defined base class for statistics gathering within SST.
Definition: elementinfo.h:46
Definition: serializable.h:23
Definition: paramsInfo.h:39
virtual bool installOnReceive()
Called to determine if the PortModule should be installed on receives.
Definition: portModule.h:204
Parameter store.
Definition: params.h:63
Definition: attributeInfo.h:40
Struct used as a base class for all AttachPoint metadata passed to registration functions.
Definition: sst_types.h:80
Definition: elementinfo.h:44
Base class for Events - Items sent across links to communicate between components.
Definition: event.h:40
Performs Unit math in full precision.
Definition: unitAlgebra.h:105
PortModules are modules that can be attached to the send and/or receive side of ports.
Definition: portModule.h:50