The Sparta Modeling Framework
Loading...
Searching...
No Matches
FastCheckpointer.hpp
1// <FastCheckpointer> -*- C++ -*-
2
3#pragma once
4
5#include <iostream>
6#include <sstream>
7#include <stack>
8#include <queue>
9#include <unordered_set>
10
12#include "sparta/functional/ArchData.hpp"
15
16#include "sparta/serialization/checkpoint/DeltaCheckpoint.hpp"
17
19#ifndef DEFAULT_SNAPSHOT_THRESH
20#define DEFAULT_SNAPSHOT_THRESH 20
21#endif
22
23namespace sparta::serialization::checkpoint
24{
67 {
68 public:
69
71 using checkpoint_ptr = std::unique_ptr<checkpoint_type>;
72 using checkpoint_ptrs = std::vector<checkpoint_ptr>;
73
77
92 FastCheckpointer(TreeNode& root, Scheduler* sched=nullptr) :
93 Checkpointer(root, sched),
94 snap_thresh_(DEFAULT_SNAPSHOT_THRESH),
95 next_chkpt_id_(checkpoint_type::MIN_CHECKPOINT),
96 num_alive_checkpoints_(0),
97 num_alive_snapshots_(0),
98 num_dead_checkpoints_(0)
99 { }
100
115 FastCheckpointer(const std::vector<sparta::TreeNode*>& roots, Scheduler* sched=nullptr) :
116 Checkpointer(roots, sched),
117 snap_thresh_(DEFAULT_SNAPSHOT_THRESH),
118 next_chkpt_id_(checkpoint_type::MIN_CHECKPOINT),
119 num_alive_checkpoints_(0),
120 num_alive_snapshots_(0),
121 num_dead_checkpoints_(0)
122 { }
123
130 // Reverse iterate and flag all as free
131 for(auto itr = chkpts_.rbegin(); itr != chkpts_.rend(); ++itr){
132 checkpoint_type* d = static_cast<checkpoint_type*>(itr->second.get());
133 if(!d->isFlaggedDeleted()){
134 d->flagDeleted();
135 }
136 }
137 }
138
141
145
158 uint32_t getSnapshotThreshold() const noexcept { return snap_thresh_; }
159
164 void setSnapshotThreshold(uint32_t thresh) noexcept {
165 snap_thresh_ = thresh;
166 }
167
174 uint64_t getTotalMemoryUse() const noexcept override {
175 uint64_t mem = 0;
176 for(auto& cp : chkpts_){
177 mem += cp.second->getTotalMemoryUse();
178 }
179 return mem;
180 }
181
186 uint64_t getContentMemoryUse() const noexcept override {
187 uint64_t mem = 0;
188 for(auto& cp : chkpts_){
189 mem += cp.second->getContentMemoryUse();
190 }
191 return mem;
192 }
193
196
200
220 void deleteCheckpoint(chkpt_id_t id) override {
221
222 // Flag checkpoint as deleted
224 if(!d){
225 throw CheckpointError("Could not delete checkpoint ID=")
226 << id << " because no checkpoint by this ID was found";
227 }
228
229 // Allow deletion and change ID to UNIDENTIFIED_CHECKPOINT.
230 // This is still part of a chain though until there are no
231 // dependencies on it.
232 if(!d->isFlaggedDeleted()){
233 num_dead_checkpoints_++;
234 if(d->isSnapshot()){
235 num_alive_snapshots_--;
236 }
237 num_alive_checkpoints_--;
238 d->flagDeleted();
239 }
240
241 // Delete this and all contiguous previous checkpoint which were
242 // flagged deleted if possible. Stop if current_ is encountered
243 cleanupChain_(d);
244 }
245
259 void loadCheckpoint(chkpt_id_t id) override {
261 if(!d){
262 throw CheckpointError("Could not load checkpoint ID=")
263 << id << " because no checkpoint by this ID was found";
264 }
265
266 d->load(getArchDatas());
267
268 // Move current to another checkpoint. Anything between head and the
269 // old current_ is fair game for removal if allowed
270 checkpoint_type* rmv = static_cast<checkpoint_type*>(getCurrent_());
271 setCurrent_(d);
272
273 // Restore scheduler tick number
274 if(sched_){
276 }
277
278 // Remove all checkpoints which can be. Stop if the new current_ is
279 // encountered again.
280 // Note that is is OK if current_ was moved to a later position in
281 // the chain. No important checkpoints will be removed. The
282 // important thing is never to remove current_.
283 cleanupChain_(rmv);
284 }
285
294 std::vector<chkpt_id_t> getCheckpointsAt(tick_t t) override {
295 std::vector<chkpt_id_t> results;
296 for(auto& p : chkpts_){
297 const Checkpoint* cp = p.second.get();
298 const checkpoint_type* dcp = static_cast<const checkpoint_type*>(cp);
299 if(cp->getTick() == t && !dcp->isFlaggedDeleted()){
300 results.push_back(cp->getID());
301 }
302 }
303 return results;
304 }
305
314 std::vector<chkpt_id_t> getCheckpoints() override {
315 std::vector<chkpt_id_t> results;
316 for(auto& p : chkpts_){
317 const Checkpoint* cp = p.second.get();
318 const checkpoint_type* dcp = static_cast<const checkpoint_type*>(cp);
319 if(!dcp->isFlaggedDeleted()){
320 results.push_back(cp->getID());
321 }
322 }
323 return results;
324 }
325
329 uint32_t getNumCheckpoints() const noexcept override {
330 return num_alive_checkpoints_;
331 }
332
336 uint32_t getNumSnapshots() const noexcept {
337 return num_alive_snapshots_;
338 }
339
343 uint32_t getNumDeltas() const noexcept {
345 }
346
351 uint32_t getNumDeadCheckpoints() const noexcept {
352 return num_dead_checkpoints_;
353 }
354
370 std::deque<chkpt_id_t> getCheckpointChain(chkpt_id_t id) override {
371 std::deque<chkpt_id_t> results;
372 if(!getHead()){
373 return results;
374 }
375 const checkpoint_type* d = findCheckpoint_(id);
376 if(!d){
377 throw CheckpointError("There is no checkpoint with ID ") << id;
378 }
379 while(d){
380 results.push_back(d->getID());
381 d = static_cast<checkpoint_type*>(d->getPrev());
382 }
383 return results;
384 }
385
404 chkpt_id_t from) {
406 if(!d){
407 throw CheckpointError("There is no checkpoint with ID ") << from;
408 }
409
410 // Search backward
411 do{
412 if(d->getTick() <= tick){
413 break;
414 }
415 d = static_cast<checkpoint_type*>(d->getPrev());
416 }while(d);
417
418 return d;
419 }
420
428 auto it = chkpts_.find(id);
429 if (it != chkpts_.end()) {
430 return static_cast<checkpoint_type*>(it->second.get());
431 }
432 return nullptr;
433 }
434
442 bool hasCheckpoint(chkpt_id_t id) noexcept override {
443 return chkpts_.find(id) != chkpts_.end();
444 }
445
449 std::vector<chkpt_id_t> getNextIDs(chkpt_id_t id) override final {
450 std::vector<chkpt_id_t> next_ids;
451 if (const auto chkpt = findCheckpoint_(id)) {
452 for (const auto next : chkpt->getNexts()) {
453 const auto dcp = static_cast<checkpoint_type*>(next);
454 if (!dcp->isFlaggedDeleted()) {
455 next_ids.push_back(next->getID());
456 }
457 }
458 }
459 return next_ids;
460 }
461
464
468
472 std::string stringize() const override {
473 std::stringstream ss;
474 ss << "<FastCheckpointer on ";
475 for (size_t i = 0; i < getRoots().size(); ++i) {
476 TreeNode* root = getRoots()[i];
477 if (i != 0) {
478 ss << ", ";
479 }
480 ss << root->getLocation();
481 }
482 ss << '>';
483 return ss.str();
484 }
485
491 void dumpList(std::ostream& o) override {
492 for(auto& cp : chkpts_){
493 o << cp.second->stringize() << std::endl;
494 }
495 }
496
502 void dumpData(std::ostream& o) override {
503 for(auto& cp : chkpts_){
504 cp.second->dumpData(o);
505 o << std::endl;
506 }
507 }
508
515 void dumpAnnotatedData(std::ostream& o) override {
516 for(auto& cp : chkpts_){
517 o << cp.second->stringize() << std::endl;
518 cp.second->dumpData(o);
519 o << std::endl;
520 }
521 }
522
526 void traceValue(std::ostream& o, chkpt_id_t id, const ArchData* container, uint32_t offset, uint32_t size) override {
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;
531 if(!dcp){
532 o << "trace: Checkpoint " << id << " not found" << std::endl;
533 }else{
534 dcp->traceValue(o, getArchDatas(), container, offset, size);
535 }
536 }
537
552 template <typename DiskT>
553 void squashCurrentBranch(DiskT& disk, bool force_new_head_chkpt = false) {
554 auto disk_checkpoints = squashCurrentBranch_(force_new_head_chkpt);
555 if (!disk_checkpoints.empty()) {
556 disk.saveCheckpoints(std::move(disk_checkpoints));
557 }
558 }
559
562
563 protected:
564
572 checkpoint_ptrs squashCurrentBranch_(bool force_new_head_chkpt = false) {
573 if (!getCurrent_()) {
574 return {};
575 }
576
577 checkpoint_ptrs to_save;
578
579 // "Force new head checkpoint" means that we should release every
580 // checkpoint from the current checkpoint back to the head checkpoint,
581 // delete all remaining checkpoints on other branches, and retake the
582 // head checkpoint.
583 if (force_new_head_chkpt) {
584 auto current_id = getCurrentID();
585 auto chkpt_chain = getCheckpointChain(current_id);
586
587 // Checkpoint chains are returned from "right to left", i.e. the
588 // first id is the current checkpoint, and the last is the head
589 // checkpoint. Reverse this list so that we serialize the checkpoints
590 // to disk in the order they were created.
591 std::reverse(chkpt_chain.begin(), chkpt_chain.end());
592
593 for (auto id : chkpt_chain) {
595 auto chkpt = std::move(chkpts_[id]);
596
597 sparta_assert(num_alive_checkpoints_-- > 0);
598 if (chkpt->isSnapshot()) {
599 sparta_assert(num_alive_snapshots_-- > 0);
600 }
601
602 to_save.emplace_back(std::move(chkpt));
603 chkpts_.erase(id);
604 }
605
606 for (auto& [id, chkpt] : chkpts_) {
607 chkpt->flagDeleted();
608 }
609 chkpts_.clear();
610
611 createHead_();
612 }
613
614 // If we are not forcing a new head checkpoint, then we can only
615 // remove checkpoints along the current chain if there exists more
616 // than one snapshot. The most recent of these will become the new
617 // head checkpoint. Say we have these checkpoints:
618 //
619 // S1 -> 2 -> 3 -> S2 -> 4 -> 5
620 // |
621 // | -> 6 -> S3 -> 7
622 // |
623 // 8 -> 9
624 //
625 // If the current checkpoint is id 7, then the checkpoint chain is
626 // S1 -> 2 -> 6 -> S3 -> 7
627 //
628 // And the restore chain is:
629 // S3 -> 7
630 //
631 // Since the checkpoint chain (back to head) is different than
632 // the restore chain (back to the last snapshot), that means
633 // that we have at least two snapshots, and can therefore return
634 // the chain S1 -> 2 -> 6 for writing to disk, while retaining
635 // the chain S3 -> 7 and deleting everything else (uncommitted
636 // branches). Then set the new head checkpoint to S3.
637 //
638 // On the other hand, if our checkpoints are like this:
639 //
640 // S1 -> 2 -> 3
641 //
642 // Then the checkpoint chain and restore chain are the same, and
643 // we only have one snapshot. We therefore can only remove checkpoints
644 // that are NOT along the checkpoint/restore chains, and there are
645 // no checkpoints returned to the caller for saving to disk, and
646 // the head checkpoint stays the same at S1.
647 else {
648 auto current_id = getCurrentID();
649 auto chkpt_chain = getCheckpointChain(current_id);
650 auto restore_chain = static_cast<checkpoint_type*>(getCurrent_())->getRestoreChain();
651
652 // We can speed up the comparison by just checking the chain lengths.
653 // If they are the same then we can only remove uncommitted branches.
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);
661 }
662 }
663
664 for (auto id : to_delete) {
665 auto chkpt = std::move(chkpts_[id]);
666
667 sparta_assert(num_alive_checkpoints_-- > 0);
668 if (chkpt->isSnapshot()) {
669 sparta_assert(num_alive_snapshots_-- > 0);
670 }
671
672 chkpts_.erase(id);
673 }
674
675 // Sanity check
676 sparta_assert(chkpts_.find(getHeadID()) != chkpts_.end());
677 sparta_assert(static_cast<const checkpoint_type*>(getHead())->isSnapshot());
678 }
679
680 // If the chains are different, then we have at least two snapshots
681 // and can save all but the latest checkpoint window (snapshot plus
682 // deltas).
683 else {
684 // Say the checkpoint chain is this (recall its first checkpoint
685 // is the current/newest, i.e. in backwards order):
686 //
687 // 7 -> S3 -> 6 -> 2 -> S1
688 //
689 // And the restore chain is this (recall that its first checkpoint
690 // is the most recent snapshot leading up to the current checkpoint):
691 //
692 // S3 -> 7
693 //
694 // The algorithm goes like this:
695 // 1) Reverse the checkpoint chain into e.g.
696 // S1 -> 2 -> 6 -> S3 -> 7
697 // 2) Loop over the checkpoint chain, and any id not at
698 // the restore chain (stack) "top" should be added
699 // to the list of checkpoints we will save to disk.
700 // If the id is the same as the restore chain "top",
701 // then store the new head checkpoint if it is a full
702 // snapshot and pop() the stack.
703 // 3) Delete all checkpoints that are neither saved to disk
704 // or left in the checkpointer (uncommitted branches).
705 std::reverse(chkpt_chain.begin(), chkpt_chain.end());
706 std::unordered_set<chkpt_id_t> to_keep;
707
708 for (auto id : chkpt_chain) {
709 if (id != restore_chain.top()->getID()) {
710 auto chkpt = std::move(chkpts_[id]);
711
712 sparta_assert(num_alive_checkpoints_-- > 0);
713 if (chkpt->isSnapshot()) {
714 sparta_assert(num_alive_snapshots_-- > 0);
715 }
716
717 to_save.emplace_back(std::move(chkpt));
718 chkpts_.erase(id);
719 } else {
720 if (restore_chain.top()->isSnapshot()) {
721 setHead_(restore_chain.top());
722 }
723 to_keep.insert(restore_chain.top()->getID());
724 restore_chain.pop();
725
726 if (restore_chain.empty()) {
727 break;
728 }
729 }
730 }
731
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);
736 }
737 }
738
739 for (auto id : to_delete) {
740 auto & chkpt = chkpts_[id];
741 chkpt->flagDeleted();
742
743 sparta_assert(num_alive_checkpoints_-- > 0);
744 if (chkpt->isSnapshot()) {
745 sparta_assert(num_alive_snapshots_-- > 0);
746 }
747 }
748
749 for (auto id : to_delete) {
750 chkpts_.erase(id);
751 }
752 }
753 }
754
755 sparta_assert(getHead() != nullptr);
757
758 return to_save;
759 }
760
774
775 // In order to truly delete any checkpoints, we must traverse back
776 // to the previous snapshot (or the head) and forward to the another
777 // snapshot or the end of the chain.
778 // ONLY if both of those points can be reached without encountering
779 // a living checkpoint or the current checkpoint (forward
780 // only) can the whole chain (including the leading shapshot) be
781 // deleted.
782
784
785 if(d == getHead()){
786 // Cannot delete head of checkpoint tree
787 return;
788 }
789
790 // Walk forward to another snapshot or current
791 const bool needed_later = (getCurrent_() == d) || recursForwardFindAlive_(d);
792 if(needed_later) {
793 // Cannot delete because a later living checkpoint (or current) depends on this
794 if(d->isSnapshot()){
795 // This snapshot is needed later. Move to previous delta and work from there
796 d = static_cast<checkpoint_type*>(d->getPrev());
797 }else{
798 return; // This delta is needed. Therefore all preceeding deltas are needed
799 }
800 }
801
802 // Delete backward until current, head, or a non-flagged-deleted checkpoint is hit.
803 // It is possible to fracture the checkpoint tree by deleting a segment
804 // between two snapshots, so prev can end up with nothing leading up to it
805 while(d && d != getHead() && d->isFlaggedDeleted()){
806
807 // If the checkpoint to delete is the current checkpoint, then
808 // We cannot just set current to the previous checkpoint because
809 // we may have run forward and storing a checkpoint in the
810 // future would depend on the checkpoint we are about to delete.
811 // This could be fixed by requiring the next checkpoint to be a
812 // spapshot. Instead, point to the flagged-deleted checkpoint
813 // and do not delete
814 if(getCurrent_() == d){
815 return;
816 }
817
818 checkpoint_type* prev = static_cast<checkpoint_type*>(d->getPrev());
819
820 // If nothing later in the chain (tree) depends on d's data, it can be deleted.
821 // This also patches the checkpoint tree around the deleted checkpoint
823 if(d->canDelete()) {
824 // Get checkpoint id regardless of whether alive or dead
825 chkpt_id_t id = d->getID();
826 if (d->isFlaggedDeleted()) {
827 id = d->getDeletedID();
828 }
829
830 num_dead_checkpoints_--;
831
832 // Erase element in the map
833 auto itr = chkpts_.find(id);
834 sparta_assert(itr != chkpts_.end());
835 chkpts_.erase(itr);
836 }
837
838 d = prev; // Continue until head is reached
839 }
840 }
841
852 {
853 const std::vector<Checkpoint*> & nexts = d->getNexts();
854 for(const auto & chkpt : nexts)
855 {
856 checkpoint_type* dc = static_cast<checkpoint_type*>(chkpt);
857 // Only check descendants for snapshot-ness
858 if(dc->isSnapshot()){
859 // Found a live snapshot that ends this branch. d is not needed
860 // after this
861 return false;
862 }
863 if(dc == getCurrent_()){
864 // Found current in this search chain
865 return true;
866 }
867 if(dc->isFlaggedDeleted() == false){
868 // Encountered a checkpoint later in the chain that still
869 // depends on this.
870 return true;
871 }
872
873 // Continue the search recursively
875 return true;
876 }
877 }
878
879 // Found nothing alive.
880 return false;
881 }
882
891 auto itr = chkpts_.find(id);
892 if (itr != chkpts_.end()) {
893 return static_cast<checkpoint_type*>(itr->second.get());
894 }
895 return nullptr;
896 }
897
901 const checkpoint_type* findCheckpoint_(chkpt_id_t id) const noexcept {
902 auto itr = chkpts_.find(id);
903 if (itr != chkpts_.end()) {
904 return static_cast<checkpoint_type*>(itr->second.get());
905 }
906 return nullptr;
907 }
908
912 void dumpCheckpointNode_(const chkpt_id_t id, std::ostream& o) override {
913 static std::string SNAPSHOT_NOTICE = "(s)";
914 auto cp = findCheckpoint_(id);
915
916 // Draw data for this checkpoint
917 if(cp->isFlaggedDeleted()){
918 o << cp->getDeletedRepr();
919 }else{
920 o << cp->getID();
921 }
922 // Show that this is a snapshot
923 if(cp->isSnapshot()){
924 o << ' ' << SNAPSHOT_NOTICE;
925 }
926 }
927
928 private:
929
933 void createHead_() override {
934 tick_t tick = 0;
935 if(sched_){
936 tick = sched_->getCurrentTick();
937 }
938
939 for (auto root : getRoots()) {
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 ";
943 if(sched_){
944 exc << tick;
945 }else{
946 exc << "<no scheduler>";
947 }
948 throw exc;
949 }
950 }
951
952 checkpoint_type* dcp = new checkpoint_type(getArchDatas(), next_chkpt_id_++, tick, nullptr, true);
953 chkpts_[dcp->getID()].reset(dcp);
954 setHead_(dcp);
955 num_alive_checkpoints_++;
956 num_alive_snapshots_++;
957 setCurrent_(dcp);
958 }
959
960 chkpt_id_t createCheckpoint_(bool force_snapshot=false) override {
961 bool is_snapshot;
962 checkpoint_type* prev;
963
964 if(next_chkpt_id_ == checkpoint_type::UNIDENTIFIED_CHECKPOINT){
965 throw CheckpointError("Exhausted all ")
966 << checkpoint_type::UNIDENTIFIED_CHECKPOINT << " possible checkpoint IDs. "
967 << "This is likely a gross misuse of checkpointing";
968 }
969
970 // Caller guarantees a head
971 sparta_assert(getHead() != nullptr);
972
973 tick_t tick;
974 if(sched_){
975 tick = sched_->getCurrentTick();
976 }else{
977 tick = 0;
978 }
979
980 if(sched_ && (tick < getHead()->getTick())){
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.";
986 }
987
988 if(nullptr == getCurrent_()){
989 // Creating a delta from the head
990 prev = static_cast<checkpoint_type*>(getHead_());
991 is_snapshot = false;
992 }else{
993 if(sched_ && (tick < getCurrent_()->getTick())){
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 "
998 << "loaded";
999 }
1000
1001 // Find latest checkpoint <= tick
1002
1003 prev = static_cast<checkpoint_type*>(getCurrent_());
1004 is_snapshot = prev->getDistanceToPrevSnapshot() >= getSnapshotThreshold();
1005 }
1006
1007 checkpoint_type* dcp = new checkpoint_type(getArchDatas(), // Created during createHead
1008 next_chkpt_id_++,
1009 tick,
1010 prev,
1011 force_snapshot || is_snapshot);
1012 chkpts_[dcp->getID()].reset(dcp);
1013 num_alive_checkpoints_++;
1014 num_alive_snapshots_ += (dcp->isSnapshot() == true);
1015 setCurrent_(dcp);
1016
1017 if (dcp->isSnapshot()){
1018 // Clean up starting with this snapshot and moving back.
1019 // May have an opportunity to free older deltas right now
1020 // (instead of upon next deletion)
1021 cleanupChain_(dcp);
1022 }
1023
1024 return dcp->getID();
1025 }
1026
1035 std::map<chkpt_id_t, checkpoint_ptr> chkpts_;
1036
1041 uint32_t snap_thresh_;
1042
1046 chkpt_id_t next_chkpt_id_;
1047
1052 uint32_t num_alive_checkpoints_;
1053
1060 uint32_t num_alive_snapshots_;
1061
1066 uint32_t num_dead_checkpoints_;
1067 };
1068
1069} // namespace sparta::serialization::checkpoint
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...
Definition ArchData.hpp:39
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.
Definition TreeNode.hpp:205
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...
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.