perf: stop per-frame SQLite writes and console spam, make perf.log opt-in

- Explorer: the tip check runs every frame the Explorer tab is open,
  and it read both tip rows and rewrote them each time (two autocommit
  WAL writes per frame). A steady tip is now kept in memory and skips
  SQLite. A new tip writes both rows in one savepoint, so a crash
  between them can't pair a new height with the old hash. A test
  checks that 100 steady checks write nothing.
- Console: while the daemon was in the Error state the Console tab
  added its error line on every poll, i.e. every frame, re-laying out
  the whole buffer each time. It prints once per error now: on entering
  Error, when the message changes, or after another crash
  (EmbeddedDaemon::getUnexpectedExitCount(), never reset). setState
  writes the message before the state, so a reader that sees Error sees
  that error's message. The stray " ===" suffix is gone.
- perf.log: the profiler appended a block every 300 frames on every
  run and never rotated the file (tens of MB a day for a wallet left
  open). It is now off unless the app starts with DRAGONX_PERFLOG=1;
  otherwise its zone hooks are near no-ops.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 19:52:09 -05:00
co-authored by Claude Opus 5.5
parent 2d29a04981
commit 16e0ee9947
11 changed files with 116 additions and 17 deletions
+11 -1
View File
@@ -6,6 +6,7 @@
#include "console_channel.h"
#include "console_command_reference.h" // consoleCommandCategories / liteConsoleCommandCategories
#include "console_input_model.h" // BuildConsoleRpcCall
#include "console_tab_helpers.h" // ShouldPrintDaemonErrorLine
#include "../../app.h"
#include "../../data/wallet_state.h"
@@ -126,7 +127,16 @@ void FullNodeConsoleExecutor::pollLogLines(const ConsoleAddLineFn& add)
add("", ConsoleChannel::None);
add(TR("console_daemon_stopped"), ConsoleChannel::Info);
} else if (cur == DState::Error) {
add(std::string(TR("console_daemon_error")) + d->getLastError() + " ===", ConsoleChannel::Error);
// Once per error (see ShouldPrintDaemonErrorLine): printing on every poll added a line per
// frame and made the console re-lay-out its whole buffer each time.
std::string err = d->getLastError();
const std::uint64_t exits = d->getUnexpectedExitCount();
if (ShouldPrintDaemonErrorLine(prev == static_cast<int>(DState::Error), true, err, last_daemon_error_,
exits != last_printed_exit_count_)) {
add(std::string(TR("console_daemon_error")) + " " + err, ConsoleChannel::Error);
last_daemon_error_ = std::move(err);
last_printed_exit_count_ = exits;
}
}
last_daemon_state_ = static_cast<int>(cur);
}