Skip to content

perf(gpui): keep the profiler journal ring out of memory until it is written - #11

Draft
rubnogueira wants to merge 1 commit into
remorses:gpuixfrom
rubnogueira:perf/lazy-profiler-journal
Draft

rubnogueira wants to merge 1 commit into
remorses:gpuixfrom
rubnogueira:perf/lazy-profiler-journal

Conversation

@rubnogueira

Copy link
Copy Markdown

Summary

The profiler journal is installed in every App, but only Zed's hang detection reads it. An embedder that never reads it (GPUIX does not) still paid for the whole 4 MiB ring: empty slots carried a non-zero sentinel sequence, so allocating the ring wrote every slot and the operating system backed every page at startup.

A slot now stores its published sequence plus one, so an empty slot is all zeros, and the ring is allocated with new_zeroed_slice. Pages become resident as entries are first written, so a process that records a few entries touches a few pages.

One file, crates/gpui/src/profiler/journal.rs. The sequence numbers the rest of the module sees are unchanged: only the stored value is offset, and try_publish and try_read apply the offset on both sides.

Notes

Test plan

  • cargo test -p gpui --features profiler,test-support journal: 23 passed. The journal tests are gated behind those features, so without them zero tests run. This ran on the previous gpuix tip; the merge of feat(gpui): list padding on all sides, averaged scroll extent, hover exit, font lookup fix #10 did not touch crates/gpui/src/profiler/, so the code under test is identical.
  • In a GPUIX window the process footprint dropped by about 4 MB, the size of the ring.
  • Not re-run on 3db1867 itself, and not measured outside macOS.

Authored with Claude (Claude Sonnet 5.5) in Cursor.

…written

The journal is installed in every App, but only Zed's hang detection reads it.
An embedder that never reads it still paid for the whole 4 MiB ring: empty slots
carried a non-zero sentinel sequence, so allocating the ring wrote every slot and
the operating system backed every page at startup.

A slot now stores its published sequence plus one, so an empty slot is all zeros
and the ring is allocated with `new_zeroed_slice`. Pages become resident as
entries are first written, and a process that records a few entries touches a few
pages.
knoopx pushed a commit to knoopx/zed that referenced this pull request Oct 19, 2026
)

When atlas tiles are rapidly allocated and freed (e.g. watching a shared
screen in Collab), a texture can become unreferenced and be removed
while GPU uploads for it are still pending. On the next frame,
`flush_uploads` indexes into the now-empty texture slot and panics:

```
  thread 'main' panicked at crates/gpui_wgpu/src/wgpu_atlas.rs:231:40:
  texture must exist...

  remorses#11 core::option::expect_failed
  remorses#12 gpui_wgpu::wgpu_atlas::WgpuAtlas::before_frame
  remorses#13 gpui_wgpu::wgpu_renderer::WgpuRenderer::draw
```

This change drains pending uploads for a texture when it becomes
unreferenced in `remove`, and skips uploads for missing textures in
`flush_uploads` as a safety net.

Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable


Release Notes:

- Fixed occasional crashes when viewing a screen share
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant