SST 16.1.0
Structural Simulation Toolkit
clock.h
1// Copyright 2009-2026 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-2026, 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_CLOCK_H
13#define SST_CORE_CLOCK_H
14
15#include "sst/core/action.h"
16#include "sst/core/ssthandler.h"
17#include "sst/core/timeConverter.h"
18#include "sst/core/util/bit_util.h"
19
20#include <cinttypes>
21#include <string>
22#include <utility>
23#include <vector>
24
25#define _CLE_DBG(fmt, args...) __DBG(DBG_CLOCK, Clock, fmt, ##args)
26
27namespace SST {
28
29class BaseComponent;
30class Component;
31class Simulation;
32class TimeConverter;
33
34/**
35 * A Clock class.
36 *
37 * Calls callback functions (handlers) on a specified period
38 */
39class Clock : public Action
40{
41public:
42 class HandlerBase;
43
44private:
45 friend class BaseComponent;
46 friend class Component;
47 friend class Simulation;
48 // Clock Group for handling ordered clocks
49 class Group
50 {
51 friend class Clock;
52
53 std::vector<HandlerBase*> handlers_;
54 int32_t inactive_start_ = 0;
55 uint16_t handler_count_ = 0;
56 Clock* clock_ = nullptr;
57 int32_t index_;
58
59 public:
60
61 /**
62 Get the period of the associated clock as a SimTime_t in units of the core atomic timebase
63 */
64 TimeConverter getClockPeriod() { return clock_->getPeriod(); }
65
66 /**
67 Get the priority of the associated clock as a SimTime_t in units of the core atomic timebase
68 */
69 int getClockPriority() { return clock_->getPriority(); }
70
71 /**
72 Get the next cycle for the clock associated with this group
73 */
74 SimTime_t getNextCycle() { return clock_->getNextCycle(); }
75
76 /**
77 Registers a handler with this group and marks it as active. This function should only be called once when
78 the handler is registered. To activate or deactivate, call activateHandler()/deactivateHandler().
79 */
80 void registerHandler(HandlerBase* handler, uint16_t order = 0);
81
82 /**
83 Activates a handler.
84 */
85 void activateHandler(HandlerBase* handler);
86
87 /**
88 Deactivates a Handler
89 */
90 void deactivateHandler(HandlerBase* handler);
91
92 /**
93 Activates the Group if there are any active handlers
94 */
95 void activateOnRestart();
96
97 /**
98 Call all active handlers
99 */
100 bool execute(Cycle_t current_cycle);
101
102 void serialize_order(SST::Core::Serialization::serializer& ser);
103
104 private:
105
106 /**
107 Swaps locations of an active handler with an inactive handler. It will also swap the index state of the two
108 handlers. No checks will be done to ensure the active state
109 */
110 static void swapActiveWithInactive(HandlerBase*& active, HandlerBase*& inactive)
111 {
112 // First swap the indices, then do the actual pointer swap
113 int32_t tmp = -1 - inactive->index_;
114 inactive->index_ = -1 - active->index_;
115 active->index_ = tmp;
116
117 std::swap(active, inactive);
118 }
119
120 /**
121 Swaps locations of two handlers with the same active state. It will also swap the index state of the two
122 handlers. No checks will be done to ensure the active states are the same
123 */
124 static void swapSameActiveState(HandlerBase*& h1, HandlerBase*& h2)
125 {
126 // First swap the indices, then do the actual pointer swap
127 std::swap(h1->index_, h2->index_);
128 std::swap(h1, h2);
129 }
130 };
131
132public:
133 /** Create a new clock with a specified period */
134 Clock(TimeConverter period, int priority = CLOCKPRIORITY);
135 ~Clock() = default; // Handlers are owned by BaseComponent and are deleted there
136
137
138 /**
139 Base classes for clock handlers. There are three classes:
140
141 HandlerBase: This is a publicly available class that is the base class that contains the API used by elements,
142 including checking active status and starting and stopping the handler.
143 */
144
145 class HandlerBase : public SSTHandlerBase<bool, Cycle_t>
146 {
147 public:
148 HandlerBase() = default;
149 ~HandlerBase() = default;
150
151 void serialize_order(SST::Core::Serialization::serializer& ser) override
152 {
153 SSTHandlerBase<bool, Cycle_t>::serialize_order(ser);
154 SST_SER(index_);
155 SST_SER(order_);
156 // No need to serialize clock_ or group_ as they get reset on restart
157 }
158
159 ImplementVirtualSerializable(HandlerBase);
160
161 /**
162 Get the period of the associated clock as a SimTime_t in units of the core atomic timebase
163 */
165 {
166 return (order_ == bit_util::type_max<uint32_t>) ? clock_->getPeriod() : group_->getClockPeriod();
167 }
168
169 /**
170 Get the priority of the associated clock as a SimTime_t in units of the core atomic timebase
171 */
173 {
174 return (order_ == bit_util::type_max<uint32_t>) ? clock_->getPriority() : group_->getClockPriority();
175 }
176
177 /**
178 Query whether handler is currently active
179 */
180 bool isActive() { return index_ >= 0; }
181
182 /**
183 Activate this Clock Handler
184
185 @return Time of next time clock handler will fire
186 */
187 Cycle_t activate()
188 {
189 if ( order_ == bit_util::type_max<uint32_t> ) {
190 clock_->registerHandler(this);
191 return clock_->getNextCycle();
192 }
193 else {
194 group_->activateHandler(this);
195 return group_->getNextCycle();
196 }
197 }
198
199 /**
200 Deactivate this Clock Handler
201 */
203 {
204 if ( order_ == bit_util::type_max<uint32_t> ) {
205 bool empty = false;
206 clock_->unregisterHandler(this, empty);
207 }
208 else {
209 group_->deactivateHandler(this);
210 }
211 }
212
213 private:
214 friend class BaseComponent;
215 friend class Clock;
216
217 /**
218 Clock object associated with this Handler. Clock::Handlers should only ever be registered with one clock
219 frequency. If you need multiple clock frequencies, each should get their own handler.
220
221 NOTE: Registering with two different clocks will continue to "work", though it may have unintended
222 results. For now, a warning will be issued, but starting at SST 17, this will become an error condition.
223 */
224 union {
225 Clock* clock_ = nullptr;
226 Group* group_;
227 };
228
229
230 /**
231 Tracks the order for this handler. If it is type_max<uint32_t>, then the handler is not ordered. If it is
232 ordered, then it's contained in a Clock::Group rather than a Clock
233 */
234 uint32_t order_ = bit_util::type_max<uint32_t>;
235
236 /**
237 Dual purpose variable. Because adding a bool to this class would require 8-bytes due to padding, the index_
238 variable will also be used to indicate if the handler is active or not. If < 0, then then it is not
239 active. The other purpose of the variable is to hold the index where the handler currently resides in the
240 handler list of either the Clock or Clock::Group object. The index for inactive handlers will be stored
241 starting at -1 (i.e. -1 means inactive at index 0, -2 means inactive at index 1, etc). If an implementation
242 of either Clock or Clock::Group does not store inactive handers in the array, then any negative number can be
243 used to indicate that the handler is inactive.
244 */
245 int32_t index_ = -1;
246
247 /**
248 Mark the handler as active.
249 */
250 void markAsActive()
251 {
252 if ( index_ >= 0 ) return;
253 index_ = -1 - index_;
254 }
255
256 /**
257 Mark the handler as inactive.
258 */
259 void markAsInactive()
260 {
261 if ( index_ < 0 ) return;
262 index_ = -1 - index_;
263 }
264
265 /**
266 Toggle the active state of the handler.
267 */
268 void toggleActiveState() { index_ = -1 - index_; }
269 };
270
271 /**
272 Used to create handlers for clock. The callback function is
273 expected to be in the form of:
274
275 bool func(Cycle_t cycle)
276
277 In which case, the class is created with:
278
279 new Clock::Handler<classname, &classname::function_name>(this)
280
281 Or, to add static data, the callback function is:
282
283 bool func(Cycle_t cycle, dataT data)
284
285 and the class is created with:
286
287 new Clock::Handler<classname, &classname::function_name, dataT>(this, data)
288
289 In both cases, the boolean that's returned indicates whether
290 the handler should be removed from the list or not. On return
291 of true, the handler will be removed. On return of false, the
292 handler will be left in the clock list.
293 */
294 template <typename classT, auto funcT, typename dataT = void>
296
297 /**
298 Handler2 version which is now the same as Handler and is provided for backward compatibility until SST 17
299 */
300 template <typename classT, auto funcT, typename dataT = void>
301 using Handler2 [[deprecated(
302 "The name Handler2 has been deprecated and will be removed in SST 17. Please rename Handler2 to Handler.")]]
304
305
306 /**
307 * Activates this clock object, by inserting into the simulation's
308 * timeVortex for future execution.
309 */
310 void schedule();
311
312 /** Return the time of the next clock tick */
313 Cycle_t getNextCycle();
314
315 /**
316 * Update current cycle count - needed at simulation end if clock has run
317 * ahead of simulation end and to return correct cycle count in getNextCycle()
318 * for clocks that are currently not scheduled
319 */
320 void updateCurrentCycle();
321
322 /**
323 Add a handler to be called on this clock's tick
324 */
325 void registerHandler(Clock::HandlerBase* handler);
326
327 /**
328 Remove a handler from the list of handlers to be called on the clock tick
329 */
330 bool unregisterHandler(Clock::HandlerBase* handler, bool& empty);
331
332 /**
333 Add a handler to this Clock object during restart
334 */
336
337 /**
338 Checks to see if a handler is registered with this clock
339 */
341
342 /**
343 Register a group with this Clock object
344 */
345 void registerGroup(Group* group);
346
347 /**
348 Activates a group that is inactive. If group is already active, nothing is done. There is no need for a
349 deactivateGroup() call as deactivation is only done based on return value during execute()
350 */
351 void activateGroup(Group* group);
352
353 std::string toString() const override;
354
355 /**
356 Get the period of the clock as a TimeConverter
357 */
358 TimeConverter getPeriod() { return period_; }
359
360private:
361
362 Clock();
363 Clock(const Clock&) = delete;
364 Clock& operator=(const Clock&) = delete;
365
366 void execute() override;
367
368 // Vectors to hold the handlers and groups
369 std::vector<HandlerBase*> handlers_;
370 std::vector<Group*> groups_;
371 int32_t groups_inactive_start_ = 0;
372
373 Cycle_t current_cycle_ = 0;
374 TimeConverter period_;
375 SimTime_t next_ = 0;
376 bool scheduled_ = false;
377 Simulation* sim_ = nullptr;
378
379 void serialize_order(SST::Core::Serialization::serializer& ser) override;
380 ImplementSerializable(SST::Clock)
381};
382
383
384class ClockHandlerMetaData : public AttachPointMetaData
385{
386public:
387 const ComponentId_t comp_id;
388 const std::string comp_name;
389 const std::string comp_type;
390
391 ClockHandlerMetaData(ComponentId_t id, const std::string& cname, const std::string& ctype) :
392 comp_id(id),
393 comp_name(cname),
394 comp_type(ctype)
395 {}
396
397 ~ClockHandlerMetaData() {}
398};
399
400
401} // namespace SST
402
403#endif // SST_CORE_CLOCK_H
virtual void execute()=0
Function which will be called when the time for this Activity comes to pass.
int getPriority() const
Return the Priority of this Activity.
Definition activity.h:153
Main component object for the simulation.
Definition baseComponent.h:98
Base classes for clock handlers.
Definition clock.h:146
Cycle_t activate()
Activate this Clock Handler.
Definition clock.h:187
TimeConverter getClockPeriod()
Get the period of the associated clock as a SimTime_t in units of the core atomic timebase.
Definition clock.h:164
int getClockPriority()
Get the priority of the associated clock as a SimTime_t in units of the core atomic timebase.
Definition clock.h:172
void deactivate()
Deactivate this Clock Handler.
Definition clock.h:202
bool isActive()
Query whether handler is currently active.
Definition clock.h:180
A Clock class.
Definition clock.h:40
Cycle_t getNextCycle()
Return the time of the next clock tick.
Definition clock.cc:306
SSTHandler< bool, Cycle_t, classT, dataT, funcT, HandlerBase > Handler
Used to create handlers for clock.
Definition clock.h:295
void schedule()
Activates this clock object, by inserting into the simulation's timeVortex for future execution.
Definition clock.cc:400
void registerHandler(Clock::HandlerBase *handler)
Add a handler to be called on this clock's tick.
Definition clock.cc:193
std::string toString() const override
Get a string represenation of the event.
Definition clock.cc:430
void activateGroup(Group *group)
Activates a group that is inactive.
Definition clock.cc:288
bool isHandlerRegistered(Clock::HandlerBase *handler)
Checks to see if a handler is registered with this clock.
Definition clock.cc:268
bool unregisterHandler(Clock::HandlerBase *handler, bool &empty)
Remove a handler from the list of handlers to be called on the clock tick.
Definition clock.cc:234
void registerHandler_restart(Clock::HandlerBase *handler)
Add a handler to this Clock object during restart.
Definition clock.cc:254
void registerGroup(Group *group)
Register a group with this Clock object.
Definition clock.cc:278
TimeConverter getPeriod()
Get the period of the clock as a TimeConverter.
Definition clock.h:357
Clock(TimeConverter period, int priority=CLOCKPRIORITY)
Create a new clock with a specified period.
Definition clock.cc:182
SSTHandler< bool, Cycle_t, classT, dataT, funcT, HandlerBase > Handler2
Handler2 version which is now the same as Handler and is provided for backward compatibility until SS...
void updateCurrentCycle()
Update current cycle count - needed at simulation end if clock has run ahead of simulation end and to...
Definition clock.cc:423
Main component object for the simulation.
Definition component.h:32
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition serializer.h:43
Base template for handlers which take a class defined argument.
Definition ssthandler.h:110
Base template for the class.
Definition ssthandler.h:1128
Main control class for a SST Simulation.
Definition simulation.h:121
A class to convert between a component's view of time and the core's view of time.
Definition timeConverter.h:31
UnitAlgebra getPeriod() const
Definition timeLord.cc:119