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() = delete;
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
533
534 protected:
535
541 void loadState(const std::vector<ArchData*>& dats) {
542 data_.prepareForLoad();
543 sparta_assert(data_.good(),
544 "Attempted to loadState from a DeltaCheckpoint with a bad data buffer");
545 if(isSnapshot()){
546 for(ArchData* ad : dats){
547 //std::cout << "Restoring for ArchData: " << (void*)ad << " " << ad->getOwnerNode()->getLocation() << std::endl;
548 ad->restoreAll(data_);
549 }
550 }else{
551 for(ArchData* ad : dats){
552 //std::cout << "Restoring for ArchData: " << (void*)ad << " " << ad->getOwnerNode()->getLocation() << std::endl;
553 ad->restore(data_);
554 }
555 }
556 }
557
558 private:
559
563
570 void storeSnapshot_(const std::vector<ArchData*>& dats) {
571 sparta_assert(data_.good(),
572 "Attempted to storeSnapshot_ from a DeltaCheckpoint with a bad data buffer");
573 // Cannot have stored already
574 for(ArchData* ad : dats){
575 //std::cout << "SaveAll for ArchData: " << ad->getOwnerNode()->getLocation() << std::endl;
576 ad->saveAll(data_);
577 }
578 }
579
586 void storeDelta_(const std::vector<ArchData*>& dats) {
587 sparta_assert(data_.good(),
588 "Attempted to storeDelta_ from a DeltaCheckpoint with a bad data buffer");
589 // Cannot have stored already
590 for(ArchData* ad : dats){
591 //std::cout << "Save for ArchData: " << ad->getOwnerNode()->getLocation() << std::endl;
592 ad->save(data_);
593 }
594 }
595
598
599
605 chkpt_id_t deleted_id_;
606 bool const is_snapshot_;
607 StorageT data_;
608 };
609
610} // 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 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 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...
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...
DeltaCheckpoint()=delete
Not default constructable.
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.
virtual uint64_t getTotalMemoryUse() const noexcept override
Returns memory usage by this checkpoint.
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...