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
+3
View File
@@ -37,18 +37,21 @@ ConsoleModel::DrainResult ConsoleModel::drain()
lines_.pop_front();
++result.popped;
}
++revision_; // deque changed — lets the view memoize its filter/layout passes
return result;
}
void ConsoleModel::clear()
{
lines_.clear();
++revision_;
}
bool ConsoleModel::toggleCollapsed(std::size_t i)
{
if (i >= lines_.size() || lines_[i].foldSpan <= 0) return false;
lines_[i].collapsed = !lines_[i].collapsed;
++revision_; // fold change alters which lines are visible
return lines_[i].collapsed;
}