perf: memoize per-frame render hot paths (console, transactions, recent lists)
Immediate-mode render functions re-run every frame; these rebuilt O(N) state each time even when nothing changed. From a 6-lens perf audit, each finding verified on a hot-path basis: - Console: ConsoleModel gains revision(); the full-model filter scan and the glyph-by-glyph text-layout pass (BuildConsoleLayout) rebuild only when the model / filter / wrap-width / zoom change — previously it re-shaped up to 10,000 lines every frame even when idle/scrolled. clear() force-invalidates the memo mid-render (no OOB on the just-emptied visible set). - Transactions: the summary-card totals memoize behind the tab's existing FNV-1a fingerprint (also folds away a now-duplicate O(N) display-key pass). - Send / Receive recent lists: early-exit the prefix scan (state.transactions is kept newest-first) instead of filtering the whole tx history every frame. - network_refresh_service: O(new x total) txid find-and-replace -> hash map. - Sidebar unconfirmed-tx badge cached on last_tx_update + tx count; the daemon-memory probe (/proc scan on Linux, popen on macOS) throttled to ~1.5s. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+20
-5
@@ -1806,7 +1806,10 @@ void App::render()
|
||||
// long confirmed (the other leg holds the real count). So: a txid with ANY confirmed leg is
|
||||
// confirmed, and we count UNIQUE unconfirmed txids — otherwise the badge sticks on stale 0-conf
|
||||
// legs of already-confirmed transactions and double-counts multi-leg ones.
|
||||
{
|
||||
// Recompute only when the tx list actually changed (last_tx_update is bumped on every tx refresh;
|
||||
// size() catches same-second content changes). Otherwise this built two unordered_sets over the whole
|
||||
// wallet tx list every frame just to size a badge.
|
||||
if (state_.last_tx_update != sb_unconf_key_ts_ || state_.transactions.size() != sb_unconf_key_n_) {
|
||||
std::unordered_set<std::string> confirmedTxids;
|
||||
for (const auto& tx : state_.transactions) {
|
||||
if (tx.confirmations >= 1) confirmedTxids.insert(tx.txid);
|
||||
@@ -1817,8 +1820,11 @@ void App::render()
|
||||
unconfirmedTxids.insert(tx.txid);
|
||||
}
|
||||
}
|
||||
sbStatus.unconfirmedTxCount = static_cast<int>(unconfirmedTxids.size());
|
||||
sb_unconf_count_ = static_cast<int>(unconfirmedTxids.size());
|
||||
sb_unconf_key_ts_ = state_.last_tx_update;
|
||||
sb_unconf_key_n_ = state_.transactions.size();
|
||||
}
|
||||
sbStatus.unconfirmedTxCount = sb_unconf_count_;
|
||||
|
||||
// Sidebar minimum height from ui.toml schema (DPI-scaled).
|
||||
const float sbMinHeight = sbde("min-height", 360.0f);
|
||||
@@ -5695,17 +5701,26 @@ bool App::stopDaemonForBootstrap()
|
||||
|
||||
double App::getDaemonMemoryUsageMB() const
|
||||
{
|
||||
// The Mining tab reads this every frame, but the probe is expensive (Linux embedded/external paths
|
||||
// scan /proc; macOS forks a shell). Throttle to ~1.5s so a 60Hz caller doesn't hammer the OS.
|
||||
const double now = ImGui::GetTime();
|
||||
if (daemon_mem_probe_at_ > 0.0 && now - daemon_mem_probe_at_ < 1.5)
|
||||
return daemon_mem_cached_mb_;
|
||||
daemon_mem_probe_at_ = now;
|
||||
|
||||
double result = 0.0;
|
||||
// If we have an embedded daemon with a tracked process handle, use it
|
||||
// directly — more reliable than a process scan since we own the handle.
|
||||
if (daemon_controller_ && daemon_controller_->isRunning()) {
|
||||
double mb = daemon_controller_->memoryUsageMB();
|
||||
daemon_mem_diag_ = "embedded";
|
||||
if (mb > 0.0) return mb;
|
||||
result = (mb > 0.0) ? mb : util::Platform::getDaemonMemoryUsageMB();
|
||||
} else {
|
||||
daemon_mem_diag_ = "process scan";
|
||||
result = util::Platform::getDaemonMemoryUsageMB(); // external daemon
|
||||
}
|
||||
// Fall back to platform-level process scan (external daemon)
|
||||
return util::Platform::getDaemonMemoryUsageMB();
|
||||
daemon_mem_cached_mb_ = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user