From f4ad5b3033899971efa565b349cd163e7bb528cb Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Mon, 10 Aug 2026 13:43:55 +0200 Subject: [PATCH 1/3] Allow optionally taking full snapshots on a set interval in tracing mode --- src/Debug/debugger.cpp | 24 ++++++++++++++++++++---- src/Debug/debugger.h | 8 +++++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/Debug/debugger.cpp b/src/Debug/debugger.cpp index 25df2957..9b57328e 100644 --- a/src/Debug/debugger.cpp +++ b/src/Debug/debugger.cpp @@ -24,6 +24,7 @@ Debugger::Debugger(Channel *duplex) { this->snapshotPolicy = SnapshotPolicy::none; this->checkpointInterval = 10; this->instructions_executed = 0; + this->instructions_since_full_snapshot = 0; this->fidx_called = {}; this->min_return_values = 0; this->checkpoint_state = nullptr; @@ -1015,6 +1016,7 @@ void Debugger::setSnapshotPolicy(Module *m, uint8_t *interruptData) { } checkpoint_state = nullptr; checkpoint_state_size = 0; + *data_ptr += 1; } else { snapshotPolicy = SnapshotPolicy::checkpointing; *data_ptr += 1; @@ -1032,8 +1034,9 @@ void Debugger::setSnapshotPolicy(Module *m, uint8_t *interruptData) { // Make a checkpoint when you first enable checkpointing if (snapshotPolicy == SnapshotPolicy::checkpointing) { - uint8_t *ptr = *data_ptr + 1; - checkpointInterval = read_B32(&ptr); + checkpointInterval = read_B32(data_ptr); + instructions_executed = 0; + instructions_since_full_snapshot = 0; checkpoint(m, true); } printf("ack%x\n", interruptSetSnapshotPolicy); @@ -1076,6 +1079,18 @@ void Debugger::handleSnapshotPolicy(Module *m) { } instructions_executed++; + // When using tracing, optionally (if the interval is 0xffffffff no full + // snapshots will be taken) take full checkpoints every + // checkpointInterval instructions. + if (checkpoint_state != nullptr) { + instructions_since_full_snapshot++; + if (checkpointInterval != UINT32_MAX && + instructions_since_full_snapshot >= checkpointInterval) { + checkpoint(m, true, true); + instructions_since_full_snapshot = 0; + } + } + ExecutionContext *ectx = m->warduino->execution_context; // Store arguments of last primitive call. if ((fidx_called = getPrimitiveBeingCalled(m, ectx->pc_ptr))) { @@ -1090,7 +1105,7 @@ void Debugger::handleSnapshotPolicy(Module *m) { } } -void Debugger::checkpoint(Module *m, const bool force) { +void Debugger::checkpoint(Module *m, const bool force, const bool full) { if (instructions_executed == 0 && !force) { return; } @@ -1119,7 +1134,7 @@ void Debugger::checkpoint(Module *m, const bool force) { this->channel->write("], "); } this->channel->write(R"("snapshot": )"); - if (!checkpoint_state) { + if (!checkpoint_state || full) { snapshot(m); } else { inspect(m, checkpoint_state_size, checkpoint_state); @@ -1661,6 +1676,7 @@ bool Debugger::handleUpdateStackValue(const Module *m, uint8_t *bytes) const { bool Debugger::reset(Module *m) { m->warduino->reset_module(m); instructions_executed = 0; + instructions_since_full_snapshot = 0; this->channel->write("Reset WARDuino.\n"); return true; } diff --git a/src/Debug/debugger.h b/src/Debug/debugger.h index 6a241ab8..3a5b6626 100644 --- a/src/Debug/debugger.h +++ b/src/Debug/debugger.h @@ -155,8 +155,10 @@ class Debugger { // Checkpointing SnapshotPolicy snapshotPolicy; - uint32_t checkpointInterval; // #instructions between checkpoints - uint32_t instructions_executed; // #instructions since last checkpoint + uint32_t checkpointInterval; // #instructions between checkpoints + uint32_t instructions_executed; // #instructions since last checkpoint + uint32_t instructions_since_full_snapshot; // #instructions since last full + // snapshot std::optional fidx_called; // The primitive that was executed uint32_t prim_args[8]; // The arguments of the executed prim uint32_t min_return_values; @@ -336,6 +338,6 @@ class Debugger { bool getMockForArgs(Module *m, uint32_t fidx, uint32_t &result); // Checkpointing - void checkpoint(Module *m, bool force = false); + void checkpoint(Module *m, bool force = false, bool full = false); inline SnapshotPolicy getSnapshotPolicy() { return snapshotPolicy; } }; From 26853471e41ff7e79213e789d360390311d2c313 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Thu, 13 Aug 2026 11:11:11 +0200 Subject: [PATCH 2/3] Fix full snapshots having the instruction counter offset by 1 This caused all kinds of strange bugs in the debugger. --- src/Debug/debugger.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Debug/debugger.cpp b/src/Debug/debugger.cpp index 9b57328e..a2edcf63 100644 --- a/src/Debug/debugger.cpp +++ b/src/Debug/debugger.cpp @@ -1077,7 +1077,6 @@ void Debugger::handleSnapshotPolicy(Module *m) { } } } - instructions_executed++; // When using tracing, optionally (if the interval is 0xffffffff no full // snapshots will be taken) take full checkpoints every @@ -1091,6 +1090,8 @@ void Debugger::handleSnapshotPolicy(Module *m) { } } + instructions_executed++; + ExecutionContext *ectx = m->warduino->execution_context; // Store arguments of last primitive call. if ((fidx_called = getPrimitiveBeingCalled(m, ectx->pc_ptr))) { From bbeb4b3845b1d8e9ddf5056222cd807bedfaf2d7 Mon Sep 17 00:00:00 2001 From: MaartenS11 Date: Wed, 19 Aug 2026 14:29:24 +0200 Subject: [PATCH 3/3] Update instructions_since_full_snapshot after check not before to be consistent with instructions_executed + reset counters when loading a snapshot --- src/Debug/debugger.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Debug/debugger.cpp b/src/Debug/debugger.cpp index a2edcf63..0cb65b9b 100644 --- a/src/Debug/debugger.cpp +++ b/src/Debug/debugger.cpp @@ -1082,12 +1082,12 @@ void Debugger::handleSnapshotPolicy(Module *m) { // snapshots will be taken) take full checkpoints every // checkpointInterval instructions. if (checkpoint_state != nullptr) { - instructions_since_full_snapshot++; if (checkpointInterval != UINT32_MAX && instructions_since_full_snapshot >= checkpointInterval) { checkpoint(m, true, true); instructions_since_full_snapshot = 0; } + instructions_since_full_snapshot++; } instructions_executed++; @@ -1158,6 +1158,11 @@ void Debugger::freeState(Module *m, uint8_t *interruptData) { ectx->sp = -1; memset(ectx->br_table, 0, BR_TABLE_SIZE); + // Reset checkpointing counters, new checkpoints will have instructions + // executed since this snapshot. + instructions_since_full_snapshot = 0; + instructions_executed = 0; + while (first_msg < endfm) { switch (*first_msg++) { case globalsState: {