The Sparta Modeling Framework
Loading...
Searching...
No Matches
DeltaCheckpoint.hpp
1// <DeltaCheckpoint.hpp> -*- C++ -*-
2
3#pragma once
4
5#include <iostream>
6#include <sstream>
7#include <stack>
8
10#include "sparta/functional/ArchData.hpp"
14
15#include "sparta/serialization/checkpoint/Checkpointer.hpp"
17#include "sparta/serialization/checkpoint/VectorStorage.hpp"
18#include "sparta/serialization/checkpoint/StringStreamStorage.hpp"
19
20namespace sparta::serialization::checkpoint
21{
22 class FastCheckpointer;
23
42 template<typename StorageT=storage::StringStreamStorage>
44 {
45 public:
46
50
52 DeltaCheckpoint() = default;
53
56
58 const DeltaCheckpoint& operator=(const DeltaCheckpoint&) = delete;
59
60 private:
61
91 DeltaCheckpoint(const std::vector<ArchData*>& dats,
92 chkpt_id_t id,
93 tick_t tick,
94 DeltaCheckpoint* prev_delta,
95 bool is_snapshot) :
96 Checkpoint(id, tick, prev_delta),
97 deleted_id_(UNIDENTIFIED_CHECKPOINT),
98 is_snapshot_(is_snapshot)
99 {
100 if(nullptr == prev_delta){
101 if(is_snapshot == false){
102 throw CheckpointError("Cannot create a DeltaCheckpoint id=")
103 << id << " at tick=" << tick << " which has no prev_delta and is not a snapshot";
104 }
105 }else{
106 prev_delta->addNext(this);
107 }
108
109 // Store the checkpoint from root
110 if(is_snapshot){
111 storeSnapshot_(dats);
112 }else{
113 storeDelta_(dats);
114 }
115 }
116
118 friend class FastCheckpointer;
119
120 public:
121
130 if(!canDelete()){
131 std::cerr << "WARNING: DeltaCheckpoint " << getID()
132 << " being destructed without being allowed to delete" << std::endl;
133 }
134 }
135
138
142 virtual std::string stringize() const override {
143 std::stringstream ss;
144 ss << "<DeltaCheckpoint id=";
145 if(isFlaggedDeleted()){
146 ss << "DELETED";
147 }else{
148 ss << getID();
149 }
150 ss << " at t=" << getTick();
151 if(isSnapshot()){
152 ss << "(snapshot)";
153 }
154 ss << ' ' << getTotalMemoryUse()/1000.0f << "kB (" << getContentMemoryUse()/1000.0f << "kB Data)";
155 ss << '>';
156 return ss.str();
157 }
158
164 virtual void dumpData(std::ostream& o) const override {
165 data_.dump(o);
166 }
167
173 void dumpRestoreChain(std::ostream& o) const {
174 auto rc = getRestoreChain();
175 while(1){
176 const DeltaCheckpoint* cp = rc.top();
177 rc.pop();
178 if(cp->isSnapshot()){
179 o << '(';
180 }
181 if(cp->getID() == UNIDENTIFIED_CHECKPOINT){
182 o << "*" << getDeletedID();
183 }else{
184 o << cp->getID();
185 }
186 if(cp->isSnapshot()){
187 o << ')';
188 }
189 if(rc.empty()){
190 break;
191 }else{
192 o << " --> ";
193 }
194 }
195 }
196
200 virtual uint64_t getTotalMemoryUse() const noexcept override {
201 return getContentMemoryUse() \
202 + sizeof(decltype(*this)) \
203 + (getNexts().size() * sizeof(typename std::remove_reference<decltype(*this)>::type*));
204 }
205
209 virtual uint64_t getContentMemoryUse() const noexcept override {
210 return data_.getSize();
211 }
212
216
220 void traceValue(std::ostream& o, const std::vector<ArchData*>& dats,
221 const ArchData* container, uint32_t offset, uint32_t size)
222 {
223 std::stack<DeltaCheckpoint*> dcps = getHistoryChain();
224
225 std::vector<std::pair<uint8_t,bool>> bytes; // pair<value,valid>
226 bytes.resize(size, decltype(bytes)::value_type(0,false));
227
228 constexpr uint32_t BUF_SIZE = 8192*2;
229 std::unique_ptr<char[]> buf(new char[BUF_SIZE]); // Line-reading buffer
230
231 while(!dcps.empty()){
232 DeltaCheckpoint* d = dcps.top();
233 o << "trace: Checkpoint " << d->getDeletedRepr() << (d->isSnapshot()?" (snapshot)":"") << std::endl;
234 dcps.pop();
235 d->data_.prepareForLoad();
236 bool found_ad = false;
237 bool changed = false;
238 for(ArchData* ad : dats){
239 if(ad == container){
240 found_ad = true;
241 if(d->isSnapshot()){
242 for(auto &x : bytes){
243 x.second = false; // Invalidate result due to snapshot load
244 }
245 }
246 }
247 while(1){
248 auto ln_idx = d->data_.getNextRestoreLine();
249 if(ln_idx == ArchData::INVALID_LINE_IDX){
250 if(ad == container){
251 //if(changed == false){
252 // o << "trace: No data for this value" << std::endl;
253 //}
254 }
255 break; // Done with this ArchData
256 }
257 auto ln_off = ln_idx * ad->getLineSize();
258 sparta_assert(BUF_SIZE > ad->getLineSize(),
259 "Cannot trace value on ArchDatas with line sizes > " << BUF_SIZE << " (" << ad->getLineSize() << ")");
260 d->data_.copyLineBytes((char*)buf.get(), ad->getLineSize()); // Need to read regardless of usefulness of data
261 if(ad == container){
262 //o << "trace: Contains data for line idx " << std::dec << ln_idx
263 // << " offsets [" << ln_off << "," << ln_off+ad->getLineSize() << ")" << std::endl;
264 if(offset >= ln_off && offset < ln_off + ad->getLineSize()){
265 sparta_assert(offset+size < ln_off + ad->getLineSize(),
266 "Cannot trace value which spans multiple lines!");
267 sparta_assert(changed == false,
268 "Value being traced changed twice in the same checkpoint");
269 changed = true;
270 auto off_in_line = offset - ln_off;
271 o << "trace: Value changed (line " << std::dec << ln_idx << ")" << std::endl;
272 for(uint32_t i=0; i<bytes.size(); i++){
273 bytes[i].first = buf.get()[i+off_in_line];
274 bytes[i].second = true; // Valid
275 }
276 }
277 }
278 }
279 }
280 if(!found_ad){
281 o << "trace: Could not find selected ArchData " << (const void*)container << " in this checkpoint!" << std::endl;
282 }
283 o << "trace: Value:";
284 for(uint32_t i=0; i<bytes.size(); i++){
285 if(bytes[i].second){
286 o << ' ' << std::setfill('0') << std::setw(2) << std::hex << (uint16_t)bytes[i].first;
287 }else{
288 o << " xx"; // Invalid
289 }
290 }
291 o << std::endl;
292 }
293 o << std::endl;
294 }
295
303 std::stack<DeltaCheckpoint*> getHistoryChain() {
304 // Build stack up to last snapshot
305 DeltaCheckpoint* n = this;
306 std::stack<DeltaCheckpoint*> dcps;
307 while(n){
308 dcps.push(n);
309 n = static_cast<DeltaCheckpoint*>(n->getPrev());
310 }
311 return dcps;
312 }
313
319 std::stack<DeltaCheckpoint*> getRestoreChain() {
320 // Build stack up to last snapshot
321 DeltaCheckpoint* n = this;
322 std::stack<DeltaCheckpoint*> dcps;
323 while(1){
324 dcps.push(n);
325 if(n->isSnapshot()){
326 break;
327 }
328 n = static_cast<DeltaCheckpoint*>(n->getPrev());
329 }
330 return dcps;
331 }
332
336 std::stack<const DeltaCheckpoint*> getRestoreChain() const {
337 // Build stack up to last snapshot
338 const DeltaCheckpoint* n = this;
339 std::stack<const DeltaCheckpoint*> dcps;
340 while(1){
341 dcps.push(n);
342 if(n->isSnapshot()){
343 break;
344 }
345 n = static_cast<const DeltaCheckpoint*>(n->getPrev());
346 }
347 return dcps;
348 }
349
355 chkpt_id_t getPrevID() const override {
356 if (auto prev = static_cast<const DeltaCheckpoint*>(getPrev())) {
357 if (!prev->isFlaggedDeleted()) {
358 return prev->getID();
359 }
360 }
362 }
363
368 std::vector<chkpt_id_t> getNextIDs() const override {
369 std::vector<chkpt_id_t> next_ids;
370 for (const auto chkpt : getNexts()) {
371 const auto dcp = static_cast<const DeltaCheckpoint*>(chkpt);
372 if (!dcp->isFlaggedDeleted()) {
373 next_ids.push_back(chkpt->getID());
374 }
375 }
376 return next_ids;
377 }
378
386 virtual void load(const std::vector<ArchData*>& dats) override {
387 // Build stack up to last snapshot
388 std::stack<DeltaCheckpoint*> dcps = getRestoreChain();
389
390 // Load in proper order
391 while(!dcps.empty()){
392 DeltaCheckpoint* d = dcps.top();
393 dcps.pop();
394 d->loadState(dats);
395 }
396 }
397
406 bool canDelete() const noexcept {
407 if(!isFlaggedDeleted()){
408 return false;
409 }
410 for(auto d : getNexts()){
411 const DeltaCheckpoint* dcp = static_cast<const DeltaCheckpoint*>(d);
412 if(!dcp->canDelete() && !dcp->isSnapshot()){
413 return false;
414 }
415 }
416 return true; // This checkpoint was flagged deleted
417 }
418
430 void flagDeleted() {
432 "Cannot delete a checkpoint when it is already deleted: " << this);
433 deleted_id_ = getID();
435 }
436
444 bool isFlaggedDeleted() const noexcept {
445 return getID() == UNIDENTIFIED_CHECKPOINT;
446 }
447
453 chkpt_id_t getDeletedID() const noexcept {
454 return deleted_id_;
455 }
456
463 virtual std::string getDeletedRepr() const override {
464 std::stringstream ss;
465 if(isFlaggedDeleted()){
466 ss << "*" << getDeletedID();
467 }else{
468 ss << getID();
469 }
470 return ss.str();
471 }
472
476 bool isSnapshot() const noexcept { return is_snapshot_; }
477
488 uint32_t getDistanceToPrevSnapshot() const noexcept {
489 const DeltaCheckpoint* d = this;
490 uint32_t dist = 0;
491 while(d){
492 if(d->isSnapshot()){
493 return dist;
494 }
495 d = static_cast<const DeltaCheckpoint*>(d->getPrev());
496 ++dist;
497 }
498
499 // This will compile just fine....
500#ifdef __clang__
501 // This is known to be needed with Clang 8.0.0; not sure about other versions.
502#pragma clang diagnostic push
503#pragma clang diagnostic ignored "-Wexceptions"
504#elif defined __GNUC__ // Note that clang defines both __clang__ and __GNUC__
505#pragma GCC diagnostic push
506#if __GNUC__ > 5
507 // gcc 4.7 doesn't like this.
508#pragma GCC diagnostic ignored "-Wterminate"
509#endif // __GNUC__ > 5
510#endif // ifdef __clang__ ... elif defined __GNUC__ ...
511
512
513 throw CheckpointError() << "In getDistanceToPrevious, somehow reached null "
514 << "previous-checkpoint without encountering a snapshot. This should "
515 << "never occur and is a critical error";
516#ifdef __clang__
517#pragma clang diagnostic pop
518#elif defined __GNUC__
519#pragma GCC diagnostic pop
520#endif
521
522
523 // But using my macro that injects the pragmas doesn't work... ugh
524 /*
525 TERMINATING_THROW(CheckpointError, "In getDistanceToPrevious, somehow reached null "
526 << "previous-checkpoint without encountering a snapshot. This should "
527 << "never occur and is a critical error");
528 */
529 }
530
536 void makeHeadCheckpoint() override {
537 sparta_assert(is_snapshot_);
539 }
540
544 template <typename Archive>
545 void serialize(Archive& ar, const unsigned int version) {
546 Checkpoint::serialize(ar, version);
547 ar & deleted_id_;
548 ar & is_snapshot_;
549 ar & data_;
550 }
551
554
555 protected:
556
562 void loadState(const std::vector<ArchData*>& dats) {
563 data_.prepareForLoad();
564 sparta_assert(data_.good(),
565 "Attempted to loadState from a DeltaCheckpoint with a bad data buffer");
566 if(isSnapshot()){
567 for(ArchData* ad : dats){
568 //std::cout << "Restoring for ArchData: " << (void*)ad << " " << ad->getOwnerNode()->getLocation() << std::endl;
569 ad->restoreAll(data_);
570 }
571 }else{
572 for(ArchData* ad : dats){
573 //std::cout << "Restoring for ArchData: " << (void*)ad << " " << ad->getOwnerNode()->getLocation() << std::endl;
574 ad->restore(data_);
575 }
576 }
577 }
578
579 private:
580
584
591 void storeSnapshot_(const std::vector<ArchData*>& dats) {
592 sparta_assert(data_.good(),
593 "Attempted to storeSnapshot_ from a DeltaCheckpoint with a bad data buffer");
594 // Cannot have stored already
595 for(ArchData* ad : dats){
596 //std::cout << "SaveAll for ArchData: " << ad->getOwnerNode()->getLocation() << std::endl;
597 ad->saveAll(data_);
598 }
599 }
600
607 void storeDelta_(const std::vector<ArchData*>& dats) {
608 sparta_assert(data_.good(),
609 "Attempted to storeDelta_ from a DeltaCheckpoint with a bad data buffer");
610 // Cannot have stored already
611 for(ArchData* ad : dats){
612 //std::cout << "Save for ArchData: " << ad->getOwnerNode()->getLocation() << std::endl;
613 ad->save(data_);
614 }
615 }
616
619
620
626 chkpt_id_t deleted_id_;
627
629 bool is_snapshot_ = false;
630
632 StorageT data_;
633 };
634
635} // namespace sparta::serialization::checkpoint
File that contains checkpoint exception types.
A simple time-based, event precedence based scheduler.
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
static const line_idx_type INVALID_LINE_IDX
Invalid line index.
Definition ArchData.hpp:112
uint64_t chkpt_id_t
tick_t Checkpoint ID type to which checkpoints will refer
void serialize(Archive &ar, const unsigned int)
boost::serialization support
void setID_(chkpt_id_t id)
Sets the checkpoint ID.
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.
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...
void makeHeadCheckpoint() override
Make this the head checkpoint by detaching from previous checkpoint.
void addNext(Checkpoint *next)
Adds another next checkpoint following *this.
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...
void makeHeadCheckpoint() override
Make this the head checkpoint by detaching from previous checkpoint.
std::vector< chkpt_id_t > getNextIDs() const override
Returns next checkpoint following *this. May be an empty vector if there are no later checkpoints.
virtual void dumpData(std::ostream &o) const override
Writes all checkpoint raw data to an ostream.
chkpt_id_t getPrevID() const override
Get the ID of our previous checkpoint. Returns UNIDENTIFIED_CHECKPOINT if we have no previous checkpo...
std::stack< DeltaCheckpoint * > getHistoryChain()
Returns a stack of checkpoints from this checkpoint as far back as possible until no previous link is...
bool isSnapshot() const noexcept
Is this checkpoint a snapshot (contains ALL simulator state)
std::stack< const DeltaCheckpoint * > getRestoreChain() const
Const-qualified version of getRestoreChain.
bool isFlaggedDeleted() const noexcept
Indicates whether this checkpoint has been flagged deleted.
virtual std::string getDeletedRepr() const override
Gets the representation of this deleted checkpoint as part of a checkpoint chain (if that checkpointe...
std::stack< DeltaCheckpoint * > getRestoreChain()
Returns a stack of checkpoints that must be restored from top-to-bottom to fully restore the state as...
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....
const DeltaCheckpoint & operator=(const DeltaCheckpoint &)=delete
Non-assignable.
void loadState(const std::vector< ArchData * > &dats)
Loads delta state of this checkpoint to root. Does not look at any other checkpoints checkpoints.
DeltaCheckpoint(const DeltaCheckpoint &)=delete
Not copy constructable.
virtual uint64_t getContentMemoryUse() const noexcept override
Returns memory usage by the content of this checkpoint.
DeltaCheckpoint()=default
Default constructor to support boost::serialization.
virtual uint64_t getTotalMemoryUse() const noexcept override
Returns memory usage by this checkpoint.
void serialize(Archive &ar, const unsigned int version)
boost::serialization support
virtual std::string stringize() const override
Returns a string describing this object.
uint32_t getDistanceToPrevSnapshot() const noexcept
Determines how many checkpoints away the closest, earlier snapshot is.
void dumpRestoreChain(std::ostream &o) const
Dumps the restore chain for this checkpoint.
Implements quick checkpointing through delta-checkpoint trees which store state-deltas in a compact f...