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
87 Checkpointer(TreeNode& root, sparta::Scheduler* sched=nullptr):
88 sched_(sched)
89 {
90 roots_.push_back(&root);
91 }
92
103 Checkpointer(const std::vector<TreeNode*>& roots, sparta::Scheduler* sched=nullptr):
104 sched_(sched),
105 roots_(roots)
106 { }
107
111 virtual ~Checkpointer() {
112 }
113
116
120
124 const std::vector<TreeNode*> & getRoots() const noexcept { return roots_; }
125
129 const Scheduler* getScheduler() const noexcept { return sched_; }
130
137 virtual uint64_t getTotalMemoryUse() const noexcept = 0;
138
143 virtual uint64_t getContentMemoryUse() const noexcept = 0;
144
150 uint64_t getTotalCheckpointsCreated() const noexcept {
151 return total_chkpts_created_;
152 }
153
156
160
182 void createHead() {
183 tick_t tick = 0;
184 if(sched_){
185 tick = sched_->getCurrentTick();
186 }
187 if(head_){
188 CheckpointError exc("Cannot create head at ");
189 if(sched_){
190 exc << tick;
191 }else{
192 exc << "<no scheduler>";
193 }
194 exc << " because a head already exists in this checkpointer";
195 throw exc;
196 }
197 for (auto root : roots_) {
198 if(root->isFinalized() == false){
199 CheckpointError exc("Cannot create a checkpoint until the tree is finalized. Attempting to checkpoint from node ");
200 exc << root->getLocation() << " at tick ";
201 if(sched_){
202 exc << tick;
203 }else{
204 exc << "<no scheduler>";
205 }
206 throw exc;
207 }
208 }
209
210 enumerateArchDatas_(); // Determines which ArchDatas are required and populates adatas_
211
212 createHead_();
213
214 sparta_assert(head_ != nullptr, "A call to createHead_ must create a head and invoke setHead_ or throw an exception");
215
216 total_chkpts_created_++;
217 }
218
246 chkpt_id_t createCheckpoint(bool force_snapshot=false) {
247 if(!head_){
248 createHead();
249 }
250
251 chkpt_id_t id = createCheckpoint_(force_snapshot);
252 total_chkpts_created_++;
253 return id;
254 }
255
275 virtual void deleteCheckpoint(chkpt_id_t id) = 0;
276
289 virtual void loadCheckpoint(chkpt_id_t id) = 0;
290
310 if(head_){
311 current_ = head_;
312 }
313 }
314
323 virtual std::vector<chkpt_id_t> getCheckpointsAt(tick_t t) = 0;
324
333 virtual std::vector<chkpt_id_t> getCheckpoints() = 0;
334
342 virtual uint32_t getNumCheckpoints() const noexcept = 0;
343
359 virtual std::deque<chkpt_id_t> getCheckpointChain(chkpt_id_t id) = 0;
360
368 virtual bool hasCheckpoint(chkpt_id_t id) noexcept = 0;
369
380 const CheckpointBase* getHead() const noexcept {
381 return head_;
382 }
383
393 chkpt_id_t getHeadID() const noexcept {
394 if(!head_){
396 }
397 return head_->getID();
398 }
399
425 if(current_){
426 return current_->getID();
427 }
428 sparta_assert(!head_); // If there was no current, it can only be because there is no head yet
430 }
431
445 if(current_){
446 return current_->getTick();
447 }
448 sparta_assert(!head_);
449 return 0;
450 }
451
455 virtual std::vector<chkpt_id_t> getNextIDs(chkpt_id_t id) = 0;
456
459
463
467 virtual std::string stringize() const {
468 std::stringstream ss;
469 ss << "<Checkpointer on ";
470 for (size_t i = 0; i < roots_.size(); ++i) {
471 TreeNode* root = roots_[i];
472 if (i != 0) {
473 ss << ", ";
474 }
475 ss << root->getLocation();
476 }
477 ss << ">";
478 return ss.str();
479 }
480
486 virtual void dumpList(std::ostream& o) = 0;
487
493 virtual void dumpData(std::ostream& o) = 0;
494
501 virtual void dumpAnnotatedData(std::ostream& o) = 0;
502
517 virtual void traceValue(std::ostream& o, chkpt_id_t id, const ArchData* container, uint32_t offset, uint32_t size) = 0;
518
525 void dumpTree(std::ostream& o) {
526 std::deque<uint32_t> c;
527 dumpBranch(o, getHeadID(), 0, 0, c);
528 o << '\n';
529 }
530
543 void dumpBranch(std::ostream& o,
544 const chkpt_id_t chkpt,
545 uint32_t indent,
546 uint32_t pos,
547 std::deque<uint32_t>& continues) {
549 static const std::string SEP_STR = "-> "; // Normal checkpoint chain
550 static const std::string CONT_SEP_STR = "`> "; // Checkpoint branch from higher line
551 assert(SEP_STR.size() == CONT_SEP_STR.size()); // Must be the same length so the layout looks OK
552
553 // Walk through indent and draw continuations
554 uint32_t i = pos;
555 std::remove_reference<decltype(continues)>::type::const_iterator next_cont = continues.begin();
556 for(; i < indent; ++i){
557 if(next_cont != continues.end() && i == *next_cont){
558 o << '|';
559 while(next_cont != continues.end() && *next_cont == i){ // Skip duplicates and move on to next
560 ++next_cont;
561 }
562 }else{
563 o << ' ';
564 }
565 }
566
567 auto nexts = getNextIDs(chkpt);
568 std::stringstream ss;
569
570 // Draw separator between prev checkpoint and this
571 if(next_cont != continues.end() && *next_cont == indent && indent != pos){
572 ss << CONT_SEP_STR;
573 }else{
574 ss << SEP_STR;
575 }
576
577 // Draw box around object if it is current
578 if(current_ && current_->getID() == chkpt){
579 ss << "[ ";
580 }
581
582 dumpCheckpointNode_(chkpt, ss);
583 ss << ' ';
584
585 if(current_ && current_->getID() == chkpt){
586 ss << ']';
587 }
588
589 o << ss.str();
590 i += ss.str().size();
591
592 // Draw all next checkpoints recursively
593 if(nexts.size() > 0){
594 if(nexts.size() > 1){
595 continues.push_back(i); // Push continues first
596 }
597 dumpBranch(o, nexts.front(), i, i, continues); // No indent, no newline
598 decltype(nexts)::const_iterator itr = nexts.begin() + 1;
599 if(itr == nexts.end()){
600 //continues.pop_back();
601 }else{
602 while(itr < nexts.end()){
603 if(itr+1 == nexts.end()){
604 continues.pop_back(); // Do not show this continuation here
605 }
606 o << '\n';
607 dumpBranch(o, *itr, i, 0, continues); // Indent
608 ++itr;
609 }
610 }
611 }
612 }
613
616
617 protected:
618
629 virtual void createHead_() = 0;
630
639 virtual chkpt_id_t createCheckpoint_(bool force_snapshot=false) = 0;
640
641 virtual void dumpCheckpointNode_(const chkpt_id_t id, std::ostream& o) {
642 o << id;
643 }
644
649 const std::vector<ArchData*>& getArchDatas() const {
650 return adatas_;
651 }
652
657 return head_;
658 }
659
663 const CheckpointBase* getHead_() const noexcept {
664 return head_;
665 }
666
675 sparta_assert(head != nullptr, "head argument in setHead_ cannot be nullptr");
676 sparta_assert(head_ == nullptr, "Cannot setHead_ again on a Checkpointer once heas is already set");
677 head_ = head;
678 }
679
684 CheckpointBase* getCurrent_() const noexcept {
685 return current_;
686 }
687
695 sparta_assert(current != nullptr,
696 "Can never setCurrent_ to nullptr except. A null current is a valid state at initialization only")
697 current_ = current;
698 }
699
706
707 private:
708
714 void enumerateArchDatas_() {
715 sparta_assert(adatas_.size() == 0, "FastCheckpointer already has a vector of ArchDatas. Cannot re-enumerate");
716
717 adatas_.clear(); // Clear in case invoked again
718
719 // This is a helper for building the adatas_ vector while detecting
720 // dupicate ArchDatas.
721 // Maps an ArchData key to the TreeNode which pointed to it.
722 std::map<ArchData*,TreeNode*> adatas_helper;
723
724 // Recursively walk the tree and add all ArchDatas to adatas_
725 for(TreeNode* root : roots_) {
726 recursAddArchData_(root, adatas_helper);
727 }
728 }
729
737 void recursAddArchData_(TreeNode* n, std::map<ArchData*,TreeNode*>& adatas_helper) {
738 assert(n);
739 auto adatas = n->getAssociatedArchDatas();
740 for(ArchData* ad : adatas){
741 if(ad != nullptr){
742 auto itr = adatas_helper.find(ad);
743 if(itr != adatas_helper.end()){
744 throw CheckpointError("Found a second reference to ArchData ")
745 << ad << " in the checkpointer: " << stringize() << " . First reference found throgh "
746 << itr->second->getLocation() << " and second found through " << n->getLocation()
747 << " . An ArchData should be findable throug exactly 1 TreeNode";
748 }
749 adatas_.push_back(ad);
750 adatas_helper[ad] = n; // Add to helper map
751 }
752 }
753 for(TreeNode* child : TreeNodePrivateAttorney::getAllChildren(n)){
754 recursAddArchData_(child, adatas_helper);
755 }
756 }
757
758 std::vector<TreeNode*> roots_;
759
764 CheckpointBase* head_ = nullptr;
765
770 std::vector<ArchData*> adatas_;
771
775 CheckpointBase* current_ = nullptr;
776
781 uint64_t total_chkpts_created_ = 0;
782 };
783
784} // namespace sparta::serialization::checkpoint
785
786
788inline std::ostream& operator<<(std::ostream& o, const sparta::serialization::checkpoint::Checkpointer& cpr){
789 o << cpr.stringize();
790 return o;
791}
792
794inline std::ostream& operator<<(std::ostream& o, const sparta::serialization::checkpoint::Checkpointer* cpr){
795 if(cpr == 0){
796 o << "null";
797 }else{
798 o << cpr->stringize();
799 }
800 return o;
801}
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
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.
static const TreeNode::ChildrenVector & getAllChildren(const TreeNode &node)
Node in a composite tree representing a sparta Tree item.
Definition TreeNode.hpp:205
std::string getLocation() const override final
Single checkpoint object interface with a tick number and an ID unique to the owning Checkpointer ins...
uint64_t chkpt_id_t
tick_t Checkpoint ID type to which checkpoints will refer
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.
sparta::Scheduler::Tick tick_t
tick_t Tick type to which checkpoints will refer
Indicates that there was an issue operating on checkpoints within the SPARTA framework.
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...
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
void createHead()
Creates a head without taking an identified checkpoint. Cannot already have a head.
virtual uint64_t getTotalMemoryUse() const noexcept=0
Computes and returns the memory usage by this checkpointer at this moment including any framework ove...
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.
virtual std::vector< chkpt_id_t > getCheckpoints()=0
Gets all known checkpoint IDs available on any timeline sorted by tick (or equivalently checkpoint ID...
Scheduler *const sched_
Scheduler whose tick count will be set and read. Cannnot be updated after first checkpoint without ba...
virtual void dumpList(std::ostream &o)=0
Dumps this checkpointer's flat list of checkpoints to an ostream with a newline following each checkp...
CheckpointBase * getHead_() noexcept
Non-const variant of getHead_.
Checkpointer(const std::vector< TreeNode * > &roots, sparta::Scheduler *sched=nullptr)
Checkpointer Constructor.
const Scheduler * getScheduler() const noexcept
Returns the sheduler 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.
const CheckpointBase * getHead() const noexcept
Returns the head checkpoint which is equivalent to the earliest checkpoint taken.
virtual void loadCheckpoint(chkpt_id_t id)=0
Loads state from a specific checkpoint by ID.
virtual void dumpAnnotatedData(std::ostream &o)=0
Dumps this checkpointer's data to an ostream with annotations between each ArchData and a newline fol...
void setHead_(CheckpointBase *head)
Sets the head checkpointer pointer to head for the first time.
virtual void createHead_()=0
Create a head node.
virtual std::deque< chkpt_id_t > getCheckpointChain(chkpt_id_t id)=0
Debugging utility which gets a deque of checkpoints representing a chain starting at the checkpoint h...
chkpt_id_t getCurrentID() const
Returns the current checkpoint ID. This is mainly a debugging utility as the current ID changes when ...
const CheckpointBase * getHead_() const noexcept
Gets the head checkpoint. Returns nullptr if none created yet.
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...
virtual std::vector< chkpt_id_t > getNextIDs(chkpt_id_t id)=0
Returns IDs of the checkpoints immediately following the given checkpoint.
void dumpBranch(std::ostream &o, const chkpt_id_t chkpt, uint32_t indent, uint32_t pos, std::deque< uint32_t > &continues)
Recursively dumps one branch (and sub-branches) to an ostream with a line for each branch.
virtual chkpt_id_t createCheckpoint_(bool force_snapshot=false)=0
Create a checkpoint.
virtual void dumpData(std::ostream &o)=0
Dumps this checkpointer's data to an ostream with a newline following each 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...
virtual void deleteCheckpoint(chkpt_id_t id)=0
Deletes a checkpoint by ID.
uint64_t getTotalCheckpointsCreated() const noexcept
Returns the total number of checkpoints which have been created by this checkpointer....
virtual bool hasCheckpoint(chkpt_id_t id) noexcept=0
Tests whether this checkpoint manager has a checkpoint with the given id.
virtual std::vector< chkpt_id_t > getCheckpointsAt(tick_t t)=0
Gets all checkpoints taken at tick t on any timeline.
virtual std::string stringize() const
Returns a string describing this object.
void dumpTree(std::ostream &o)
Dumps this checkpointer's tree to an ostream with a line for each branch. Printout timescale is not r...
chkpt_id_t getHeadID() const noexcept
Returns the checkpoint ID of the head checkpoint (if it exists) which is equivalent to the earliest c...
virtual uint64_t getContentMemoryUse() const noexcept=0
Computes and returns the memory usage by this checkpointer at this moment purely for the checkpoint s...
CheckpointBase * getCurrent_() const noexcept
Gets the current checkpointer pointer. Returns nullptr if there is no current checkpoint object.
void forgetCurrent()
Forgets the current checkpoint and current checkpoint (resetting to the head checkpoint) so that chec...
std::ostream & operator<<(std::ostream &o, const SimulationInfo &info)
ostream insertion operator for SimulationInfo