SST  12.0.1
StructuralSimulationToolkit
activity.h
1 // Copyright 2009-2022 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-2022, 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 extern int main(int argc, char** argv);
42 
43 namespace SST {
44 
45 /** Base class for all Activities in the SST Event Queue */
47 {
48 public:
49  Activity() : delivery_time(0), priority_order(0), queue_order(0) {}
50  virtual ~Activity() {}
51 
52  /**
53  Class to use as the less than operator for STL functions or
54  sorting algorithms. If a template parameter is set to true,
55  then that variable will be included in the comparison. The
56  parameters are: T - delivery time, P - priority and order tag,
57  Q - queue order.
58  */
59  template <bool T, bool P, bool Q>
60  class less
61  {
62  public:
63  inline bool operator()(const Activity* lhs, const Activity* rhs) const
64  {
65  if ( T && lhs->delivery_time != rhs->delivery_time ) return lhs->delivery_time < rhs->delivery_time;
66  if ( P && lhs->priority_order != rhs->priority_order ) return lhs->priority_order < rhs->priority_order;
67  return Q && lhs->queue_order < rhs->queue_order;
68  }
69 
70  // // Version without branching. Still need to test to see if
71  // // this is faster than the above implementation for "real"
72  // // simulations. For the sst-benchmark, the above is slightly
73  // // faster. Uses the bitwise operator because there are no
74  // // early outs. For bools, this is logically equivalent to the
75  // // logical operators
76  // inline bool operator()(const Activity* lhs, const Activity* rhs) const
77  // {
78  // return ( T & lhs->delivery_time < rhs->delivery_time ) |
79  // (P & lhs->delivery_time == rhs->delivery_time & lhs->priority_order < rhs->priority_order) |
80  // (Q & lhs->delivery_time == rhs->delivery_time & lhs->priority_order == rhs->priority_order &
81  // lhs->queue_order < rhs->queue_order);
82  // }
83 
84  // // Version without ifs, but with early outs in the logic.
85  // inline bool operator()(const Activity* lhs, const Activity* rhs) const
86  // {
87  // return ( T && lhs->delivery_time < rhs->delivery_time ) |
88  // (P && lhs->delivery_time == rhs->delivery_time && lhs->priority_order < rhs->priority_order) |
89  // (Q && lhs->delivery_time == rhs->delivery_time && lhs->priority_order == rhs->priority_order &&
90  // lhs->queue_order < rhs->queue_order);
91  // }
92  };
93 
94  /**
95  Class to use as the greater than operator for STL functions or
96  sorting algorithms (used if you want to sort opposite the
97  natural soring order). If a template parameter is set to true,
98  then that variable will be included in the comparison. The
99  parameters are: T - delivery time, P - priority and order tag,
100  Q - queue order.
101  */
102  template <bool T, bool P, bool Q>
103  class greater
104  {
105  public:
106  inline bool operator()(const Activity* lhs, const Activity* rhs) const
107  {
108  if ( T && lhs->delivery_time != rhs->delivery_time ) return lhs->delivery_time > rhs->delivery_time;
109  if ( P && lhs->priority_order != rhs->priority_order ) return lhs->priority_order > rhs->priority_order;
110  return Q && lhs->queue_order > rhs->queue_order;
111  }
112 
113  // // Version without branching. Still need to test to see if
114  // // this is faster than the above implementation for "real"
115  // // simulations. For the sst-benchmark, the above is slightly
116  // // faster. Uses the bitwise operator because there are no
117  // // early outs. For bools, this is logically equivalent to the
118  // // logical operators
119  // inline bool operator()(const Activity* lhs, const Activity* rhs) const
120  // {
121  // return ( T & lhs->delivery_time > rhs->delivery_time ) |
122  // (P & lhs->delivery_time == rhs->delivery_time & lhs->priority_order > rhs->priority_order) |
123  // (Q & lhs->delivery_time == rhs->delivery_time & lhs->priority_order == rhs->priority_order &
124  // lhs->queue_order > rhs->queue_order);
125  // }
126 
127  // // Version without ifs, but with early outs in the logic.
128  // inline bool operator()(const Activity* lhs, const Activity* rhs) const
129  // {
130  // return ( T && lhs->delivery_time > rhs->delivery_time ) |
131  // (P && lhs->delivery_time == rhs->delivery_time && lhs->priority_order > rhs->priority_order) |
132  // (Q && lhs->delivery_time == rhs->delivery_time && lhs->priority_order == rhs->priority_order &&
133  // lhs->queue_order > rhs->queue_order);
134  // }
135  };
136 
137 
138  /** Function which will be called when the time for this Activity comes to pass. */
139  virtual void execute(void) = 0;
140 
141  /** Set the time for which this Activity should be delivered */
142  inline void setDeliveryTime(SimTime_t time) { delivery_time = time; }
143 
144  /** Return the time at which this Activity will be delivered */
145  inline SimTime_t getDeliveryTime() const { return delivery_time; }
146 
147  /** Return the Priority of this Activity */
148  inline int getPriority() const { return (int)(priority_order >> 32); }
149 
150  /** Sets the order tag */
151  inline void setOrderTag(uint32_t tag) { priority_order = (priority_order & 0xFFFFFFFF00000000ul) | (uint64_t)tag; }
152 
153  /** Return the order tag associated with this activity */
154  inline uint32_t getOrderTag() const { return (uint32_t)(priority_order & 0xFFFFFFFFul); }
155 
156  /** Returns the queue order associated with this activity */
157  inline uint64_t getQueueOrder() const { return queue_order; }
158 
159  /** Get a string represenation of the event. The default version
160  * will just use the name of the class, retrieved through the
161  * cls_name() function inherited from the serialzable class, which
162  * will return the name of the last class to call one of the
163  * serialization macros (ImplementSerializable(),
164  * ImplementVirtualSerializable(), or NotSerializable()).
165  * Subclasses can override this function if they want to add
166  * additional information.
167  */
168  virtual std::string toString() const
169  {
170  std::stringstream buf;
171 
172  buf << cls_name() << " to be delivered at " << getDeliveryTimeInfo();
173  return buf.str();
174  }
175 
176  /** Generic print-print function for this Activity.
177  * Subclasses should override this function.
178  */
179  virtual void print(const std::string& header, Output& out) const
180  {
181  out.output("%s%s\n", header.c_str(), toString().c_str());
182  }
183 
184 #ifdef __SST_DEBUG_EVENT_TRACKING__
185  virtual void printTrackingInfo(const std::string& header, Output& out) const {}
186 #endif
187 
188 protected:
189  /** Set the priority of the Activity */
190  void setPriority(uint64_t priority) { priority_order = (priority_order & 0x00000000FFFFFFFFul) | (priority << 32); }
191 
192  /**
193  Gets the delivery time info as a string. To be used in
194  inherited classes if they'd like to overwrite the default print
195  or toString()
196  */
197  std::string getDeliveryTimeInfo() const
198  {
199  std::stringstream buf;
200  buf << "time: " << delivery_time << ", priority: " << getPriority() << ", order tag: " << getOrderTag()
201  << ", queue order: " << getQueueOrder();
202  return buf.str();
203  }
204 
205  // Function used by derived classes to serialize data members.
206  // This class is not serializable, because not all class that
207  // inherit from it need to be serializable.
208  void serialize_order(SST::Core::Serialization::serializer& ser) override
209  {
210  ser& delivery_time;
211  ser& priority_order;
212  ser& queue_order;
213  }
214  ImplementVirtualSerializable(SST::Activity)
215 
216 
217  /** Set a new Queue order */
218  void setQueueOrder(uint64_t order)
219  {
220  queue_order = order;
221  }
222 
223 private:
224  // Data members
225  SimTime_t delivery_time;
226  // This will hold both the priority (high bits) and the link order
227  // (low_bits)
228  uint64_t priority_order;
229  // Used for TimeVortex implementations that don't naturally keep
230  // the insertion order
231  uint64_t queue_order;
232 
233 
234 #ifdef USE_MEMPOOL
235  friend int ::main(int argc, char** argv);
236  /* Defined in event.cc */
237  typedef Core::MemPool* PoolData_t;
238  struct PoolInfo_t
239  {
240  std::thread::id tid;
241  size_t size;
242  Core::MemPool* pool;
243  PoolInfo_t(std::thread::id tid, size_t size, Core::MemPool* pool) : tid(tid), size(size), pool(pool) {}
244  };
245  static std::mutex poolMutex;
246  static std::vector<PoolInfo_t> memPools;
247 
248 public:
249  /** Allocates memory from a memory pool for a new Activity */
250  void* operator new(std::size_t size) noexcept
251  {
252  /* 1) Find memory pool
253  * 1.5) If not found, create new
254  * 2) Alloc item from pool
255  * 3) Append PoolID to item, increment pointer
256  */
257  Core::MemPool* pool = nullptr;
258  size_t nPools = memPools.size();
259  std::thread::id tid = std::this_thread::get_id();
260  for ( size_t i = 0; i < nPools; i++ ) {
261  PoolInfo_t& p = memPools[i];
262  if ( p.tid == tid && p.size == size ) {
263  pool = p.pool;
264  break;
265  }
266  }
267  if ( nullptr == pool ) {
268  /* Still can't find it, alloc a new one */
269  pool = new Core::MemPool(size + sizeof(PoolData_t));
270 
271  std::lock_guard<std::mutex> lock(poolMutex);
272  memPools.emplace_back(tid, size, pool);
273  }
274 
275  PoolData_t* ptr = (PoolData_t*)pool->malloc();
276  if ( !ptr ) {
277  fprintf(stderr, "Memory Pool failed to allocate a new object. Error: %s\n", strerror(errno));
278  return nullptr;
279  }
280  *ptr = pool;
281  return (void*)(ptr + 1);
282  }
283 
284  /** Returns memory for this Activity to the appropriate memory pool */
285  void operator delete(void* ptr)
286  {
287  /* 1) Decrement pointer
288  * 2) Determine Pool Pointer
289  * 2b) Set Pointer field to nullptr to allow tracking
290  * 3) Return to pool
291  */
292  PoolData_t* ptr8 = ((PoolData_t*)ptr) - 1;
293  Core::MemPool* pool = *ptr8;
294  *ptr8 = nullptr;
295 
296  pool->free(ptr8);
297  }
298  void operator delete(void* ptr, std::size_t UNUSED(sz))
299  {
300  /* 1) Decrement pointer
301  * 2) Determine Pool Pointer
302  * 2b) Set Pointer field to nullptr to allow tracking
303  * 3) Return to pool
304  */
305  PoolData_t* ptr8 = ((PoolData_t*)ptr) - 1;
306  Core::MemPool* pool = *ptr8;
307  *ptr8 = nullptr;
308 
309  pool->free(ptr8);
310  };
311 
312  static void getMemPoolUsage(uint64_t& bytes, uint64_t& active_activities)
313  {
314  bytes = 0;
315  active_activities = 0;
316  for ( auto&& entry : Activity::memPools ) {
317  bytes += entry.pool->getBytesMemUsed();
318  active_activities += entry.pool->getUndeletedEntries();
319  }
320  }
321 
322  static void printUndeletedActivities(const std::string& header, Output& out, SimTime_t before = MAX_SIMTIME_T)
323  {
324  for ( auto&& entry : Activity::memPools ) {
325  const std::list<uint8_t*>& arenas = entry.pool->getArenas();
326  size_t arenaSize = entry.pool->getArenaSize();
327  size_t elemSize = entry.pool->getElementSize();
328  size_t nelem = arenaSize / elemSize;
329  for ( auto iter = arenas.begin(); iter != arenas.end(); ++iter ) {
330  for ( size_t j = 0; j < nelem; j++ ) {
331  PoolData_t* ptr = (PoolData_t*)((*iter) + (elemSize * j));
332  if ( *ptr != nullptr ) {
333  Activity* act = (Activity*)(ptr + 1);
334  if ( act->delivery_time <= before ) {
335  act->print(header, out);
336 #ifdef __SST_DEBUG_EVENT_TRACKING__
337  act->printTrackingInfo(header + " ", out);
338 #endif
339  }
340  }
341  }
342  }
343  }
344  }
345 
346 #endif
347 };
348 
349 } // namespace SST
350 
351 #endif // SST_CORE_ACTIVITY_H
virtual std::string toString() const
Get a string represenation of the event.
Definition: activity.h:168
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
void setDeliveryTime(SimTime_t time)
Set the time for which this Activity should be delivered.
Definition: activity.h:142
void setQueueOrder(uint64_t order)
Set a new Queue order.
Definition: activity.h:218
Base class for all Activities in the SST Event Queue.
Definition: activity.h:46
uint32_t getOrderTag() const
Return the order tag associated with this activity.
Definition: activity.h:154
void setOrderTag(uint32_t tag)
Sets the order tag.
Definition: activity.h:151
virtual void execute(void)=0
Function which will be called when the time for this Activity comes to pass.
uint64_t getQueueOrder() const
Returns the queue order associated with this activity.
Definition: activity.h:157
void setPriority(uint64_t priority)
Set the priority of the Activity.
Definition: activity.h:190
Definition: serializable.h:118
std::string getDeliveryTimeInfo() const
Gets the delivery time info as a string.
Definition: activity.h:197
SimTime_t getDeliveryTime() const
Return the time at which this Activity will be delivered.
Definition: activity.h:145
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
virtual void print(const std::string &header, Output &out) const
Generic print-print function for this Activity.
Definition: activity.h:179
int getPriority() const
Return the Priority of this Activity.
Definition: activity.h:148
Class to use as the greater than operator for STL functions or sorting algorithms (used if you want t...
Definition: activity.h:103
Simple Memory Pool class.
Definition: mempool.h:32
Class to use as the less than operator for STL functions or sorting algorithms.
Definition: activity.h:60