9#include <unordered_set>
12#include "sparta/functional/ArchData.hpp"
16#include "sparta/serialization/checkpoint/DeltaCheckpoint.hpp"
19#ifndef DEFAULT_SNAPSHOT_THRESH
20#define DEFAULT_SNAPSHOT_THRESH 20
23namespace sparta::serialization::checkpoint
71 using checkpoint_ptr = std::unique_ptr<checkpoint_type>;
72 using checkpoint_ptrs = std::vector<checkpoint_ptr>;
94 snap_thresh_(DEFAULT_SNAPSHOT_THRESH),
96 num_alive_checkpoints_(0),
97 num_alive_snapshots_(0),
98 num_dead_checkpoints_(0)
117 snap_thresh_(DEFAULT_SNAPSHOT_THRESH),
119 num_alive_checkpoints_(0),
120 num_alive_snapshots_(0),
121 num_dead_checkpoints_(0)
131 for(
auto itr = chkpts_.rbegin(); itr != chkpts_.rend(); ++itr){
165 snap_thresh_ = thresh;
176 for(
auto& cp : chkpts_){
177 mem += cp.second->getTotalMemoryUse();
188 for(
auto& cp : chkpts_){
189 mem += cp.second->getContentMemoryUse();
226 <<
id <<
" because no checkpoint by this ID was found";
233 num_dead_checkpoints_++;
235 num_alive_snapshots_--;
237 num_alive_checkpoints_--;
263 <<
id <<
" because no checkpoint by this ID was found";
295 std::vector<chkpt_id_t> results;
296 for(
auto& p : chkpts_){
300 results.push_back(cp->
getID());
315 std::vector<chkpt_id_t> results;
316 for(
auto& p : chkpts_){
320 results.push_back(cp->
getID());
330 return num_alive_checkpoints_;
337 return num_alive_snapshots_;
352 return num_dead_checkpoints_;
371 std::deque<chkpt_id_t> results;
380 results.push_back(d->
getID());
428 auto it = chkpts_.find(
id);
429 if (it != chkpts_.end()) {
443 return chkpts_.find(
id) != chkpts_.end();
450 std::vector<chkpt_id_t> next_ids;
452 for (
const auto next : chkpt->getNexts()) {
454 if (!dcp->isFlaggedDeleted()) {
455 next_ids.push_back(next->getID());
473 std::stringstream ss;
474 ss <<
"<FastCheckpointer on ";
475 for (
size_t i = 0; i <
getRoots().size(); ++i) {
492 for(
auto& cp : chkpts_){
493 o << cp.second->stringize() << std::endl;
503 for(
auto& cp : chkpts_){
504 cp.second->dumpData(o);
516 for(
auto& cp : chkpts_){
517 o << cp.second->stringize() << std::endl;
518 cp.second->dumpData(o);
528 o <<
"trace: Searching for 0x" << std::hex << offset <<
" (" << std::dec << size
529 <<
" bytes) in ArchData " << (
const void*)container <<
" when loading checkpoint "
530 << std::dec <<
id << std::endl;
532 o <<
"trace: Checkpoint " <<
id <<
" not found" << std::endl;
552 template <
typename DiskT>
555 if (!disk_checkpoints.empty()) {
556 disk.saveCheckpoints(std::move(disk_checkpoints));
577 checkpoint_ptrs to_save;
583 if (force_new_head_chkpt) {
591 std::reverse(chkpt_chain.begin(), chkpt_chain.end());
593 for (
auto id : chkpt_chain) {
595 auto chkpt = std::move(chkpts_[
id]);
598 if (chkpt->isSnapshot()) {
602 to_save.emplace_back(std::move(chkpt));
606 for (
auto& [
id, chkpt] : chkpts_) {
607 chkpt->flagDeleted();
654 if (chkpt_chain.size() == restore_chain.size()) {
655 std::unordered_set<chkpt_id_t> to_keep(chkpt_chain.begin(), chkpt_chain.end());
656 std::vector<chkpt_id_t> to_delete;
657 for (
auto& [
id, chkpt] : chkpts_) {
658 if (!to_keep.count(
id)) {
659 chkpt->flagDeleted();
660 to_delete.emplace_back(
id);
664 for (
auto id : to_delete) {
665 auto chkpt = std::move(chkpts_[
id]);
668 if (chkpt->isSnapshot()) {
705 std::reverse(chkpt_chain.begin(), chkpt_chain.end());
706 std::unordered_set<chkpt_id_t> to_keep;
708 for (
auto id : chkpt_chain) {
709 if (
id != restore_chain.top()->getID()) {
710 auto chkpt = std::move(chkpts_[
id]);
713 if (chkpt->isSnapshot()) {
717 to_save.emplace_back(std::move(chkpt));
720 if (restore_chain.top()->isSnapshot()) {
723 to_keep.insert(restore_chain.top()->getID());
726 if (restore_chain.empty()) {
732 std::vector<chkpt_id_t> to_delete;
733 for (
auto& [
id, chkpt] : chkpts_) {
734 if (!to_keep.count(
id)) {
735 to_delete.emplace_back(
id);
739 for (
auto id : to_delete) {
740 auto & chkpt = chkpts_[id];
741 chkpt->flagDeleted();
744 if (chkpt->isSnapshot()) {
749 for (
auto id : to_delete) {
830 num_dead_checkpoints_--;
833 auto itr = chkpts_.find(
id);
853 const std::vector<Checkpoint*> & nexts = d->
getNexts();
854 for(
const auto & chkpt : nexts)
891 auto itr = chkpts_.find(
id);
892 if (itr != chkpts_.end()) {
902 auto itr = chkpts_.find(
id);
903 if (itr != chkpts_.end()) {
913 static std::string SNAPSHOT_NOTICE =
"(s)";
917 if(cp->isFlaggedDeleted()){
918 o << cp->getDeletedRepr();
923 if(cp->isSnapshot()){
924 o <<
' ' << SNAPSHOT_NOTICE;
933 void createHead_()
override {
940 if(root->isFinalized() ==
false){
941 CheckpointError exc(
"Cannot create a checkpoint until the tree is finalized. Attempting to checkpoint from node ");
942 exc << root->getLocation() <<
" at tick ";
946 exc <<
"<no scheduler>";
952 checkpoint_type* dcp =
new checkpoint_type(
getArchDatas(), next_chkpt_id_++, tick,
nullptr,
true);
953 chkpts_[dcp->getID()].reset(dcp);
955 num_alive_checkpoints_++;
956 num_alive_snapshots_++;
960 chkpt_id_t createCheckpoint_(
bool force_snapshot=
false)
override {
962 checkpoint_type* prev;
965 throw CheckpointError(
"Exhausted all ")
967 <<
"This is likely a gross misuse of checkpointing";
981 throw CheckpointError(
"Cannot create a new checkpoint at tick ")
982 << tick <<
" because this tick number is smaller than the tick number of the head checkpoint at: "
983 <<
getHead()->
getTick() <<
". The head checkpoint cannot be reset once created, so it should be done "
984 <<
"at the start of simulation before running. The simulator front-end should do this so this must "
985 <<
"likely be fixed in the simulator.";
990 prev =
static_cast<checkpoint_type*
>(
getHead_());
994 throw CheckpointError(
"Current tick number from sparta scheduler (")
995 << tick <<
" ) is less than the current checkpoint's tick number ("
996 <<
getCurrent_()->
getTick() <<
" To create a checkpoint with an earlier tick number, an "
997 <<
"older checkpoint having a tick number <= the tick number specified here must first be "
1003 prev =
static_cast<checkpoint_type*
>(
getCurrent_());
1007 checkpoint_type* dcp =
new checkpoint_type(
getArchDatas(),
1011 force_snapshot || is_snapshot);
1012 chkpts_[dcp->getID()].reset(dcp);
1013 num_alive_checkpoints_++;
1014 num_alive_snapshots_ += (dcp->isSnapshot() ==
true);
1017 if (dcp->isSnapshot()){
1024 return dcp->getID();
1035 std::map<chkpt_id_t, checkpoint_ptr> chkpts_;
1041 uint32_t snap_thresh_;
1052 uint32_t num_alive_checkpoints_;
1060 uint32_t num_alive_snapshots_;
1066 uint32_t num_dead_checkpoints_;
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Exception class for all of Sparta.
Basic Node framework in sparta device tree composite pattern.
Contains a set of contiguous line of architectural data which can be referred to by any architected o...
A class that lets you schedule events now and in the future.
Tick getCurrentTick() const noexcept
The current tick the Scheduler is working on or just finished.
void restartAt(Tick t)
Clears the events in the scheduler, sets the current tick to tick and the elapsed ticks to either tic...
Node in a composite tree representing a sparta Tree item.
std::string getLocation() const override final
chkpt_id_t getID() const noexcept
Returns the ID of this checkpoint.
tick_t getTick() const noexcept
Returns the tick number at which this checkpoint was taken.
static const chkpt_id_t UNIDENTIFIED_CHECKPOINT
Indicates unidentified checkpoint (could mean 'invalid' or 'any') depending on context.
Indicates that there was an issue operating on checkpoints within the SPARTA framework.
Single checkpoint object interface with a tick number and an ID unique to the owning Checkpointer ins...
Checkpoint * getPrev() const noexcept
Returns the previous checkpoint. If this checkpoint is a snapshot, it has no previous checkpoint.
const std::vector< Checkpoint * > & getNexts() const noexcept
Returns next checkpoint following *this. May be an empty vector if there are no later checkpoints fol...
Checkpointer interface. Defines an ID-based checkpointing API for tree of related checkpoints which c...
const std::vector< TreeNode * > & getRoots() const noexcept
Returns the root(s) associated with this checkpointer.
Checkpoint::chkpt_id_t chkpt_id_t
tick_t Tick type to which checkpoints will refer
const std::vector< ArchData * > & getArchDatas() const
Returns ArchDatas enumerated by this Checkpointer for iteration when saving or loading checkpoint dat...
void setCurrent_(CheckpointBase *current)
Sets the current checkpoint pointer.
Scheduler *const sched_
Scheduler whose tick count will be set and read. Cannnot be updated after first checkpoint without ba...
CheckpointBase * getHead_() noexcept
Non-const variant of getHead_.
const CheckpointBase * getHead() const noexcept
Returns the head checkpoint which is equivalent to the earliest checkpoint taken.
void setHead_(CheckpointBase *head)
Sets the head checkpointer pointer to head.
chkpt_id_t getCurrentID() const
Returns the current checkpoint ID. This is mainly a debugging utility as the current ID changes when ...
Checkpoint::tick_t tick_t
tick_t Tick type to which checkpoints will refer
tick_t getCurrentTick() const
Gets the tick number of the current checkpoint (see getCurrentID). This is the tick number of the lat...
chkpt_id_t getHeadID() const noexcept
Returns the checkpoint ID of the head checkpoint (if it exists) which is equivalent to the earliest c...
CheckpointBase * getCurrent_() const noexcept
Gets the current checkpointer pointer. Returns nullptr if there is no current checkpoint object.
Single delta checkpoint object containing all simulator state which changed since some previous Delta...
chkpt_id_t getDeletedID() const noexcept
Return the ID had by this checkpoint before it was deleted If this checkpoint has not been flagged fo...
bool isSnapshot() const noexcept
Is this checkpoint a snapshot (contains ALL simulator state)
bool isFlaggedDeleted() const noexcept
Indicates whether this checkpoint has been flagged deleted.
virtual void load(const std::vector< ArchData * > &dats) override
Attempts to restore this checkpoint including any previous deltas (dependencies).
bool canDelete() const noexcept
Can this checkpoint be deleted Cannot be deleted if:
void traceValue(std::ostream &o, const std::vector< ArchData * > &dats, const ArchData *container, uint32_t offset, uint32_t size)
Implement trace of a value across the restore chain as described in Checkpointer::traceValue.
void flagDeleted()
Allows this checkpoint to be deleted if it is no longer a previous delta of some other delta (i....
Implements quick checkpointing through delta-checkpoint trees which store state-deltas in a compact f...
std::vector< chkpt_id_t > getNextIDs(chkpt_id_t id) override final
Returns IDs of the checkpoints immediately following the given checkpoint.
const checkpoint_type * findCheckpoint(chkpt_id_t id) noexcept
Finds a checkpoint by its ID.
FastCheckpointer(TreeNode &root, Scheduler *sched=nullptr)
FastCheckpointer Constructor.
void deleteCheckpoint(chkpt_id_t id) override
Deletes a checkpoint by ID.
uint64_t getTotalMemoryUse() const noexcept override
Computes and returns the memory usage by this checkpointer at this moment including any framework ove...
void setSnapshotThreshold(uint32_t thresh) noexcept
Sets the snapshot threshold.
uint32_t getNumCheckpoints() const noexcept override
Gets the current number of checkpoints having valid IDs.
std::string stringize() const override
Returns a string describing this object.
void cleanupChain_(checkpoint_type *d)
Delete given checkpoint and all contiguous previous checkpoints which can be deleted (See checkpoint_...
std::deque< chkpt_id_t > getCheckpointChain(chkpt_id_t id) override
Debugging utility which gets a deque of checkpoints representing a chain starting at the checkpoint h...
checkpoint_type * findCheckpoint_(chkpt_id_t id) noexcept
Attempts to find a checkpoint within this checkpointer by ID.
uint32_t getSnapshotThreshold() const noexcept
Returns the next-shapshot threshold.
checkpoint_type * findLatestCheckpointAtOrBefore(tick_t tick, chkpt_id_t from)
Finds the latest checkpoint at or before the given tick starting at the from checkpoint and working b...
uint64_t getContentMemoryUse() const noexcept override
Computes and returns the memory usage by this checkpointer at this moment purely for the checkpoint s...
checkpoint_ptrs squashCurrentBranch_(bool force_new_head_chkpt=false)
Squash the current branch and discard all those checkpoints that do not exist on the current branch....
std::vector< chkpt_id_t > getCheckpoints() override
Gets all checkpoint IDs available on any timeline sorted by tick (or equivalently checkpoint ID).
void dumpAnnotatedData(std::ostream &o) override
Dumps this checkpointer's data to an ostream with annotations between each ArchData and a newline fol...
bool hasCheckpoint(chkpt_id_t id) noexcept override
Tests whether this checkpoint manager has a checkpoint with the given id.
const checkpoint_type * findCheckpoint_(chkpt_id_t id) const noexcept
const variant of findCheckpoint_
void squashCurrentBranch(DiskT &disk, bool force_new_head_chkpt=false)
When satisfied with the outstanding/uncommitted checkpoints, call this method to commit them to the D...
FastCheckpointer(const std::vector< sparta::TreeNode * > &roots, Scheduler *sched=nullptr)
FastCheckpointer Constructor.
uint32_t getNumDeltas() const noexcept
Gets the current number of delta checkpoints with valid IDs.
void loadCheckpoint(chkpt_id_t id) override
Loads state from a specific checkpoint by ID.
std::vector< chkpt_id_t > getCheckpointsAt(tick_t t) override
Gets all checkpoints taken at tick t on any timeline.
uint32_t getNumSnapshots() const noexcept
Gets the current number of snapshots with valid IDs.
uint32_t getNumDeadCheckpoints() const noexcept
Gets the curent number of checkpoints (delta or snapshot) withOUT valid IDs.
bool recursForwardFindAlive_(checkpoint_type *d) const
Look forward to see if any future checkpoints depend on d.
void dumpList(std::ostream &o) override
Dumps this checkpointer's flat list of checkpoints to an ostream with a newline following each checkp...
~FastCheckpointer()
Destructor.
void dumpData(std::ostream &o) override
Dumps this checkpointer's data to an ostream with a newline following each checkpoint.
void dumpCheckpointNode_(const chkpt_id_t id, std::ostream &o) override
Implements Checkpointer::dumpCheckpointNode_.
void traceValue(std::ostream &o, chkpt_id_t id, const ArchData *container, uint32_t offset, uint32_t size) override
Forwards debug/trace info onto checkpoint by ID.