Skip to content

backend: add opt-in pprof server (RADIANCE_PPROF_ADDR)#513

Open
myleshorton wants to merge 3 commits into
fisk/unbounded-conn-source-on-closefrom
fisk/radiance-pprof
Open

backend: add opt-in pprof server (RADIANCE_PPROF_ADDR)#513
myleshorton wants to merge 3 commits into
fisk/unbounded-conn-source-on-closefrom
fisk/radiance-pprof

Conversation

@myleshorton

@myleshorton myleshorton commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

What

Adds a loopback pprof/HTTP server to LocalBackend, gated behind the RADIANCE_PPROF_ADDR env var. Off by default — with the var unset, nothing is registered and no port is opened, so it's safe in release builds.

RADIANCE_PPROF_ADDR=localhost:6060 <app>
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30

Why

Radiance is compiled into the host app via gomobile, so there's no separate process to attach a profiler to, and no other on-device profiling hook. This came out of investigating high CPU while the Unbounded / broflake WebRTC relay is active — that relay's cost (pion DTLS/ICE/SCTP + QUIC-over-datachannel + byte copying) is otherwise invisible, and there was no way to capture a CPU/heap profile of the running client.

Safety

  • Hard-refuses non-loopback addresses. isLoopbackAddr rejects an empty host (:6060 → all interfaces), 0.0.0.0, and public IPs before the listener opens; only localhost, 127.0.0.0/8, and ::1 are accepted. The pprof endpoints expose goroutine stacks and can be driven to burn CPU, so they must never be reachable off-device — this is enforced, not left to the caller.
  • Tied to Close(). The server's Close is registered in shutdownFuncs, so a Start/Close cycle (re-init, tests, in-process clients) frees the port and stops the goroutine instead of leaking it and failing the next Start with "address already in use".
  • Served from a dedicated mux, not http.DefaultServeMux, so importing net/http/pprof here can't surface these handlers on any other server in the process.

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings June 7, 2026 01:50

Copilot AI 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.

Pull request overview

Adds an opt-in, loopback-only pprof HTTP server for on-device profiling when Radiance is embedded (e.g., via gomobile), gated behind the RADIANCE_PPROF_ADDR environment variable so nothing is exposed by default.

Changes:

  • Start an optional debug/pprof server during LocalBackend.Start() when RADIANCE_PPROF_ADDR is set.
  • Introduce a dedicated http.ServeMux hosting net/http/pprof endpoints to avoid using http.DefaultServeMux.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
backend/radiance.go Starts the debug server during backend startup.
backend/pprof.go Implements the opt-in pprof HTTP server with a dedicated mux.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread backend/pprof.go Outdated
Comment thread backend/radiance.go Outdated
myleshorton and others added 2 commits June 7, 2026 19:00
Radiance is compiled into the host app via gomobile, so there's no
process to attach a profiler to and no on-device profiling hook. Add a
loopback pprof/HTTP server gated behind RADIANCE_PPROF_ADDR — off by
default (nothing registered, no port opened) so it ships safely in
release builds. Set it to e.g. localhost:6060 to capture CPU/heap
profiles of the running client, notably the broflake / Unbounded WebRTC
relay whose cost is otherwise invisible:

    RADIANCE_PPROF_ADDR=localhost:6060 <app>
    go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30

Bound to loopback only and served from a dedicated mux (not
DefaultServeMux) so the debug handlers can't leak off-device or onto
another server in the process.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Hard-refuse any RADIANCE_PPROF_ADDR that isn't loopback (empty host,
  0.0.0.0, or a public IP) instead of trusting the caller. pprof exposes
  goroutine stacks and can be driven to burn CPU, so it must never bind
  off-device.
- Register the server's Close in shutdownFuncs so a Start/Close cycle
  (re-init, tests, in-process clients) frees the port and stops the
  goroutine. Previously it leaked and the next Start would hit "address
  already in use".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@myleshorton myleshorton force-pushed the fisk/radiance-pprof branch from febf293 to 58d7b61 Compare June 8, 2026 01:00
@myleshorton myleshorton changed the base branch from main to fisk/unbounded-conn-source-on-close June 8, 2026 01:01
Add an env.Pprof key and have startDebugServer read the address through
the radiance env package instead of os.Getenv directly. env.Get already
honours an OS env var, a .env file in the working dir, and runtime
env.Set (incl. the IPC SetEnv path) — the latter two are what let the
profiler be enabled on sandboxed macOS/iOS system extensions, which don't
inherit the launching shell's environment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

3 participants