Native App Footprint
c1382026-11-12 · every strobe reading, c1 to c5What the native app costs a machine: its binary, its memory and its CPU, measured with strobe at every phase from the spike to c5. It leads with c138 Phase 0, the developer-mode gate, for the team and for the Rust engineer who reviews it.
Each value is a reading as recorded, never an average. Where a state was read twice, both readings are drawn. The marks and footnotes are the records' own; the table at the end holds every value with its recording. The readings come from the Footprint section of qnative's README and the write-ups it points to; the dashed lines are the working targets (c131 D22).
The developer-mode gate
Phase 0 moved the developer pages behind a Cargo feature, dev, so the default build is lean. Four states were read: the lean build; the full build with developer mode not allowed; the full build with it on and nothing opened; the full build with the Components page shown.
Showing a page costs more than carrying its code.
Binary: the full build is the lean build plus the dev feature
The full build is 24,302,656 bytes. Without the feature, 23,230,096. The build before Phase 0 (7468f9c) was 24,218,976 bytes.
Memory at rest, two readings per state
Physical footprint, the window idle on the first page. The band is the spread of the quiet readings of every state with no Dev page shown (60.3–63.0 MB): the gate moves nothing outside it. Only the Components page does. The hollow readings drew frames during the minute with no input; each state also has a quiet one.
lean, then the full build: not allowed, on with nothing opened, Components shown
the full build allowed and turned off in the tray, and the build before Phase 0
* The window drew frames during the minute with no input. These read higher; the 77.4 MB is all IOSurface (38 against 25 MB). Each state also has a quiet reading. † The guide's port was held, so it didn't bind, and the machine's load average was 3.8.
Review stop 0's verdict
The burden test passes on all four lines, so B (a switch plus a lean build) holds as ruled. On CI, the macOS runner passes the lean check at Phase 2's code. Since c6's info panel, the lean build carries one row saying it has no developer mode (ruling 10, b); the check looks for words only devmode carries.
Developer mode on disk, since Phase 0
By review stop 3, with Source and Live Activity built: lean 24.93 MB against full 29.47 MB. Bars from zero.
Source added about 2.9 MB (a guess, not measured: the kit's text input pulling in its editor). Live Activity added 0.65 MB. The lean build is unchanged by it, and the lean check passes.
On CI at Phase 2's code (macOS, run 43111428095): lean 24,931,728 bytes, full 28,820,880.
The app over time
The binary grew with the Inventory section, the Tour stretch and c4's messages, and the lean build sets the developer pages aside. Read on an idle Mac from c2 to Phase 0, the window at rest on the first page stayed between 60.3 and 63.0 MB, except where it drew frames. c4 and c5 were read on a Mac in use; there, Status's landing read higher.
Release binary, by build
MB, bars from zero.
Target for the lean binary: under 32 MB. c1's debug build was 122 MB.
c2's +5.3 MB, as review stop 3 splits it
about 4.2 MB of code and about 1.1 MB of assets (the worlds, fonts and logos).
The Tour stretch: +1.05 MB
23.2 → 24.2 MB, over the stretch that built the native tour and the in-app guide.
c4's slice: +0.99 MB
23.9 → 24.9 MB: the messages crate, its SQLite binding and the notification bindings, the two pages, c5's two pages and c3's stream core together.
Memory at rest, by session
Release builds, the window at rest. Read down a session, not across sessions: c1's two days read 52 and 80 MB on two displays, so a window's memory follows the display before it follows the code. The diamonds were read on a Mac in use.
One reading a day. The spread is the display: GPU surfaces scale with it.
One session, one display: both builds read side by side.
Interleaved with c2's build; the window idle on the overview.
The window on a Studio Display (5120 × 2880); two readings per build.
On a Mac in use: not idle readings. An idle reading of Status is owed.
On a Mac in use, two builds back to back in the pilot world: compare the builds, not the absolutes.
Showing every page: a cache filling once
Showing every page once took the window from 62 to 116 MB. Four repeated walks read 125, 127, 125 and 129 MB: the growth levels off. It is a cache filling once, not a leak; most of it is GPU memory, the atlases GPUI fills the first time it draws a page.
The window after each walk
c2 release, physical footprint, MB, bars from zero.
Where the first walk's +54 MB went
IOSurface and IOAccelerator are GPU memory; heap is the app's own allocations.
Idle after the walk, the window read 116 MB at 0.003% of a core and 0.75 wakes a second. In the Tour stretch, a tour left open on Providers read 91 MB at 0.004% and 0.9 wakes a second.
After the walk, c5 read 106 MB (30021df), 91.0 MB (2c01ebf, the session locked meanwhile) and 92.6 MB (the c2 + c3 Phase 0 binary), on a Mac in use. Leaving Live Activity (Phase 3), memory stays at 95 MB: the allocator and GPUI's atlases keep what the page used.
Target after a full walk: under 128 MB, and back within a minute.
On an idle Mac, CPU and wakes at rest stay near zero
CPU is drawn on the scale it is measured in, one core, so a reading is as wide as its share of that core. Every reading taken at rest on an idle Mac sits at the zero end, including the ones where the window drew frames; the target is under 0.01% of a core. The readings taken on a Mac in use are drawn apart, and so is the one that caught someone using the window, 7%, which shows what activity looks like on this scale.
CPU at rest, on the scale of one core
% of one core over a 60 s recording after a 5 s settle. The track is the whole core. The values column gives each reading as recorded.
c1, c2 and the Tour by the recipe; Phase 0 and Phase 3 under the idle-Mac rule
c4 and c5. Status's landing is the open question below.
Read on a Mac in use, the Status landing read 2.43% of a core and 212 wakes a second for a whole minute (c4), then 1.19% and 3.17% (c5). Untouched, every page read 0.00–0.01 s of CPU over 20 s (ps), and nothing in Status's code asks for frames. The pattern is not understood yet, only bounded; an idle reading is owed before the figure stands.
Wakes at rest, on an idle Mac
Per second, from zero. With the window open the quiet readings stay near one a second; the tray alone wakes less. The readings where the window drew frames read higher. On a Mac in use, Status's landing woke 212 (c4) and up to 332 times a second (c5), and Live Activity under a stream up to 1,061: those are in the table, off this scale.
Live Activity under a stream: the cost is the drawing
The first page that does work while it is open. As first built, it redrew once per arriving batch and cost up to a third of a core, nearly all of it on the main thread. Capped at 4 redraws a second, it costs about a tenth of a core. The stream core alone costs a few percent at most, and leaving the page returns the app to rest.
CPU under a stream, on the scale of one core
The same track as at rest: the whole core. As first built, memory read 107.5, 103.4 and 112.2 MB at 10, 100 and 1,000 a second, and 95.1 MB after leaving; at 4 redraws a second, 105.2, 105.8 and 120.3 MB, and 100.5 MB after leaving.
9d265fb: a redraw per arriving batch
arrivals gathered for 50 ms, rows on screen cached
d3de579, 2026-11-13, 12:03–12:40: arrivals gathered for 250 ms, the firehose in qdash's grammar
ps over every thread for 20 s, the window covered: ingest, presence, the tally and the entity index
‡ Taken while the session's own release build ran, at load 16: the CPU figure is the app's own, but the minute was not clean.
Read on 2026-11-13 (d3de579, review stop 3, call 12): the page now redraws at most 4 times a second, the monitor TUI's cadence, and costs 7.85% and 11.1% of a core at 100 and 1,000 a second, from 27.9% and 33.9%. A redraw costs at least 18–22 ms of main thread (7–9% busy at no more than 4 redraws a second), against about 10 ms on Phase 3's page, which has since been restyled in qdash's grammar (f19e679). If up to 11% of a core is too dear while the page is open, the next step is a cached view for the table.
The same script under caffeinate -d (the screensaver locks this Mac after 10 idle minutes), the window on display 2 as the script records it. One reading at 1,000 a second was touched (rec_b221c5) and taken again.
Method and caveats
The method
- Memory
- strobe's
memory.app.private: the macOS physical footprint, whichfootprint(1)agreed with to the MB. RSS is in the table beside it. - CPU
- The % of one core over a 60 s recording after a 5 s settle. The table adds the CPU time that minute added up to, in ms.
- Wakes
- Per second, over the same recording.
- Startup
- The app's own clock from
mainto the shell's first render. - Machine
- Apple M2 Max (12 cores, 32 GB), macOS 15.6, strobe 0.26.0, Rust 1.99.1, GPUI Kit 0.9.1. Release builds,
QPOINT_DATA=synthetic, the window idle on the first page unless noted. - Idle rule
- From Phase 0 on: a reading counted only after 60 s with no keyboard or pointer input, with no input during it, the display on and the session unlocked. Phase 0's window opened on a Studio Display (5120 × 2880).
- Phase 3
- The full release build with QPOINT_SPIKE_OPEN=/dev/live and a coding-session stream at the rate, the window on the Studio Display; the idle-Mac rule, and a locked screen refused too. The stream core's figures are
psover every thread for 20 s with the window covered, not strobe. - c4 and c5
- Read on a Mac in use, not under the idle rule. c4 read two builds back to back.
The caveats
- Compare readings inside one session. A window's memory follows the display it opens on: c1 read 52 MB on 2026-11-09 and 80 MB on 2026-11-10, and the spread was the display, since GPU surfaces scale with it.
- * marks a reading where the window drew frames during the minute with no input. These read higher; the 77.4 MB is all IOSurface (38 against 25 MB). Each Phase 0 state also has a quiet reading.
- † marks the reading where the guide's port was held, so it didn't bind, and the machine's load average was 3.8.
- ‡ Phase 3's reading at 10 a second: taken while the session's own release build ran, at load 16: the CPU figure is the app's own, but the minute was not clean. That build has no rest reading; six attempts were all touched.
- Each Phase 0 state was read twice. The page shows both readings, not an average, so the launch-to-launch spread stays in view.
- Read on a Mac in use, the Status landing read 2.43% of a core and 212 wakes a second for a whole minute (c4), then 1.19% and 3.17% (c5). Untouched, every page read 0.00–0.01 s of CPU over 20 s (ps), and nothing in Status's code asks for frames. The pattern is not understood yet, only bounded; an idle reading is owed before the figure stands.
- c2's binary split is approximate, as recorded: about 1.1 MB of assets and about 4.2 MB of code.
- The Tour stretch's readings were taken interleaved with c2's build, idle on the overview. One reading caught someone using the window: 127 MB at 7% of a core.
- The working targets are proposals with the force of a working rule: c131 D22 (G1, 2026-11-11) made shape.md §6's V1 targets the working targets until G2, where Tyler sets them.
- The charts show release builds. c1's debug build (a 122 MB binary) is in the table.
- · Window open, idle: under 80 MB per display
- · Tray only, idle: under 25 MB
- · After a full walk: under 128 MB, and back within a minute
- · Idle CPU: under 0.01% of a core
- · First render: under 400 ms warm
- · Lean binary: under 32 MB
- · Nothing resident when quit
c131 D22 (G1, 2026-11-11) made shape.md §6's V1 targets the working targets until G2, where Tyler sets them.
- Status at rest and after the walk, on an idle Mac (c5 review-1). If Status reads busy then, a frame-request trace is next.
- Every reading here is macOS on one M2 Max. The method records them per OS at each release (shape.md §6).
- · Readings taken while the Mac was in use: 145 MB at 3.9%; then 111.5, 100.7, 93.8 and 62.4 MB at 0.05–1.7%.
- · One launch that quit by itself after 10 s (unexplained).
- · One reading overlapped by a second app window.
The gate (a switch plus a lean build) is a working decision, recorded for a Rust expert to review; they may take a different course for other reasons (c138 ruling 1). These readings are what the review is shown. The plan's gate section →
Every reading
The charts' table: each value as recorded, with its strobe recording, grouped by write-up. Private and RSS in MB; CPU in % of one core, with the CPU time in ms in brackets; wakes per second. * the window drew frames; † the guide's port was held and the load average was 3.8; ‡ the minute was not clean.
c3 · c138 Phase 0
2026-11-11, 09:10–09:36, two interleaved rounds| Build or state | Private | RSS | CPU % (ms) | Wakes /s | First render ms | Binary | Recording |
|---|---|---|---|---|---|---|---|
1. Lean the default build | 61.6 | 75.6 | 0.0055 (3.3) | 0.95 | 260 | 23,230,096 B | rec_dbdd02 |
| 63.0 | 77.4 | 0.0042 (2.5) | 0.90 | 277 | rec_2ca89b | ||
2. Full, not allowed developer mode not allowed | 77.4* | 79.2 | 0.033* (19.8) | 2.73* | 257 | 24,302,656 B | rec_1cc0a8 |
| 61.0 | 76.2 | 0.0037 (2.2) | 0.98 | 266 | rec_fe426c | ||
3. Full, on nothing opened | 63.0*† | 77.5 | 0.022* (13.3) | 2.78* | 416† | rec_0773d9 | |
| 61.5 | 76.0 | 0.0046 (2.8) | 1.27 | 279 | rec_15ab21 | ||
4. Full, Components shown a Dev page on screen | 65.3 | 80.4 | 0.0049 (3.0) | 1.18 | 265 | rec_fc1c72 | |
| 65.0 | 81.0 | 0.0050 (3.0) | 0.92 | 297 | rec_1219d3 | ||
Full, allowed, turned off turned off in the tray | 62.8 | 77.4 | 0.0039 (2.3) | 0.92 | 291 | rec_f9bf3c | |
| 61.8 | 75.9 | 0.0061 (3.7) | 0.87 | 276 | rec_e612b3 | ||
Before Phase 0 the build before the gate, 7468f9c | 60.3 | 75.7 | 0.0022 (1.3) | 0.90 | 282 | 24,218,976 B | rec_5055de |
| 63.0* | 77.0 | 0.040* (24.1) | 4.31* | 284 | rec_1e5df4 |
c3 · Phase 3, Live Activity under a stream
2026-11-11, 17:00–17:40CPU with the main thread's share after it. The last column is the thread count. The stream core's figures are ps, not strobe.
| Build or state | Private | RSS | CPU % (ms) | Wakes /s | Threads | Binary | Recording |
|---|---|---|---|---|---|---|---|
9d265fb, 10 a second ‡ | 107.5 | — | 5.67 · main 5.18 | 269 | 8 | rec_782642 | |
9d265fb, 100 a second | 103.4 | — | 27.9 · main 26.1 | 1,061 | 8 | rec_a281d8 | |
9d265fb, 1,000 a second | 112.2 | — | 33.9 · main 31.7 | 1,047 | 8 | rec_f7f4b0 | |
9d265fb, left after 30 s at 1,000 a second | 95.1 | — | 0.003 · main 0.00 | 0.8 | 6 | rec_a770fa | |
second build (50 ms gather), 10 a second load 2.8 | — | — | 10.4 · main 9.6 | — | — | rec_0ca212 | |
second build, at rest | 73.7 | — | 0.006 | 1.1 | — | rec_ee3c1d | |
stream core alone (ps, 20 s, window covered) at 10, 100 and 1,000 a second | — | — | 0.60 · 1.70 · 7.05 | — | — | ||
d3de579 (at most 4 redraws a second), at rest 2026-11-13, 12:03–12:40 | 73.5 | — | 0.005 | 1.0 | 12 | rec_0d34ab | |
d3de579, 10 a second | 105.2 | — | 8.90 · main 8.14 | 408 | 14 | rec_64666d | |
d3de579, 100 a second | 105.8 | — | 7.85 · main 7.07 | 611 | 14 | rec_5f1de7 | |
d3de579, 1,000 a second | 120.3 | — | 11.1 · main 8.99 | 364 | 14 | rec_1a2333 | |
d3de579, left after 30 s at 1,000 a second | 100.5 | — | 0.003 · main 0.00 | 0.7 | 12 | rec_d6ca86 |
c5 · Status as the landing
2026-11-11, 13:15–13:40, on a Mac in useOn a Mac in use; the two Status rows were taken with Mark at the Mac. The binary is 24.9 MB.
| Build or state | Private | RSS | CPU % (ms) | Wakes /s | First render ms | Binary | Recording |
|---|---|---|---|---|---|---|---|
30021df, Status at rest | 66.4 | — | 1.19 (715) | 99.8 | 328 | rec_b897d6 | |
30021df, after the walk, on the overview | 106 | — | 0.09 | 7.6 | 357 | rec_fe807d | |
2c01ebf, Status at rest | 108 | — | 3.17 (1.9 s) | 332 | 408 | rec_0b5f88 | |
2c01ebf, after the walk; the session locked meanwhile | 91.0 | — | 0.01 | 2.5 | 336 | rec_458dee | |
the c2 + c3 Phase 0 binary, on its overview | 63.5 · 92.6 after the walk | — | 0.06 · 0.002 | 10.3 · 0.85 | 706 · 324 | rec_da95fa · rec_6a077e |
c4 · the messaging slice
2026-11-11, on a Mac in use, the pilot worldTwo builds read back to back: compare the builds, not the absolutes. The slice build opened on its landing, Status. Binaries: before 23.9 MB, the slice 24.9 MB.
| Build or state | Private | RSS | CPU % (ms) | Wakes /s | footprint(1) | Binary | Recording |
|---|---|---|---|---|---|---|---|
273ada7 (before), window, overview | 62.2 | 76 | 0.002 (1.20) | 0.83 | 62 | rec_1d0efa | |
2c01ebf (the slice), window, overview | 83.3 | 88 | 2.43 (1456) | 212 | 83 | rec_f10f1b | |
2c01ebf, window, Inbox (ten messages) | 63.5 | 79 | 0.15 (90.3) | 25.9 | 64 | rec_aba199 | |
273ada7 (before), tray only | 23.3 | 47 | 0.003 (1.85) | 0.88 | 23 | rec_25b5b5 | |
2c01ebf, tray only (four waiting) | 23.0 | 48 | 0.01 (3.04) | 0.73 | 23 | rec_d700fd | |
2c01ebf, window, Inventory overview (second round) | 68.5 | — | 0.06 (34.3) | 6.39 | 69 | rec_088645 | |
2c01ebf, window, Inbox (second round) | 61.8 | — | 0.02 (12.6) | 2.96 | 62 | rec_fa9be6 |
The Tour stretch
2026-11-11, interleaved with c2's build| Build or state | Private | RSS | CPU % (ms) | Wakes /s | Startup ms | Binary | Recording |
|---|---|---|---|---|---|---|---|
c2, window idle on the overview | 62.9 | — | 0.006 | 1.2 | — | 23.2 MB | rec_c37e45 |
Tour, window idle on the overview | 63.0 | — | 0.007 | 1.1 | — | 24.2 MB (+1.05) | rec_29b1ad |
Tour, a tour open on Providers, idle | 91 | — | 0.004 | 0.9 | — | rec_36b9a3 | |
Not at rest: someone using the window | 127 | — | 7 | — | — |
c2 · review stop 3
2026-11-10, one session, one display| Build or state | Private | RSS | CPU % (ms) | Wakes /s | Startup ms | Binary | Recording |
|---|---|---|---|---|---|---|---|
c1 release, window | 51 | 62 | 0.005 (3.0) | 0.88 | 262 (257, 262, 277) | 17.9 MB | rec_efd19b |
c2 release, window, first page | 62 | 76 | 0.005 (2.9) | 0.90 | 254 (247, 254, 266) | 23.2 MB | rec_1e4cd5 |
c2 release, after every page shown once | 116 | 91 | 0.003 (1.9) | 0.75 | — | rec_b2e442 | |
c2, four repeated walks | 125, 127, 125, 129 | — | — | — | — | ||
c1 release, tray only | 15 | 38 | 0.002 (1.5) | 0.32 | — | rec_141fce | |
c2 release, tray only | 21 | 45 | 0.003 (1.8) | 0.45 | — | rec_6ab80f |
c1 · the spike
2026-11-09 and 11-10Startup is the median of three cold starts.
| Build or state | Private | RSS | CPU % (ms) | Wakes /s | Startup ms | Binary | Recording |
|---|---|---|---|---|---|---|---|
Release, window | 52 (11-09) · 80 (11-10) | 66–68 | 0.005 (2.9) | 0.9 | 264 | 17.9 MB | rec_cdfcb0 |
Release, tray only | 16 | 39 | 0.002 (1.2) | 0.3 | — | 17.9 MB | rec_2b2d45 |
Debug, window | 80 | 83 | 0.005 (2.8) | 1.2 | 270 | 122 MB | rec_79dba9 |
Debug, tray only | 16 | 51 | 0.002 (1.1) | 0.3 | — | 122 MB | rec_deabd6 |
The records
- c138 Developer Mode →the cycle record; Phase 0 is the gate
- The plan →the gate, the four states, ruling 1
- The Guide, page 7: footprint →the recipe, for Kamal
- qnative c2, review stop 3 →the Inventory section and its budget
- qnative c2, the Tour stretch →the tour engine and the guide
- qnative c3, review stop 0 →Phase 0: every reading, the burden test, the expert's eight questions
- qnative c3, review stop 3 →Phase 3: Live Activity under a stream, developer mode on disk
- qnative c4, review stop 1 →the messaging slice, read on a Mac in use
- qnative c5, review stop 1 →Status as the landing, and what is owed
- c130 shape.md, § 6 the budget →the targets c131 D22 made the working ones
- c131 Native App V1 →R7: the budget is measured, not promised