Skip to content

Productionize Linux jemalloc heap profiling#12265

Merged
kevinyang372 merged 3 commits into
masterfrom
kevin/linux-heap-profiling
Jun 8, 2026
Merged

Productionize Linux jemalloc heap profiling#12265
kevinyang372 merged 3 commits into
masterfrom
kevin/linux-heap-profiling

Conversation

@kevinyang372

@kevinyang372 kevinyang372 commented Jun 5, 2026

Copy link
Copy Markdown
Member

Description

Productionizes automatic jemalloc heap profiling on Linux so high-memory events upload a heap profile to Sentry, matching what macOS already does.

The key difference from macOS: the Linux profile is uploaded unsymbolized (raw pprof). It carries sample addresses + memory mappings + the GNU build-id, and is symbolized offline against the debug-info file (DIF) the release pipeline already uploads to Sentry — the same artifact used to symbolize panics, matched by build-id. This lets the shipped binary stay fully stripped (no symbol-table bloat) while still producing usable, symbolizable profiles.

What changed

  • app/src/profiling.rs: on Linux, dump the gzipped pprof in-process via jemalloc_pprof (dump_jemalloc_pprof_bytes) — no external pprof binary, HTTP server, or fixed port (essential for the headless remote-server daemon). The dump is now raw / unsymbolized. The external-pprof path is kept for macOS, where in-process symbolization stays.
  • app/Cargo.toml: build jemalloc_pprof without the symbolize feature, so dump_pprof() returns a raw profile instead of symbolizing in-process (in-process symbolization would have required keeping the symbol table in the shipped binary).
  • Cargo.lock: bump jemalloc_pprof / pprof_util to 0.8.2. This is required: 0.8.2 writes a usable mapping range (memory_limit = u64::MAX), whereas 0.8.1 wrote memory_limit = 0, leaving pprof unable to bind sample addresses to the binary — so profiles would be unsymbolizable even with the correct DIF. (See this PR: Use max limit in mappings polarsignals/rust-jemalloc-pprof#31)
  • script/linux/bundle: enable jemalloc_pprof,heap_usage_tracking for the dev and preview channels, and keep the normal strip behavior (--strip-all for non-dev builds). The shipped binary stays small; symbols live only in the uploaded DIF.

Symbolizing a Linux heap profile (offline, via the Sentry DIF)

The release pipeline already uploads each build's debug-info file to Sentry (script/sentry_upload_dif.sh), keyed by GNU build-id. To analyze a heap-profile.pb from an "Excessive memory usage detected" event:

# 0. Use the standalone pprof (the Go-bundled `go tool pprof` misreads the
#    build-id on large DIFs):
go install github.com/google/pprof@latest

# 1. Read the main binary's build-id from the raw profile's mappings:
BUILD_ID=$(pprof -raw heap-profile.pb \
  | sed -n '/^Mappings/,/^Locations/p' \
  | grep -E 'warp-(dev|preview)' | head -1 | awk '{print $NF}')

# 2. Download the matching DIF from the channel's Sentry project
#    (a read-only token is sufficient; dev -> warp-client-dev,
#     preview -> warp-client-preview):
ORG=warpdotdev; PROJECT=warp-client-dev
ID=$(curl -s "https://us.sentry.io/api/0/projects/$ORG/$PROJECT/files/dsyms/?query=${BUILD_ID:0:20}" \
       -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" | jq -r '.[0].id')
mkdir -p difs
curl -sL "https://us.sentry.io/api/0/projects/$ORG/$PROJECT/files/dsyms/?id=$ID" \
  -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" -o "difs/${BUILD_ID}.debug"

# 3. Symbolize + analyze (pprof matches the DIF to the profile by build-id):
PPROF_BINARY_PATH=./difs pprof -http=: heap-profile.pb   # flame graph / top / graph

The DIF carries .symtab + DWARF, so frames resolve to function names with file:line and inlined frames. (addr2line -e difs/$BUILD_ID.debug <addr> works as a lower-level alternative.)

Notes / scope

  • No pprof binary is bundled on Linux (in-process raw dump).
  • stable Linux builds are unchanged (no profiling features) — enabling for dev + preview first.

Linked Issue

N/A — infrastructure/observability follow-up.

Testing

  • cargo check + cargo clippy -- -D warnings for the app lib targeting Linux with heap_usage_tracking (exercises the new raw-dump branch); macOS host path also checked (validates the pprof_binary_path cfg-gate) — passes.

  • ./script/format — no changes beyond the edited files.

  • End-to-end validated on a build sharing this exact code path

  • I have manually tested my changes locally with ./script/run

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-NONE


🤖 Generated with Warp Agent Mode
Conversation: https://staging.warp.dev/conversation/e6ba6343-1bb8-4cce-a155-6f0b453bad40
Plan: https://staging.warp.dev/drive/notebook/359wXMjgAzXhtOZfnSWUlA

@cla-bot cla-bot Bot added the cla-signed label Jun 5, 2026
@oz-for-oss

oz-for-oss Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

@kevinyang372

I'm starting a first review of this pull request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

@oz-for-oss oz-for-oss Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This PR enables Linux dev and preview bundles to upload symbolized jemalloc heap profiles by using the in-process jemalloc_pprof dump path and preserving the executable symbol table when heap usage tracking is enabled. Stable Linux builds remain outside the rollout.

Concerns

  • No blocking correctness, security, or spec-drift concerns found in the annotated diff.

Verdict

Found: 0 critical, 0 important, 0 suggestions

Approve

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

@kevinyang372 kevinyang372 requested a review from vorporeal June 5, 2026 19:30
Enable automatic symbolized jemalloc heap profiling on Linux (notably the
headless Oz remote-server daemon), matching what macOS already does.

- profiling.rs: on Linux, dump the symbolized, gzipped pprof profile
  in-process via jemalloc_pprof (no external pprof binary, HTTP server, or
  port required); keep the external-pprof path for macOS, where in-process
  symbolization is unsupported.
- script/linux/bundle: enable jemalloc_pprof,heap_usage_tracking for the
  dev and preview channels, and stop strip --strip-all (use --strip-debug
  to retain the symbol table) for builds with heap profiling enabled, since
  in-process symbolization resolves against the running binary's own symbols.

CHANGELOG-NONE
@kevinyang372 kevinyang372 force-pushed the kevin/linux-heap-profiling branch from 2a0d98e to dd1e1ce Compare June 8, 2026 20:41

Copy link
Copy Markdown
Member Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@kevinyang372 kevinyang372 merged commit 1ef622e into master Jun 8, 2026
37 checks passed
@kevinyang372 kevinyang372 deleted the kevin/linux-heap-profiling branch June 8, 2026 22:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants