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:
2026-09-01 22:55:04 -05:00
co-authored by Claude Opus 4.8
parent 0a042df8e0
commit d9fa00bb38
9 changed files with 238 additions and 104 deletions
+9
View File
@@ -15,6 +15,7 @@
#include "../../rpc/rpc_client.h"
#include "../../rpc/rpc_worker.h"
#include <cstdint>
#include <string>
#include <vector>
#include <deque>
@@ -188,6 +189,14 @@ private:
bool has_text_filter_ = false; // computed once per frame (before the toolbar draws it)
std::string filter_lower_; // lowercased filter needle for match highlighting
// Memoization keys so the two expensive per-frame passes rebuild only on change (not every frame):
// computeVisibleLines (filter scan over the whole model) is keyed on the model revision + filter
// state; BuildConsoleLayout (glyph-by-glyph text shaping of every visible line) is keyed on the
// resulting visible-set generation + wrap width + line height/zoom.
std::uint64_t vis_key_ = ~0ull; // key of the last computeVisibleLines
std::uint64_t vis_generation_ = 0; // bumped whenever visible_indices_ is rebuilt
std::uint64_t layout_key_ = ~0ull; // key of the last BuildConsoleLayout
// Wrap layout for the visible lines (segments + per-line heights + cumulative Y),
// recomputed each frame by the pure BuildConsoleLayout (console_text_layout.h) and
// consumed by the renderer + hit-testing.