The Sparta Modeling Framework
Loading...
Searching...
No Matches
Checkpointer.hpp
1// <Checkpointer> -*- C++ -*-
2
3#pragma once
4
5#include <iostream>
6#include <sstream>
7#include <stack>
8#include <queue>
9#include <list>
10#include <map>
11#include <string>
12#include <memory>
13
15#include "sparta/functional/ArchData.hpp"
18#include "sparta/simulation/TreeNodePrivateAttorney.hpp"
19#include "sparta/serialization/checkpoint/Checkpoint.hpp"
20
21namespace sparta::serialization::checkpoint
22{
57 {
58 public:
59
63
66
69
72
76
88 Checkpointer(TreeNode& root, sparta::Scheduler* sched=nullptr) :
89 sched_(sched),
90 root_(root),
91 head_(nullptr),
92 current_(nullptr),
93 total_chkpts_created_(0)
94 { }
95
99 virtual ~Checkpointer() {
100 }
101
104
108
112 const TreeNode& getRoot() const noexcept { return root_; }
113
117 TreeNode& getRoot() noexcept { return root_; }
118
122 const Scheduler* getScheduler() const noexcept { return sched_; }
123
130 uint64_t getTotalMemoryUse() const noexcept {
131 uint64_t mem = 0;
132 for(auto& cp : chkpts_){
133 mem += cp.second->getTotalMemoryUse();
134 }
135 return mem;
136 }
137
142 uint64_t getContentMemoryUse() const noexcept {
143 uint64_t mem = 0;
144 for(auto& cp : chkpts_){
145 mem += cp.second->getContentMemoryUse();
146 }
147 return mem;
148 }
149
155 uint64_t getTotalCheckpointsCreated() const noexcept {
156 return total_chkpts_created_;
157 }
158
161
165
187 void createHead() {
188 tick_t tick = 0;
189 if(sched_){
190 tick = sched_->getCurrentTick();
191 }
192 if(head_){
193 CheckpointError exc("Cannot create head at ");
194 if(sched_){
195 exc << tick;
196 }else{
197 exc << "<no scheduler>";
198 }
199 exc << " because a head already exists in this checkpointer";
200 throw exc;
201 }
202 if(root_.isFinalized() == false){
203 CheckpointError exc("Cannot create a checkpoint until the tree is finalized. Attempting to checkpoint from node ");
204 exc << root_.getLocation() << " at tick ";
205 if(sched_){
206 exc << tick;
207 }else{
208 exc << "<no scheduler>";
209 }
210 throw exc;
211 }
212
213 enumerateArchDatas_(); // Determines which ArchDatas are required and populates adatas_
214
215 createHead_();
216
217 sparta_assert(head_ != nullptr, "A call to createHead_ must create a head and invoke setHead_ or throw an exception");
218
219 total_chkpts_created_++;
220 }
221
249 chkpt_id_t createCheckpoint(bool force_snapshot=false) {
250 if(!head_){
251 createHead();
252 }
253
254 chkpt_id_t id = createCheckpoint_(force_snapshot);
255 total_chkpts_created_++;
256 return id;
257 }
258
278 virtual void deleteCheckpoint(chkpt_id_t id) = 0;
279
292 virtual void loadCheckpoint(chkpt_id_t id) = 0;
293
313 if(head_){
314 current_ = head_;
315 }
316 }
317
326 virtual std::vector<chkpt_id_t> getCheckpointsAt(tick_t t) const = 0;
327
336 virtual std::vector<chkpt_id_t> getCheckpoints() const = 0;
337
345 virtual uint32_t getNumCheckpoints() const noexcept = 0;
346
362 virtual std::deque<chkpt_id_t> getCheckpointChain(chkpt_id_t id) const = 0;
363
382 chkpt_id_t from) = 0;
383
391 return findCheckpoint_(id);
392 }
393
401 virtual bool hasCheckpoint(chkpt_id_t id) const noexcept {
402 return findCheckpoint_(id) != nullptr;
403 }
404
415 const Checkpoint* getHead() const noexcept {
416 return head_;
417 }
418
428 chkpt_id_t getHeadID() const noexcept {
429 if(!head_){
431 }
432 return head_->getID();
433 }
434
460 if(current_){
461 return current_->getID();
462 }
463 sparta_assert(!head_); // If there was no current, it can only be because there is no head yet
465 }
466
480 if(current_){
481 return current_->getTick();
482 }
483 sparta_assert(!head_);
484 return 0;
485 }
486
489
493
497 virtual std::string stringize() const {
498 std::stringstream ss;
499 ss << "<Checkpointer on " << root_.getLocation() << '>';
500 return ss.str();
501 }
502
508 void dumpList(std::ostream& o) const {
509 for(auto& cp : chkpts_){
510 o << cp.second->stringize() << std::endl;
511 }
512 }
513
519 void dumpData(std::ostream& o) const {
520 for(auto& cp : chkpts_){
521 cp.second->dumpData(o);
522 o << std::endl;
523 }
524 }
525
532 void dumpAnnotatedData(std::ostream& o) const {
533 for(auto& cp : chkpts_){
534 o << cp.second->stringize() << std::endl;
535 cp.second->dumpData(o);
536 o << std::endl;
537 }
538 }
539
554 virtual void traceValue(std::ostream& o, chkpt_id_t id, const ArchData* container, uint32_t offset, uint32_t size) = 0;
555
562 void dumpTree(std::ostream& o) const {
563 std::deque<uint32_t> c;
564 dumpBranch(o, head_, 0, 0, c);
565 o << '\n';
566 }
567
580 void dumpBranch(std::ostream& o,
581 const Checkpoint* chkpt,
582 uint32_t indent,
583 uint32_t pos,
584 std::deque<uint32_t>& continues) const {
586 static const std::string SEP_STR = "-> "; // Normal checkpoint chain
587 static const std::string CONT_SEP_STR = "`> "; // Checkpoint branch from higher line
588 assert(SEP_STR.size() == CONT_SEP_STR.size()); // Must be the same length so the layout looks OK
589
590 // Walk through indent and draw continuations
591 uint32_t i = pos;
592 std::remove_reference<decltype(continues)>::type::const_iterator next_cont = continues.begin();
593 for(; i < indent; ++i){
594 if(next_cont != continues.end() && i == *next_cont){
595 o << '|';
596 while(next_cont != continues.end() && *next_cont == i){ // Skip duplicates and move on to next
597 ++next_cont;
598 }
599 }else{
600 o << ' ';
601 }
602 }
603
604 auto nexts = chkpt->getNexts();
605 std::stringstream ss;
606
607 // Draw separator between prev checkpoint and this
608 if(next_cont != continues.end() && *next_cont == indent && indent != pos){
609 ss << CONT_SEP_STR;
610 }else{
611 ss << SEP_STR;
612 }
613
614 // Draw box around object if it is current
615 if(current_ == chkpt){
616 ss << "[ ";
617 }
618
619 dumpCheckpointNode_(chkpt, ss);
620 ss << ' ';
621
622 if(current_ == chkpt){
623 ss << ']';
624 }
625
626 o << ss.str();
627 i += ss.str().size();
628
629 // Draw all next checkpoints recursively
630 if(nexts.size() > 0){
631 if(nexts.size() > 1){
632 continues.push_back(i); // Push continues first
633 }
634 dumpBranch(o, nexts.front(), i, i, continues); // No indent, no newline
635 decltype(nexts)::const_iterator itr = nexts.begin() + 1;
636 if(itr == nexts.end()){
637 //continues.pop_back();
638 }else{
639 while(itr < nexts.end()){
640 if(itr+1 == nexts.end()){
641 continues.pop_back(); // Do not show this continuation here
642 }
643 o << '\n';
644 dumpBranch(o, *itr, i, 0, continues); // Indent
645 ++itr;
646 }
647 }
648 }
649 }
650
653
654 protected:
655
663 virtual Checkpoint* findCheckpoint_(chkpt_id_t id) noexcept = 0;
664
668 virtual const Checkpoint* findCheckpoint_(chkpt_id_t id) const noexcept = 0;
669
680 virtual void createHead_() = 0;
681
690 virtual chkpt_id_t createCheckpoint_(bool force_snapshot=false) = 0;
691
692 virtual void dumpCheckpointNode_(const Checkpoint* chkpt, std::ostream& o) const {
693 o << chkpt->getID();
694 }
695
700 const std::vector<ArchData*>& getArchDatas() const {
701 return adatas_;
702 }
703
707 Checkpoint* getHead_() noexcept {
708 return head_;
709 }
710
714 const Checkpoint* getHead_() const noexcept {
715 return head_;
716 }
717
725 void setHead_(Checkpoint* head) {
726 sparta_assert(head != nullptr, "head argument in setHead_ cannot be nullptr");
727 sparta_assert(head_ == nullptr, "Cannot setHead_ again on a Checkpointer once heas is already set");
728 head_ = head;
729 }
730
735 Checkpoint* getCurrent_() const noexcept {
736 return current_;
737 }
738
745 void setCurrent_(Checkpoint* current) {
746 sparta_assert(current != nullptr,
747 "Can never setCurrent_ to nullptr except. A null current is a valid state at initialization only")
748 current_ = current;
749 }
750
759 std::map<chkpt_id_t, std::unique_ptr<Checkpoint>> chkpts_;
760
767
768 private:
769
775 void enumerateArchDatas_() {
776 sparta_assert(adatas_.size() == 0, "FastCheckpointer already has a vector of ArchDatas. Cannot re-enumerate");
777
778 adatas_.clear(); // Clear in case invoked again
779
780 // This is a helper for building the adatas_ vector while detecting
781 // dupicate ArchDatas.
782 // Maps an ArchData key to the TreeNode which pointed to it.
783 std::map<ArchData*,TreeNode*> adatas_helper;
784
785 // Recursively walk the tree and add all ArchDatas to adatas_
786 recursAddArchData_(&root_, adatas_helper);
787 }
788
796 void recursAddArchData_(TreeNode* n, std::map<ArchData*,TreeNode*>& adatas_helper) {
797 assert(n);
798 auto adatas = n->getAssociatedArchDatas();
799 for(ArchData* ad : adatas){
800 if(ad != nullptr){
801 auto itr = adatas_helper.find(ad);
802 if(itr != adatas_helper.end()){
803 throw CheckpointError("Found a second reference to ArchData ")
804 << ad << " in the tree: " << root_.stringize() << " . First reference found throgh "
805 << itr->second->getLocation() << " and second found through " << n->getLocation()
806 << " . An ArchData should be findable throug exactly 1 TreeNode";
807 }
808 adatas_.push_back(ad);
809 adatas_helper[ad] = n; // Add to helper map
810 }
811 }
812 for(TreeNode* child : TreeNodePrivateAttorney::getAllChildren(n)){
813 recursAddArchData_(child, adatas_helper);
814 }
815 }
816
817 TreeNode& root_;
818
823 Checkpoint* head_;
824
829 std::vector<ArchData*> adatas_;
830
834 Checkpoint* current_;
835
840 uint64_t total_chkpts_created_;
841 };
842
843} // namespace sparta::serialization::checkpoint
844
845
847inline std::ostream& operator<<(std::ostream& o, const sparta::serialization::checkpoint::Checkpointer& cpr){
848 o << cpr.stringize();
849 return o;
850}
851
853inline std::ostream& operator<<(std::ostream& o, const sparta::serialization::checkpoint::Checkpointer* cpr){
854 if(cpr == 0){
855 o << "null";
856 }else{
857 o << cpr->stringize();
858 }
859 return o;
860}
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.
std::vector< ArchData * > getAssociatedArchDatas()
Retrieves all ArchDatas associated with this TreeNode so that children can use it to allocate their d...
Contains a set of contiguous line of architectural data which can be referred to by any architected o...
Definition ArchData.hpp:39
virtual bool isFinalized() const
Is this node (and thus the entire tree above it) "finalized".
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.
Node in a composite tree representing a sparta Tree item.
Definition TreeNode.hpp:205
std::string getLocation() const override final
virtual std::string stringize(bool pretty=false) const
Create a string representation of this node.
Definition TreeNode.hpp:723
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...
const std::vector< Checkpoint * > & getNexts() const noexcept
Returns next checkpoint following *this. May be an empty vector if there are no later checkpoints fol...
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.
sparta::Scheduler::Tick tick_t
tick_t Tick type to which checkpoints will refer
uint64_t chkpt_id_t
tick_t Tick type to which checkpoints will refer
static const chkpt_id_t UNIDENTIFIED_CHECKPOINT
Indicates unidentified checkpoint (could mean 'invalid' or 'any') depending on context.
Checkpointer interface. Defines an ID-based checkpointing API for tree of related checkpoints which c...
virtual void traceValue(std::ostream &o, chkpt_id_t id, const ArchData *container, uint32_t offset, uint32_t size)=0
Debugging utility which dumps values in some bytes across a chain of checkpoints. The intent is to sh...
virtual Checkpoint * findLatestCheckpointAtOrBefore(tick_t tick, chkpt_id_t from)=0
Finds the latest checkpoint at or before the given tick starting at the from checkpoint and working b...
void createHead()
Creates a head without taking an identified checkpoint. Cannot already have a head.
virtual const Checkpoint * findCheckpoint_(chkpt_id_t id) const noexcept=0
const variant of findCheckpoint_
const std::vector< ArchData * > & getArchDatas() const
Returns ArchDatas enumerated by this Checkpointer for iteration when saving or loading checkpoint dat...
virtual Checkpoint * findCheckpoint_(chkpt_id_t id) noexcept=0
Attempts to find a checkpoint within this checkpointer by ID.
const Checkpoint * getHead_() const noexcept
Gets the head checkpoint. Returns nullptr if none created yet.
void dumpTree(std::ostream &o) const
Dumps this checkpointer's tree to an ostream with a line for each branch. Printout timescale is not r...
Scheduler *const sched_
Scheduler whose tick count will be set and read. Cannnot be updated after first checkpoint without ba...
void dumpList(std::ostream &o) const
Dumps this checkpointer's flat list of checkpoints to an ostream with a newline following each checkp...
const Scheduler * getScheduler() const noexcept
Returns the sheduler associated with this checkpointer.
const TreeNode & getRoot() const noexcept
Returns the root associated with this checkpointer.
chkpt_id_t createCheckpoint(bool force_snapshot=false)
Creates a checkpoint at the given scheduler's current tick with a new checkpoint ID some point after ...
Checkpointer(TreeNode &root, sparta::Scheduler *sched=nullptr)
Checkpointer Constructor.
virtual void loadCheckpoint(chkpt_id_t id)=0
Loads state from a specific checkpoint by ID.
void dumpData(std::ostream &o) const
Dumps this checkpointer's data to an ostream with a newline following each checkpoint.
uint64_t getTotalMemoryUse() const noexcept
Computes and returns the memory usage by this checkpointer at this moment including any framework ove...
void dumpAnnotatedData(std::ostream &o) const
Dumps this checkpointer's data to an ostream with annotations between each ArchData and a newline fol...
Checkpoint * getCurrent_() const noexcept
Gets the current checkpointer pointer. Returns nullptr if there is no current checkpoint object.
virtual void createHead_()=0
Create a head node.
virtual std::vector< chkpt_id_t > getCheckpointsAt(tick_t t) const =0
Gets all checkpoints taken at tick t on any timeline.
void dumpBranch(std::ostream &o, const Checkpoint *chkpt, uint32_t indent, uint32_t pos, std::deque< uint32_t > &continues) const
Recursively dumps one branch (and sub-branches) to an ostream with a line for each branch.
Checkpoint * getHead_() noexcept
Non-const variant of getHead_.
virtual bool hasCheckpoint(chkpt_id_t id) const noexcept
Tests whether this checkpoint manager has a checkpoint with the given id.
chkpt_id_t getCurrentID() const
Returns the current checkpoint ID. This is mainly a debugging utility as the current ID changes when ...
virtual std::vector< chkpt_id_t > getCheckpoints() const =0
Gets all known checkpoint IDs available on any timeline sorted by tick (or equivalently checkpoint ID...
tick_t getCurrentTick() const
Gets the tick number of the current checkpoint (see getCurrentID). This is the tick number of the lat...
virtual chkpt_id_t createCheckpoint_(bool force_snapshot=false)=0
Create a checkpoint.
virtual uint32_t getNumCheckpoints() const noexcept=0
Gets the current number of checkpoints having valid IDs which a client of this interface can refer to...
Checkpoint::tick_t tick_t
tick_t Tick type to which checkpoints will refer
virtual void deleteCheckpoint(chkpt_id_t id)=0
Deletes a checkpoint by ID.
std::map< chkpt_id_t, std::unique_ptr< Checkpoint > > chkpts_
All checkpoints sorted by ascending tick number (or equivalently ascending checkpoint ID since both a...
const Checkpoint * getHead() const noexcept
Returns the head checkpoint which is equivalent to the earliest checkpoint taken.
uint64_t getTotalCheckpointsCreated() const noexcept
Returns the total number of checkpoints which have been created by this checkpointer....
Checkpoint::chkpt_id_t chkpt_id_t
tick_t Tick type to which checkpoints will refer
TreeNode & getRoot() noexcept
Non-const variant of getRoot.
virtual std::string stringize() const
Returns a string describing this object.
void setCurrent_(Checkpoint *current)
Sets the current checkpoint pointer.
chkpt_id_t getHeadID() const noexcept
Returns the checkpoint ID of the head checkpoint (if it exists) which is equivalent to the earliest c...
Checkpoint * findCheckpoint(chkpt_id_t id) noexcept
Finds a checkpoint by its ID.
virtual std::deque< chkpt_id_t > getCheckpointChain(chkpt_id_t id) const =0
Debugging utility which gets a deque of checkpoints representing a chain starting at the checkpoint h...
void forgetCurrent()
Forgets the current checkpoint and current checkpoint (resetting to the head checkpoint) so that chec...
uint64_t getContentMemoryUse() const noexcept
Computes and returns the memory usage by this checkpointer at this moment purely for the checkpoint s...
void setHead_(Checkpoint *head)
Sets the head checkpointer pointer to head for the first time.
std::ostream & operator<<(std::ostream &o, const SimulationInfo &info)
ostream insertion operator for SimulationInfo