Buffer undo trace to a ring, add dump action, stop per-tick loadSaveProj spam
Trace lines fill a 4096-line ring instead of hitting the console per line; DUMP_UNDO_TRACE drains it in one ShowConsoleMsg call. Overflow is marked, not silent.
This commit is contained in:
+14
-3
@@ -108,6 +108,9 @@ static void RunShowVersion(int) {
|
|||||||
// the console window).
|
// the console window).
|
||||||
ShowConsoleMsg(("ReaSampler " + reasampler::version::appVersion() + "\n").c_str());
|
ShowConsoleMsg(("ReaSampler " + reasampler::version::appVersion() + "\n").c_str());
|
||||||
}
|
}
|
||||||
|
// TEMPORARY: drains the undo-trace ring buffer to the console in one call. See
|
||||||
|
// undo_trace.h; revert together with the rest of the undo-span tracing pass.
|
||||||
|
static void RunDumpUndoTrace(int) { reasampler::undoTraceDump(); }
|
||||||
|
|
||||||
// ONE row per bindable action this TU owns: FOREVER-STABLE id suffix, Actions-list
|
// ONE row per bindable action this TU owns: FOREVER-STABLE id suffix, Actions-list
|
||||||
// phrase, handler, per-row arg. Registration, hookcommand dispatch, and the unload
|
// phrase, handler, per-row arg. Registration, hookcommand dispatch, and the unload
|
||||||
@@ -170,6 +173,9 @@ static std::vector<reasampler::ActionTableRow> buildMainActionTable() {
|
|||||||
rows.push_back({"IMPORT_BANK_PACKAGE", "import bank package (.rsbank)",
|
rows.push_back({"IMPORT_BANK_PACKAGE", "import bank package (.rsbank)",
|
||||||
&RunImportBankPackage});
|
&RunImportBankPackage});
|
||||||
rows.push_back({"SHOW_VERSION", "show version", &RunShowVersion});
|
rows.push_back({"SHOW_VERSION", "show version", &RunShowVersion});
|
||||||
|
// TEMPORARY: see undo_trace.h; revert together with the rest of the undo-span
|
||||||
|
// tracing pass.
|
||||||
|
rows.push_back({"DUMP_UNDO_TRACE", "DIAG: dump undo trace", &RunDumpUndoTrace});
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
@@ -185,10 +191,15 @@ static void OnTimer()
|
|||||||
if (capture::g_rtCapture) capture::DriveRealtimeCapture(g_session);
|
if (capture::g_rtCapture) capture::DriveRealtimeCapture(g_session);
|
||||||
|
|
||||||
// TEMPORARY: captured in a local (rather than calling GetCurrentProjectInLoadSave()
|
// TEMPORARY: captured in a local (rather than calling GetCurrentProjectInLoadSave()
|
||||||
// twice) so the trace can report the value on every tick, standoff or not, with no
|
// twice) so the trace can report it without a second call, with no change to the
|
||||||
// change to the call below. See undo_trace.h.
|
// call below. See undo_trace.h. Traced only on CHANGE — every tick reads this
|
||||||
|
// regardless of state, and the transition is the whole point of the line.
|
||||||
ReaProject* const loadSaveProj = GetCurrentProjectInLoadSave();
|
ReaProject* const loadSaveProj = GetCurrentProjectInLoadSave();
|
||||||
REASAMPLER_TRACE("[Timer] loadSaveProj=%p", (void*)loadSaveProj);
|
static ReaProject* s_tracedLoadSaveProj = nullptr;
|
||||||
|
if (loadSaveProj != s_tracedLoadSaveProj) {
|
||||||
|
REASAMPLER_TRACE("[Timer] loadSaveProj=%p", (void*)loadSaveProj);
|
||||||
|
s_tracedLoadSaveProj = loadSaveProj;
|
||||||
|
}
|
||||||
|
|
||||||
// A project load or save is IN FLIGHT, so this tick is running inside its own message
|
// A project load or save is IN FLIGHT, so this tick is running inside its own message
|
||||||
// pump — a restore brings plugins online and a plugin load pumps. Everything below
|
// pump — a restore brings plugins online and a plugin load pumps. Everything below
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#define REAPERAPI_MINIMAL
|
#define REAPERAPI_MINIMAL
|
||||||
#define REAPERAPI_WANT_ShowConsoleMsg
|
#define REAPERAPI_WANT_ShowConsoleMsg
|
||||||
@@ -19,7 +20,21 @@ namespace reasampler {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
unsigned long long g_seq = 0;
|
// A few thousand lines comfortably outlasts a full mode switch, its background park
|
||||||
|
// drain, and a mid-drain undo — the exact span the dump has to still hold whole when
|
||||||
|
// fired well after the fact. Static storage: one allocation for the process, none per
|
||||||
|
// line.
|
||||||
|
constexpr std::size_t kCapacity = 4096;
|
||||||
|
constexpr std::size_t kLineChars = 288;
|
||||||
|
|
||||||
|
struct Line {
|
||||||
|
char text[kLineChars];
|
||||||
|
};
|
||||||
|
|
||||||
|
Line g_lines[kCapacity];
|
||||||
|
std::size_t g_next = 0; // next write slot, wraps
|
||||||
|
unsigned long long g_totalWritten = 0; // lines written since the last dump/clear
|
||||||
|
unsigned long long g_seq = 0;
|
||||||
|
|
||||||
double startMs() {
|
double startMs() {
|
||||||
static const double t0 = std::chrono::duration<double, std::milli>(
|
static const double t0 = std::chrono::duration<double, std::milli>(
|
||||||
@@ -38,15 +53,40 @@ double nowMs() {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void undoTrace(const char* fmt, ...) {
|
void undoTrace(const char* fmt, ...) {
|
||||||
char body[256];
|
char body[224];
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
std::vsnprintf(body, sizeof(body), fmt, args);
|
std::vsnprintf(body, sizeof(body), fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
char line[320];
|
Line& line = g_lines[g_next];
|
||||||
std::snprintf(line, sizeof(line), "!SHOW:#%llu %.0fms %s\n", ++g_seq, nowMs(), body);
|
std::snprintf(line.text, sizeof(line.text), "#%llu %.0fms %s\n", ++g_seq, nowMs(), body);
|
||||||
ShowConsoleMsg(line);
|
g_next = (g_next + 1) % kCapacity;
|
||||||
|
++g_totalWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
void undoTraceDump() {
|
||||||
|
const bool overflowed = g_totalWritten > kCapacity;
|
||||||
|
const std::size_t count =
|
||||||
|
overflowed ? kCapacity : static_cast<std::size_t>(g_totalWritten);
|
||||||
|
const std::size_t oldest = overflowed ? g_next : 0;
|
||||||
|
|
||||||
|
std::string out;
|
||||||
|
out.reserve(count * 96 + 128);
|
||||||
|
if (overflowed) {
|
||||||
|
char marker[128];
|
||||||
|
std::snprintf(marker, sizeof(marker),
|
||||||
|
"[UT OVERFLOW: %llu lines dropped, buffer holds %zu]\n",
|
||||||
|
g_totalWritten - kCapacity, kCapacity);
|
||||||
|
out += marker;
|
||||||
|
}
|
||||||
|
for (std::size_t i = 0; i < count; ++i) out += g_lines[(oldest + i) % kCapacity].text;
|
||||||
|
if (out.empty()) out = "[UT] buffer empty\n";
|
||||||
|
|
||||||
|
ShowConsoleMsg(out.c_str());
|
||||||
|
|
||||||
|
g_next = 0;
|
||||||
|
g_totalWritten = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace reasampler
|
} // namespace reasampler
|
||||||
|
|||||||
@@ -3,19 +3,31 @@
|
|||||||
// Ctrl-Z-mid-drain). NOT for shipping. ONE switch below gates every trace line in the
|
// Ctrl-Z-mid-drain). NOT for shipping. ONE switch below gates every trace line in the
|
||||||
// tree; flip REASAMPLER_UNDO_TRACE to 0, or delete this file pair plus the call sites
|
// tree; flip REASAMPLER_UNDO_TRACE to 0, or delete this file pair plus the call sites
|
||||||
// that include it, to revert.
|
// that include it, to revert.
|
||||||
|
//
|
||||||
|
// Lines land in an in-memory ring buffer, never straight to the console — a tick-rate
|
||||||
|
// trace point that called ShowConsoleMsg directly scrolled the console faster than
|
||||||
|
// Daniel could copy the interesting span. "DIAG: dump undo trace"
|
||||||
|
// (shell/actions/action_registry, DUMP_UNDO_TRACE) is the one bindable action that
|
||||||
|
// drains the buffer to the console.
|
||||||
#define REASAMPLER_UNDO_TRACE 1
|
#define REASAMPLER_UNDO_TRACE 1
|
||||||
|
|
||||||
#if REASAMPLER_UNDO_TRACE
|
#if REASAMPLER_UNDO_TRACE
|
||||||
|
|
||||||
namespace reasampler {
|
namespace reasampler {
|
||||||
|
|
||||||
// Emits one line via ShowConsoleMsg: "UT#<seq> <ms>ms <fmt...>\n", "!SHOW:"-prefixed so
|
// Appends one line to the ring buffer: "#<seq> <ms>ms <fmt...>\n". printf-style;
|
||||||
// a trace point on a background tick never forces the console open. printf-style;
|
|
||||||
// sequence number and a monotonic millisecond timestamp are stamped here so lines sort
|
// sequence number and a monotonic millisecond timestamp are stamped here so lines sort
|
||||||
// and date themselves even pasted back out of order. Keep each `fmt` short — this has to
|
// and date themselves however the buffer is later drained. No ShowConsoleMsg call here
|
||||||
// read at a glance in REAPER's console.
|
// — that is what kept this off the reentrancy risk a tick-rate console write posed.
|
||||||
|
// Keep each `fmt` short — this has to read at a glance once dumped.
|
||||||
void undoTrace(const char* fmt, ...);
|
void undoTrace(const char* fmt, ...);
|
||||||
|
|
||||||
|
// Dumps the whole buffer to the console in ONE ShowConsoleMsg call, oldest line
|
||||||
|
// first, then clears it. If the buffer wrapped since the last dump, the dump is
|
||||||
|
// prefixed with a marker naming how many lines were lost rather than dropping them
|
||||||
|
// silently.
|
||||||
|
void undoTraceDump();
|
||||||
|
|
||||||
} // namespace reasampler
|
} // namespace reasampler
|
||||||
|
|
||||||
#define REASAMPLER_TRACE(...) ::reasampler::undoTrace(__VA_ARGS__)
|
#define REASAMPLER_TRACE(...) ::reasampler::undoTrace(__VA_ARGS__)
|
||||||
|
|||||||
Reference in New Issue
Block a user