SST  11.1.0
StructuralSimulationToolkit
activity.h
1 // Copyright 2009-2021 NTESS. Under the terms
2 // of Contract DE-NA0003525 with NTESS, the U.S.
3 // Government retains certain rights in this software.
4 //
5 // Copyright (c) 2009-2021, NTESS
6 // All rights reserved.
7 //
8 // This file is part of the SST software package. For license
9 // information, see the LICENSE file in the top level directory of the
10 // distribution.
11 
12 #ifndef SST_CORE_ACTIVITY_H
13 #define SST_CORE_ACTIVITY_H
14 
15 #include "sst/core/mempool.h"
16 #include "sst/core/output.h"
17 #include "sst/core/serialization/serializable.h"
18 #include "sst/core/sst_types.h"
19 #include "sst/core/warnmacros.h"
20 
21 #include <cinttypes>
22 #include <cstring>
23 #include <errno.h>
24 #include <sstream>
25 #include <unordered_map>
26 
27 // Default Priority Settings
28 #define STOPACTIONPRIORITY 01
29 #define THREADSYNCPRIORITY 20
30 #define SYNCPRIORITY 25
31 #define INTROSPECTPRIORITY 30
32 #define CLOCKPRIORITY 40
33 #define EVENTPRIORITY 50
34 #define MEMEVENTPRIORITY 50
35 #define BARRIERPRIORITY 75
36 #define ONESHOTPRIORITY 80
37 #define STATISTICCLOCKPRIORITY 85
38 #define FINALEVENTPRIORITY 98
39 #define EXITPRIORITY 99
40 
41 #define SST_ENFORCE_EVENT_ORDERING
42 
43 extern int main(int argc, char** argv);
44 
45 namespace SST {
46 
47 /** Base class for all Activities in the SST Event Queue */
49 {
50 public:
51  Activity() {}
52  virtual ~Activity() {}
53 
54  /** Function which will be called when the time for this Activity comes to pass. */
55  virtual void execute(void) = 0;
56 
57 #ifdef SST_ENFORCE_EVENT_ORDERING
58 
59  /** To use with STL container classes. */
60 
61  /** For use when you have already binned by time */
63  {
64  public:
65  /** Compare based off pointers */
66  inline bool operator()(const Activity* lhs, const Activity* rhs) const
67  {
68  if ( lhs->priority == rhs->priority ) { return lhs->enforce_link_order < rhs->enforce_link_order; }
69  else {
70  return lhs->priority < rhs->priority;
71  }
72  }
73 
74  /** Compare based off references */
75  inline bool operator()(const Activity& lhs, const Activity& rhs) const
76  {
77  if ( lhs.priority == rhs.priority ) { return lhs.enforce_link_order < rhs.enforce_link_order; }
78  else {
79  return lhs.priority < rhs.priority;
80  }
81  }
82  };
83 
84  /** To use with STL priority queues, that order in reverse. */
85 
86  /** For use when you have already binned by time */
88  {
89  public:
90  /** Compare based off pointers */
91  inline bool operator()(const Activity* lhs, const Activity* rhs) const
92  {
93  if ( lhs->priority == rhs->priority ) {
94  if ( lhs->enforce_link_order == rhs->enforce_link_order ) {
95  return lhs->queue_order > rhs->queue_order;
96  }
97  else {
98  return lhs->enforce_link_order > rhs->enforce_link_order;
99  }
100  }
101  else {
102  return lhs->priority > rhs->priority;
103  }
104  }
105 
106  /** Compare based off references */
107  inline bool operator()(const Activity& lhs, const Activity& rhs) const
108  {
109  if ( lhs.priority == rhs.priority ) {
110  if ( lhs.enforce_link_order == rhs.enforce_link_order ) { return lhs.queue_order > rhs.queue_order; }
111  else {
112  return lhs.enforce_link_order > rhs.enforce_link_order;
113  }
114  }
115  else {
116  return lhs.priority > rhs.priority;
117  }
118  }
119  };
120 
121  /** To use with STL container classes. */
123  {
124  public:
125  /** Compare based off pointers */
126  inline bool operator()(const Activity* lhs, const Activity* rhs) const
127  {
128  if ( lhs->delivery_time == rhs->delivery_time ) {
129  if ( lhs->priority == rhs->priority ) {
130  /* TODO: Handle 64-bit wrap-around */
131  return lhs->enforce_link_order < rhs->enforce_link_order;
132  }
133  else {
134  return lhs->priority < rhs->priority;
135  }
136  }
137  else {
138  return lhs->delivery_time < rhs->delivery_time;
139  }
140  }
141 
142  /** Compare based off references */
143  inline bool operator()(const Activity& lhs, const Activity& rhs) const
144  {
145  if ( lhs.delivery_time == rhs.delivery_time ) {
146  if ( lhs.priority == rhs.priority ) {
147  /* TODO: Handle 64-bit wrap-around */
148  return lhs.enforce_link_order < rhs.enforce_link_order;
149  }
150  else {
151  return lhs.priority < rhs.priority;
152  }
153  }
154  else {
155  return lhs.delivery_time < rhs.delivery_time;
156  }
157  }
158  };
159 
160  /** To use with STL priority queues, that order in reverse. */
162  {
163  public:
164  /** Compare based off pointers */
165  inline bool operator()(const Activity* lhs, const Activity* rhs) const
166  {
167  if ( lhs->delivery_time == rhs->delivery_time ) {
168  if ( lhs->priority == rhs->priority ) {
169  if ( lhs->enforce_link_order == rhs->enforce_link_order ) {
170  /* TODO: Handle 64-bit wrap-around */
171  return lhs->queue_order > rhs->queue_order;
172  }
173  else {
174  return lhs->enforce_link_order > rhs->enforce_link_order;
175  }
176  }
177  else {
178  return lhs->priority > rhs->priority;
179  }
180  }
181  else {
182  return lhs->delivery_time > rhs->delivery_time;
183  }
184  }
185 
186  /** Compare based off references */
187  inline bool operator()(const Activity& lhs, const Activity& rhs) const
188  {
189  if ( lhs.delivery_time == rhs.delivery_time ) {
190  if ( lhs.priority == rhs.priority ) {
191  if ( lhs.enforce_link_order == rhs.enforce_link_order ) {
192  return lhs.queue_order > rhs.queue_order;
193  }
194  else {
195  return lhs.enforce_link_order > rhs.enforce_link_order;
196  }
197  }
198  else {
199  return lhs.priority > rhs.priority;
200  }
201  }
202  else {
203  return lhs.delivery_time > rhs.delivery_time;
204  }
205  }
206  };
207 
208 #endif
209 
210  /** Comparator class to use with STL container classes. */
211 
212  /** For use when you have already binned by time */
214  {
215  public:
216  /** Compare based off pointers */
217  inline bool operator()(const Activity* lhs, const Activity* rhs) { return lhs->priority < rhs->priority; }
218 
219  /** Compare based off references */
220  inline bool operator()(const Activity& lhs, const Activity& rhs) { return lhs.priority < rhs.priority; }
221  };
222 
223  /** To use with STL priority queues, that order in reverse. */
225  {
226  public:
227  /** Compare based off pointers */
228  inline bool operator()(const Activity* lhs, const Activity* rhs) const
229  {
230  if ( lhs->priority == rhs->priority ) { return lhs->queue_order > rhs->queue_order; }
231  else {
232  return lhs->priority > rhs->priority;
233  }
234  }
235 
236  /** Compare based off references */
237  inline bool operator()(const Activity& lhs, const Activity& rhs) const
238  {
239  if ( lhs.priority == rhs.priority ) { return lhs.queue_order > rhs.queue_order; }
240  else {
241  return lhs.priority > rhs.priority;
242  }
243  }
244  };
245 
246  /** Comparator class to use with STL container classes. */
248  {
249  public:
250  /** Compare based off pointers */
251  inline bool operator()(const Activity* lhs, const Activity* rhs)
252  {
253  if ( lhs->delivery_time == rhs->delivery_time )
254  return lhs->priority < rhs->priority;
255  else
256  return lhs->delivery_time < rhs->delivery_time;
257  }
258 
259  /** Compare based off references */
260  inline bool operator()(const Activity& lhs, const Activity& rhs)
261  {
262  if ( lhs.delivery_time == rhs.delivery_time )
263  return lhs.priority < rhs.priority;
264  else
265  return lhs.delivery_time < rhs.delivery_time;
266  }
267  };
268 
269  /** To use with STL priority queues, that order in reverse. */
271  {
272  public:
273  /** Compare based off pointers */
274  inline bool operator()(const Activity* lhs, const Activity* rhs) const
275  {
276  if ( lhs->delivery_time == rhs->delivery_time ) {
277  if ( lhs->priority == rhs->priority ) {
278  /* TODO: Handle 64-bit wrap-around */
279  return lhs->queue_order > rhs->queue_order;
280  }
281  else {
282  return lhs->priority > rhs->priority;
283  }
284  }
285  else {
286  return lhs->delivery_time > rhs->delivery_time;
287  }
288  }
289 
290  /** Compare based off references */
291  inline bool operator()(const Activity& lhs, const Activity& rhs) const
292  {
293  if ( lhs.delivery_time == rhs.delivery_time ) {
294  if ( lhs.priority == rhs.priority ) {
295  /* TODO: Handle 64-bit wrap-around */
296  return lhs.queue_order > rhs.queue_order;
297  }
298  else {
299  return lhs.priority > rhs.priority;
300  }
301  }
302  else {
303  return lhs.delivery_time > rhs.delivery_time;
304  }
305  }
306  };
307 
308  /** Comparator class to use with STL container classes. */
309  class less_time
310  {
311  public:
312  /** Compare pointers */
313  inline bool operator()(const Activity* lhs, const Activity* rhs) const
314  {
315  return lhs->delivery_time < rhs->delivery_time;
316  }
317 
318  /** Compare references */
319  inline bool operator()(const Activity& lhs, const Activity& rhs) const
320  {
321  return lhs.delivery_time < rhs.delivery_time;
322  }
323  };
324 
325  /** Set the time for which this Activity should be delivered */
326  inline void setDeliveryTime(SimTime_t time) { delivery_time = time; }
327 
328  /** Return the time at which this Activity will be delivered */
329  inline SimTime_t getDeliveryTime() const { return delivery_time; }
330 
331  /** Return the Priority of this Activity */
332  inline int getPriority() const { return priority; }
333 
334  std::string getDeliveryTimeInfo() const
335  {
336  std::stringstream buf;
337  buf << "time: " << delivery_time << ", priority: " << priority;
338  return buf.str();
339  }
340 
341  /** Get a string represenation of the event. The default version
342  * will just use the name of the class, retrieved through the
343  * cls_name() function inherited from the serialzable class, which
344  * will return the name of the last class to call one of the
345  * serialization macros (ImplementSerializable(),
346  * ImplementVirtualSerializable(), or NotSerializable()).
347  * Subclasses can override this function if they want to add
348  * additional information.
349  */
350  virtual std::string toString() const
351  {
352  std::stringstream buf;
353 
354  buf << cls_name() << " to be delivered at " << getDeliveryTimeInfo();
355  return buf.str();
356  }
357 
358  /** Generic print-print function for this Activity.
359  * Subclasses should override this function.
360  */
361  virtual void print(const std::string& header, Output& out) const
362  {
363  out.output("%s%s\n", header.c_str(), toString().c_str());
364  }
365 
366 #ifdef __SST_DEBUG_EVENT_TRACKING__
367  virtual void printTrackingInfo(const std::string& header, Output& out) const {}
368 #endif
369 
370  /** Set a new Queue order */
371  void setQueueOrder(uint64_t order) { queue_order = order; }
372 
373  uint64_t getQueueOrder() { return queue_order; }
374 
375 #ifdef USE_MEMPOOL
376  /** Allocates memory from a memory pool for a new Activity */
377  void* operator new(std::size_t size) noexcept
378  {
379  /* 1) Find memory pool
380  * 1.5) If not found, create new
381  * 2) Alloc item from pool
382  * 3) Append PoolID to item, increment pointer
383  */
384  Core::MemPool* pool = nullptr;
385  size_t nPools = memPools.size();
386  std::thread::id tid = std::this_thread::get_id();
387  for ( size_t i = 0; i < nPools; i++ ) {
388  PoolInfo_t& p = memPools[i];
389  if ( p.tid == tid && p.size == size ) {
390  pool = p.pool;
391  break;
392  }
393  }
394  if ( nullptr == pool ) {
395  /* Still can't find it, alloc a new one */
396  pool = new Core::MemPool(size + sizeof(PoolData_t));
397 
398  std::lock_guard<std::mutex> lock(poolMutex);
399  memPools.emplace_back(tid, size, pool);
400  }
401 
402  PoolData_t* ptr = (PoolData_t*)pool->malloc();
403  if ( !ptr ) {
404  fprintf(stderr, "Memory Pool failed to allocate a new object. Error: %s\n", strerror(errno));
405  return nullptr;
406  }
407  *ptr = pool;
408  return (void*)(ptr + 1);
409  }
410 
411  /** Returns memory for this Activity to the appropriate memory pool */
412  void operator delete(void* ptr)
413  {
414  /* 1) Decrement pointer
415  * 2) Determine Pool Pointer
416  * 2b) Set Pointer field to nullptr to allow tracking
417  * 3) Return to pool
418  */
419  PoolData_t* ptr8 = ((PoolData_t*)ptr) - 1;
420  Core::MemPool* pool = *ptr8;
421  *ptr8 = nullptr;
422 
423  pool->free(ptr8);
424  }
425  void operator delete(void* ptr, std::size_t UNUSED(sz))
426  {
427  /* 1) Decrement pointer
428  * 2) Determine Pool Pointer
429  * 2b) Set Pointer field to nullptr to allow tracking
430  * 3) Return to pool
431  */
432  PoolData_t* ptr8 = ((PoolData_t*)ptr) - 1;
433  Core::MemPool* pool = *ptr8;
434  *ptr8 = nullptr;
435 
436  pool->free(ptr8);
437  };
438 
439  static void getMemPoolUsage(uint64_t& bytes, uint64_t& active_activities)
440  {
441  bytes = 0;
442  active_activities = 0;
443  for ( auto&& entry : Activity::memPools ) {
444  bytes += entry.pool->getBytesMemUsed();
445  active_activities += entry.pool->getUndeletedEntries();
446  }
447  }
448 
449  static void printUndeletedActivities(const std::string& header, Output& out, SimTime_t before = MAX_SIMTIME_T)
450  {
451  for ( auto&& entry : Activity::memPools ) {
452  const std::list<uint8_t*>& arenas = entry.pool->getArenas();
453  size_t arenaSize = entry.pool->getArenaSize();
454  size_t elemSize = entry.pool->getElementSize();
455  size_t nelem = arenaSize / elemSize;
456  for ( auto iter = arenas.begin(); iter != arenas.end(); ++iter ) {
457  for ( size_t j = 0; j < nelem; j++ ) {
458  PoolData_t* ptr = (PoolData_t*)((*iter) + (elemSize * j));
459  if ( *ptr != nullptr ) {
460  Activity* act = (Activity*)(ptr + 1);
461  if ( act->delivery_time <= before ) {
462  act->print(header, out);
463 #ifdef __SST_DEBUG_EVENT_TRACKING__
464  act->printTrackingInfo(header + " ", out);
465 #endif
466  }
467  }
468  }
469  }
470  }
471  }
472 
473 #endif
474 
475  // /* Serializable interface methods */
476  // void serialize_order(serializer &ser);
477 
478 
479  int32_t getEnforceLinkOrder() { return enforce_link_order; }
480 
481 protected:
482  /** Set the priority of the Activity */
483  void setPriority(int priority) { this->priority = priority; }
484 
485  // Function used by derived classes to serialize data members.
486  // This class is not serializable, because not all class that
487  // inherit from it need to be serializable.
488  void serialize_order(SST::Core::Serialization::serializer& ser) override
489  {
490  ser& queue_order;
491  ser& delivery_time;
492  ser& priority;
493 #ifdef SST_ENFORCE_EVENT_ORDERING
494  ser& enforce_link_order;
495 #endif
496  }
497 
498 #ifdef SST_ENFORCE_EVENT_ORDERING
499  int32_t enforce_link_order;
500 #endif
501 
502 private:
503  uint64_t queue_order;
504  SimTime_t delivery_time;
505  int priority;
506 #ifdef USE_MEMPOOL
507  friend int ::main(int argc, char** argv);
508  /* Defined in event.cc */
509  typedef Core::MemPool* PoolData_t;
510  struct PoolInfo_t
511  {
512  std::thread::id tid;
513  size_t size;
514  Core::MemPool* pool;
515  PoolInfo_t(std::thread::id tid, size_t size, Core::MemPool* pool) : tid(tid), size(size), pool(pool) {}
516  };
517  static std::mutex poolMutex;
518  static std::vector<PoolInfo_t> memPools;
519 #endif
520 
521  ImplementVirtualSerializable(SST::Activity)
522 };
523 
524 } // namespace SST
525 
526 #endif // SST_CORE_ACTIVITY_H
virtual std::string toString() const
Get a string represenation of the event.
Definition: activity.h:350
Output object provides consistent method for outputting data to stdout, stderr and/or sst debug file...
Definition: output.h:51
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:34
Comparator class to use with STL container classes.
Definition: activity.h:247
void setDeliveryTime(SimTime_t time)
Set the time for which this Activity should be delivered.
Definition: activity.h:326
void setQueueOrder(uint64_t order)
Set a new Queue order.
Definition: activity.h:371
bool operator()(const Activity *lhs, const Activity *rhs) const
Compare pointers.
Definition: activity.h:313
Base class for all Activities in the SST Event Queue.
Definition: activity.h:48
bool operator()(const Activity &lhs, const Activity &rhs) const
Compare based off references.
Definition: activity.h:237
To use with STL container classes.
Definition: activity.h:122
Comparator class to use with STL container classes.
Definition: activity.h:213
bool operator()(const Activity &lhs, const Activity &rhs) const
Compare based off references.
Definition: activity.h:291
bool operator()(const Activity *lhs, const Activity *rhs) const
Compare based off pointers.
Definition: activity.h:91
virtual void execute(void)=0
Function which will be called when the time for this Activity comes to pass.
bool operator()(const Activity *lhs, const Activity *rhs) const
Compare based off pointers.
Definition: activity.h:165
bool operator()(const Activity *lhs, const Activity *rhs) const
Compare based off pointers.
Definition: activity.h:66
bool operator()(const Activity *lhs, const Activity *rhs) const
Compare based off pointers.
Definition: activity.h:126
Definition: serializable.h:118
bool operator()(const Activity &lhs, const Activity &rhs)
Compare based off references.
Definition: activity.h:260
bool operator()(const Activity &lhs, const Activity &rhs) const
Compare references.
Definition: activity.h:319
bool operator()(const Activity &lhs, const Activity &rhs) const
Compare based off references.
Definition: activity.h:107
void setPriority(int priority)
Set the priority of the Activity.
Definition: activity.h:483
SimTime_t getDeliveryTime() const
Return the time at which this Activity will be delivered.
Definition: activity.h:329
To use with STL priority queues, that order in reverse.
Definition: activity.h:87
bool operator()(const Activity *lhs, const Activity *rhs) const
Compare based off pointers.
Definition: activity.h:274
To use with STL priority queues, that order in reverse.
Definition: activity.h:224
void output(uint32_t line, const char *file, const char *func, const char *format,...) const
Output the message with formatting as specified by the format parameter.
Definition: output.h:182
To use with STL priority queues, that order in reverse.
Definition: activity.h:161
bool operator()(const Activity *lhs, const Activity *rhs)
Compare based off pointers.
Definition: activity.h:251
virtual void print(const std::string &header, Output &out) const
Generic print-print function for this Activity.
Definition: activity.h:361
To use with STL container classes.
Definition: activity.h:62
int getPriority() const
Return the Priority of this Activity.
Definition: activity.h:332
bool operator()(const Activity &lhs, const Activity &rhs) const
Compare based off references.
Definition: activity.h:143
bool operator()(const Activity *lhs, const Activity *rhs)
Compare based off pointers.
Definition: activity.h:217
To use with STL priority queues, that order in reverse.
Definition: activity.h:270
Comparator class to use with STL container classes.
Definition: activity.h:309
bool operator()(const Activity &lhs, const Activity &rhs) const
Compare based off references.
Definition: activity.h:187
bool operator()(const Activity *lhs, const Activity *rhs) const
Compare based off pointers.
Definition: activity.h:228
bool operator()(const Activity &lhs, const Activity &rhs) const
Compare based off references.
Definition: activity.h:75
bool operator()(const Activity &lhs, const Activity &rhs)
Compare based off references.
Definition: activity.h:220