Skip to content

Commit 8657687

Browse files
authored
TimeVortex is no longer serialized during checkpoint/restart. (#1334)
On checkpoint, the TimeVortex returns a copy of its contents, which are then sorted. Events are serialized with the Component trees they are targetting. Actions are ignored and are recreated on restart. The Actions that are recreated are: StopAction, Exit, Clocks, OneShots (for stats). As a consequence, a couple things were added: - BaseComponent now sorts the clocks that are registered through it so that it can ensure they exist after restart - OneShotManager was added and can create OneShots whose trigger time is either absolute or relative to current time Stat Groups now checkpoint/restart correctly Event and Action now define both isAction() and isEvent() as final Unrelated fix: TimeVortexPQ can now properly print its contents
1 parent 03d4531 commit 8657687

39 files changed

+760
-400
lines changed

src/sst/core/Makefile.am

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ sst_core_sources = \
198198
mempool.cc \
199199
mempoolAccessor.h \
200200
namecheck.cc \
201-
oneshot.cc \
202201
output.cc \
203202
params.cc \
204203
pollingLinkQueue.cc \

src/sst/core/action.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class Action : public Activity
2929
Action() {}
3030
~Action() {}
3131

32-
bool isAction() override final { return true; }
32+
bool isEvent() const override final { return false; }
33+
bool isAction() const override final { return true; }
3334

3435
protected:
3536
/** Called to signal to the Simulation object to end the simulation */

src/sst/core/activity.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ class Activity : public SST::Core::MemPoolItem
159159
/** Returns the queue order associated with this activity */
160160
inline uint64_t getQueueOrder() const { return queue_order; }
161161

162-
virtual bool isEvent() { return false; }
163-
virtual bool isAction() { return false; }
162+
virtual bool isEvent() const = 0;
163+
virtual bool isAction() const = 0;
164164

165165
/** Get a string represenation of the event. The default version
166166
* will just use the name of the class, retrieved through the

src/sst/core/baseComponent.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ BaseComponent::pushValidParams(Params& params, const std::string& type)
122122
void
123123
BaseComponent::registerClock_impl(TimeConverter* tc, Clock::HandlerBase* handler, bool regAll)
124124
{
125+
// Add this clock to our registered_clocks_ set
126+
registered_clocks_.insert(tc->getFactor());
125127

126128
// Need to see if I already know about this clock handler
127129
bool found = false;
@@ -962,6 +964,9 @@ BaseComponent::serialize_order(SST::Core::Serialization::serializer& ser)
962964
case SST::Core::Serialization::serializer::SIZER:
963965
case SST::Core::Serialization::serializer::PACK:
964966
{
967+
// Serialize our registered_clocks_
968+
SST_SER(registered_clocks_);
969+
965970
// Need to serialize each handler
966971
std::pair<Clock::HandlerBase*, SimTime_t> p;
967972
size_t num_handlers = clock_handlers_.size();
@@ -985,6 +990,11 @@ BaseComponent::serialize_order(SST::Core::Serialization::serializer& ser)
985990
primaryComponentDoNotEndSim();
986991
}
987992

993+
SST_SER(registered_clocks_);
994+
for ( auto x : registered_clocks_ ) {
995+
sim_->reportClock(x, CLOCKPRIORITY);
996+
}
997+
988998
std::pair<Clock::HandlerBase*, SimTime_t> p;
989999
size_t num_handlers;
9901000
SST_SER(num_handlers);

src/sst/core/baseComponent.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include "sst/core/eli/elementinfo.h"
1818
#include "sst/core/event.h"
1919
#include "sst/core/factory.h"
20-
#include "sst/core/oneshot.h"
2120
#include "sst/core/portModule.h"
2221
#include "sst/core/profile/componentProfileTool.h"
2322
#include "sst/core/serialization/serializable_base.h"
@@ -1143,6 +1142,7 @@ class BaseComponent : public SST::Core::Serialization::serializable_base
11431142
// Need to track clock handlers for checkpointing. We need to
11441143
// know what clock handlers we have registered with the core
11451144
std::vector<Clock::HandlerBase*> clock_handlers_;
1145+
std::set<SimTime_t> registered_clocks_;
11461146

11471147
void addSelfLink(const std::string& name);
11481148
Link* getLinkFromParentSharedPort(const std::string& port, std::vector<ConfigPortModule>& port_modules);

src/sst/core/clock.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,12 @@ Clock::schedule()
128128
// simtime. This happens if the clock would have fired at this
129129
// tick and if the current priority is less than my priority.
130130
// However, if we are at time = 0, then we always go out to the
131-
// next cycle;
132-
if ( sim->getCurrentPriority() < getPriority() && sim->getCurrentSimCycle() != 0 ) {
131+
// next cycle. Also, if the call happens during complete() or
132+
// finish(), then we don't adjust either.
133+
if ( sim->getCurrentPriority() < getPriority() && sim->getCurrentSimCycle() != 0 && !sim->endSim ) {
133134
if ( sim->getCurrentSimCycle() % period->getFactor() == 0 ) {
134135
next = sim->getCurrentSimCycle();
136+
currentCycle--; // First thing execute does in increment currentCycle
135137
}
136138
}
137139

src/sst/core/componentInfo.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,9 @@ ComponentInfo::serialize_order(SST::Core::Serialization::serializer& ser)
268268
if ( !is_null ) SST_SER(*enabled_stat_names_);
269269
}
270270

271-
SST_SER(statLoadLevel); // Potentially needed for late stat registration
271+
// Potentially needed for late stat registration
272+
SST_SER(statLoadLevel);
273+
SST_SER(enabled_all_stats_);
272274

273275
// For SubComponents map, need to serialize map by hand since we
274276
// we will need to use the track non-pointer as pointer feature in

src/sst/core/event.h

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,18 @@ class NullEvent;
2727
class RankSync;
2828
class ThreadSync;
2929

30+
namespace pvt {
31+
class DeliveryInfoCompEvent;
32+
} // namespace pvt
33+
3034
/**
3135
* Base class for Events - Items sent across links to communicate between
3236
* components.
3337
*/
3438
class Event : public Activity
3539
{
40+
friend class pvt::DeliveryInfoCompEvent;
41+
3642
public:
3743
/**
3844
Base handler for event delivery.
@@ -69,6 +75,28 @@ class Event : public Activity
6975
template <typename classT, auto funcT, typename dataT = void>
7076
using Handler2 = SSTHandler2<void, Event*, classT, dataT, funcT>;
7177

78+
/**
79+
Class used to sort events during checkpointing. This is used
80+
to sort events by delivery_info so we can use std::lower_bound
81+
to easily find events targeting a specific handler. For Events
82+
targetting the same handler, it will sort according to
83+
Activity::less. This will ensure that things get inserted back
84+
in correct order, though the only important thing is that
85+
insertion order is maintained, so two events to be delivered at
86+
the same time maintain their send order.
87+
88+
*/
89+
class less
90+
{
91+
public:
92+
bool operator()(const Event* lhs, const Event* rhs) const
93+
{
94+
if ( lhs->delivery_info != rhs->delivery_info ) return lhs->delivery_info < rhs->delivery_info;
95+
return Activity::less<true, true, true>()(lhs, rhs);
96+
}
97+
};
98+
99+
72100
/** Type definition of unique identifiers */
73101
using id_type = std::pair<uint64_t, int>;
74102
/** Constant, default value for id_types */
@@ -123,7 +151,8 @@ class Event : public Activity
123151

124152
#endif
125153

126-
bool isEvent() override final { return true; }
154+
bool isEvent() const override final { return true; }
155+
bool isAction() const override final { return false; }
127156

128157
void copyAllDeliveryInfo(const Activity* act) override final
129158
{
@@ -184,6 +213,15 @@ class Event : public Activity
184213
this->delivery_info = delivery_info;
185214
}
186215

216+
/**
217+
Update the delivery_info during a restart. This will fixup the
218+
handler pointer.
219+
220+
@param dinfo New handler pointer cast as a uintptr_t
221+
*/
222+
void updateDeliveryInfo(uintptr_t dinfo) { delivery_info = dinfo; }
223+
224+
187225
/** Gets the link id used for delivery. For use by SST Core only */
188226
inline Link* getDeliveryLink() { return reinterpret_cast<Link*>(delivery_info); }
189227

@@ -250,6 +288,22 @@ class EventHandlerMetaData : public AttachPointMetaData
250288
~EventHandlerMetaData() {}
251289
};
252290

291+
namespace pvt {
292+
293+
/**
294+
Class used with std::lower_bound to find the start of events in a
295+
sorted list with the specified delivery_info.
296+
*/
297+
class DeliveryInfoCompEvent : public Event
298+
{
299+
public:
300+
static uintptr_t getDeliveryInfo(Event* ev) { return ev->delivery_info; }
301+
302+
DeliveryInfoCompEvent(uintptr_t delivery_info) { setDeliveryInfo(0, delivery_info); }
303+
};
304+
305+
} // namespace pvt
306+
253307
} // namespace SST
254308

255309
#endif // SST_CORE_EVENT_H

src/sst/core/impl/Makefile.inc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
#
44
#
55

6+
sst_core_sources += \
7+
impl/oneshotManager.h \
8+
impl/oneshotManager.cc
9+
10+
611
include impl/interactive/Makefile.inc
712
include impl/timevortex/Makefile.inc
813
include impl/partitioners/Makefile.inc
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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+
#include "sst_config.h"
13+
14+
#include "sst/core/impl/oneshotManager.h"
15+
16+
#include "sst/core/simulation_impl.h"
17+
#include "sst/core/timeVortex.h"
18+
19+
namespace SST::Core {
20+
21+
void
22+
OneShot::execute()
23+
{
24+
// Call all the handlers. Delete each one once after calling.
25+
// The handlers are guaranteed not to be shared.
26+
for ( auto* x : handlers ) {
27+
(*x)();
28+
delete x;
29+
}
30+
31+
manager->oneshotCallback(time, this);
32+
}
33+
34+
35+
OneShotManager::OneShotManager(Simulation_impl* sim) :
36+
sim_(sim)
37+
{}
38+
39+
OneShotManager::~OneShotManager()
40+
{
41+
// Need to delete all the Handlers
42+
for ( auto& list : handler_vector_map_ ) {
43+
for ( auto* item : list.second.first ) {
44+
delete item;
45+
}
46+
}
47+
}
48+
49+
void
50+
OneShotManager::registerHandlerBase(SimTime_t trigger_time, int priority, bool relative, OneShot::HandlerBase* handler)
51+
{
52+
53+
// Check to make sure this isn't in the past
54+
TimeStamp_t curr_time = std::make_pair(sim_->getCurrentSimCycle(), sim_->getCurrentPriority());
55+
TimeStamp_t trig_time = std::make_pair(trigger_time + (relative ? sim_->getCurrentSimCycle() : 0), priority);
56+
57+
if ( trig_time <= curr_time ) {
58+
// Emit warning and ignore request
59+
sim_->getSimulationOutput().output(
60+
"WARNING: Trying to register a OneShot for a time in the past, ignoring request\n");
61+
return;
62+
}
63+
64+
// Get the handler list for the specified time stamp. If it's not
65+
// already there, it will be created.
66+
std::pair<OneShot::HandlerList_t, bool>& map_item = handler_vector_map_[trig_time];
67+
68+
// Push handler onto the list
69+
map_item.first.push_back(handler);
70+
71+
// Check to see if anything needs to be scheduled
72+
scheduleNextOneShot();
73+
}
74+
75+
void
76+
OneShotManager::oneshotCallback(TimeStamp_t time, OneShot* oneshot)
77+
{
78+
// Remove the data for this time, schedule the next time and
79+
// delete the OneShot.
80+
handler_vector_map_.erase(time);
81+
delete oneshot;
82+
83+
scheduleNextOneShot();
84+
}
85+
86+
void
87+
OneShotManager::scheduleNextOneShot()
88+
{
89+
// Get next event to schdule. Iterator maps as follows:
90+
// it.first : TimeStamp_t : trigger time
91+
// it.second.first = HandlerList_t : list of handlers to call
92+
// it.second.second = bool : scheduled
93+
auto it = handler_vector_map_.begin();
94+
95+
// If there are no events, return
96+
if ( it == handler_vector_map_.end() ) return;
97+
98+
// If first event is already scheduled, nothing to do
99+
if ( it->second.second ) return;
100+
101+
// Not yet scheduled, create a OneShot and insert into TimeVortex
102+
TimeStamp_t t = it->first;
103+
104+
OneShot* oneshot = new OneShot(t, this, it->second.first);
105+
sim_->timeVortex->insert(oneshot);
106+
it->second.second = true;
107+
}
108+
109+
} // namespace SST::Core

0 commit comments

Comments
 (0)