Skip to content

bug(desktop): Settings Usage can hang after selecting the All range #5019

Closed

Description

@Sun-GLiang

What happened

When running Desktop from the latest main, opening Settings → Usage and changing the time range to All can make the application completely unresponsive with an existing local Usage history.

The Usage page stops responding and does not recover within the observed time. Command+Q also does not cause the Electron application to exit. I have to return to the terminal and manually kill the Electron processes.

Expected behavior:

  • Selecting All should keep the Desktop responsive while Usage data is loading.
  • The page should present a loading, partial, or paginated state rather than materializing an unbounded activity history.
  • The application should remain possible to quit while a Usage query is running.

How to reproduce

  1. Build and run Desktop from commit 5a1514c1d on main.
  2. Use an existing local profile containing accumulated model-call and tool-usage history.
  3. Open Settings.
  4. Select Usage.
  5. Change the time range to All.
  6. Observe that the Usage page and application become unresponsive.
  7. Press Command+Q.
  8. Observe that the Electron application remains running.
  9. Kill the Electron processes manually from the terminal.

The issue appears to depend on the amount of accumulated Usage data. I have not yet reduced it to an exact record-count threshold or reproduced it with a clean profile.

Environment

  • Maka version or commit: 5a1514c1d
  • Branch: main
  • OS and version: macOS 15.6 (24G84), arm64
  • Surface: Desktop, running from source
  • Node.js version: v24.19.0
  • npm version: 11.17.0

Logs, screenshots, or additional context

This report is related to the same Settings → Usage read path as #4058 and #4068, but the observed defect is different:

Initial static investigation of main found the following potential amplification path:

  1. loadUsageStats() loads the summary, all LLM activity, all tool activity, and pricing together.
  2. Activity is paged in protocol frames of 100 records, but Desktop continues requesting pages until it has accumulated the complete activity set, capped at 50,000 LLM rows and 50,000 tool rows.
  3. The current SQLite Usage reader materializes, JSON-decodes, filters, and sorts the matching range before applying slice(offset, offset + limit), so each protocol page can repeat work over the full range.
  4. Desktop then merges, aggregates, and sorts the accumulated arrays.
  5. When request details are displayed, renderer code maps the complete activity array into a non-paginated/non-virtualized table.

Relevant paths:

  • apps/desktop/src/main/runtime-host-usage-ipc-main.ts
  • apps/desktop/src/renderer/features/usage/ui/usage-settings-view.tsx
  • apps/desktop/src/renderer/features/usage/ui/usage-stats-table.tsx
  • packages/storage/src/sqlite-usage-store.ts
  • packages/runtime-host/src/protocol/usage-pricing.ts

The current implementation in #4068 may reduce repeated Storage scans and serialize overlapping range reloads, but it still:

  • captures up to 50,000 LLM rows and 50,000 tool rows into a Host memory snapshot;
  • pages both snapshots to Desktop until the arrays are complete;
  • aggregates all returned rows in Desktop main;
  • can pass the complete activity array to the renderer table.

For that reason, #4068 may mitigate this reproduction but does not appear to establish a bounded end-to-end read or render path.

The P1 design proposed in the final #4068 review appears relevant to this defect:

  • return summary and SQL GROUP BY projections with only the first bounded activity page in one Storage transaction;
  • fetch later activity pages on demand using a stable (ts, id)-style cursor;
  • stamp pages with a Usage revision and return revision_changed for stale continuations;
  • use hasMore instead of traversing the full data set to compute or transfer an exact total;
  • keep the Runtime Host stateless rather than retaining a full in-memory activity snapshot;
  • render only a bounded page of activity rows.

Related:

Additional evidence that would be useful but has not yet been collected:

  • model-call and tool-invocation row counts for the affected profile;
  • Activity Monitor CPU and memory observations;
  • a macOS Sample Process capture while the application is stuck;
  • whether request details were enabled at the time of reproduction;
  • comparison with a clean profile and with the 24h, 7d, and 30d ranges.

Activity

  1. Sun-GLiang commented on Sep 8, 2026

    @Sun-GLiang
    MemberAuthor

    take

  2. Sun-GLiang commented on Sep 8, 2026

    @Sun-GLiang
    MemberAuthor

    Live CPU, memory, and stack sampling during the reproduced hang

    Captured while the reported Settings → Usage → All hang was still present. This supplies the process-resource observations and macOS sampling evidence listed as missing in the issue.

    Environment and collection

    • Sampling window: 2026-09-08 16:40:52–16:41:16 UTC+08:00 (initial process inspection immediately before this window).
    • macOS 15.6 (24G84), arm64; Electron 43.4.1.
    • Workspace HEAD at collection: 5a1514c1d43894691186174cc0683e0b6fd88f53. The running build artifacts were not independently verified against that source commit.
    • Read-only observations using ps, repeated top samples, sample, vm_stat, and sysctl vm.swapusage. No processes were terminated or restarted, and no application code was changed during collection.

    Process observations

    Process PID Observed CPU Resident memory (RSS) Memory footprint
    Maka page renderer 99781 Initially ~194.4%; subsequent observations ~99–116% ~2.8–2.9 GiB ~4.2–4.4 GB
    Electron main 99755 Approximately 0% ~93–106 MiB ~249 MB
    Runtime Host execution candidate 99769 Approximately 0% ~45–54 MiB ~270 MB

    CPU of 100% corresponds approximately to one logical core. RSS and footprint are different memory-accounting measures and should not be interpreted as consecutive measurements of the same metric.

    Successive top observations reported renderer memory of 4,231 MB → 4,251 MB → 4,373 MB over several seconds. The renderer remained busy and its memory was still increasing during observation; this alone does not establish a memory leak. A subsequent sample report recorded a peak footprint of approximately 4.4 GB.

    System-wide observations

    • Approximately 15 GB physical memory used.
    • Approximately 7 GB occupied by compressed memory.
    • Approximately 10 GB swap used.
    • Approximately 66–71% aggregate CPU idle during the top samples.

    These are system-wide figures, not memory or swap attributable exclusively to Maka. The observations show a busy renderer and substantial memory usage rather than exhaustion of all CPU cores.

    Stack-sampling observations

    • The renderer main thread remained in V8/JavaScript execution paths. Native samples contained repeated unsymbolicated frames, so they do not identify the responsible JavaScript function or establish an infinite loop.
    • Electron main spent most samples waiting in the macOS event loop.
    • Runtime Host spent most samples waiting for I/O in its Node/libuv event loop.

    Interpretation and limits

    The sustained activity at the time of capture was concentrated in the renderer, while Electron main and Runtime Host were largely idle. This makes renderer-side data processing, component updates, and activity-table rendering the next profiling targets. It does not rule out expensive Host/Storage work earlier in the load.

    The user also reported that Command+Q did not exit the application, but this sampling does not establish why quitting failed.

    The evidence is relevant to the bounded-read and bounded-render direction discussed in #4068, but it does not yet prove that full-history loading is the root cause or that the proposed redesign alone resolves this hang. A JavaScript CPU profile is still needed to locate the hot path. Exact record counts, request-details visibility, and clean-profile/range comparisons remain unverified.

    AI assistance: Codex collected and summarized the process observations at the reporter's request; the reporter reproduced the hang.

  3. Astro-Han commented on Sep 17, 2026

    @Astro-Han
    Contributor

    @Sun-GLiang could you re-test this on current main? The amplification path described here has since changed: #5387 (c980b93a3) made the Usage screen read statistics, breakdowns, pricing and the first activity page in one SQLite transaction behind a revision-fenced keyset cursor, and #4539 (f2b6066a6) limits activity rendering to 50 records per page, so the 50,000-row accumulation in Desktop main no longer exists in production code. Neither change was made against this report, so the All-range hang has not been confirmed fixed. If it no longer reproduces on your existing profile we can close this.

  4. Sun-GLiang commented on Sep 18, 2026

    @Sun-GLiang
    MemberAuthor

    Rechecked current main against my existing Usage profile (6,544 activity records): the All-range query completes and returns a bounded 50-row first page. The original unbounded loading and rendering path has been resolved by #5387 and #4539. Closing this issue as fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions