Skip to content

feat: on-demand profiling endpoints (/start_profile, /stop_profile, /profile_status) - #3

Open
sufubao wants to merge 18 commits into
mainfrom
profile_server
Open

feat: on-demand profiling endpoints (/start_profile, /stop_profile, /profile_status)#3
sufubao wants to merge 18 commits into
mainfrom
profile_server

Conversation

@sufubao

@sufubao sufubao commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds vLLM/SGLang-style on-demand torch.profiler capture to a running server, gated by a new --enable_profiling flag: POST /start_profile (with num_steps auto-stop / start_step arming), POST /stop_profile, and GET /profile_status (per-rank state via a shared-memory status board).
  • Control flow reuses existing plumbing end to end: httpserver → router over the existing zmq socket (ProfileControlReq), router → all worker ranks via the ShmObjsIOBuffer command broadcast (same path as AbortedReqCmd), and a per-rank WorkerProfilerManager state machine that starts/stops capture at forward-step boundaries. One gzipped chrome trace per rank ({prefix}-{id}-TP-{t}-DP-{d}.trace.json.gz), viewable in perfetto.
  • Handles the hard cases found in review: kineto start/stop is thread-affine, so stops hit on the non-owner infer thread are deferred to the owner thread's next boundary (±1 step window); trace export is atomic (tmp + rename, cleanup on failure); /start_profile input is fully validated (output_dir sandbox, prefix whitelist, positive-int steps); multinode-TP mode is gated off (local cmd injection would desync the nodes' lockstep cmd buffers and hang NCCL); servers without the flag allocate no profiler state at all.

Design doc: docs/profile_server/design.md · Usage: docs/profile_server/usage.md

Test Plan

  • 23 unit tests (unit_tests/server/core/objs/test_profile_cmd.py, test_profile_status_board.py, unit_tests/server/router/test_worker_profiler_manager.py) — state machine incl. cross-thread deferred stop, atomic-export failure cleanup, shm board
  • E2E on GPU (Qwen3.5-0.8B, tp=1): armed → running → auto-stop after exactly num_steps forwards → idle; two valid chrome traces (13.9k events, 3.4k GPU kernels); manual-stop path; all six 400/501 validation paths; flag-off 501 gate; default (flag-off) server serves normally
  • black (CI-pinned 21.12b0) + flake8 clean on all changed files

sufubao added 18 commits June 12, 2026 03:10
Implement ProfileControlReq, StartProfileCmd, and StopProfileCmd dataclasses
for on-demand profiling control. ProfileControlReq is sent from HTTP server
to router and converted to worker commands via to_worker_cmd() method. All
classes are pickle-serializable for shared-memory transport.

- ProfileControlReq: httpserver -> router control message with defaults
- StartProfileCmd: worker command for profile initiation with full config
- StopProfileCmd: worker command for profile termination
Implements WorkerProfilerManager: IDLE→ARMED→RUNNING→FLUSHING→IDLE
state machine with on_cmd/on_step_boundary interface. Failures report
to ProfileStatusBoard and reset to IDLE for recovery. Includes 8 TDD
unit tests covering auto-stop, start_step delay, manual stop, cancel
while armed, duplicate-start guard, factory/export error paths, and
idle fast-path forward counting.
- Import StartProfileCmd/StopProfileCmd and WorkerProfilerManager in base_backend.py
- Instantiate WorkerProfilerManager after shm buffers are set up, before infer threads start
- Dispatch StartProfileCmd/StopProfileCmd to profiler_manager.on_cmd() in _read_reqs_buffer_and_init_reqs
- Call profiler_manager.on_step_boundary() as first statement in is_prefill() and is_decode() branches of ChunkedPrefillBackend.infer_loop and DPChunkedPrefillBackend.infer_loop; is_pass() branches unchanged
…ing disabled

- 501 /start_profile in multinode tensor-parallel mode (nnodes>1, dp=1):
  locally injected cmds would desync the nodes' lockstep shm cmd buffers
  and hang NCCL collectives; router also drops such cmds defensively
- create ProfileStatusBoard / WorkerProfilerManager only under
  --enable_profiling (NullProfilerManager no-op otherwise), so disabled
  servers allocate no /dev/shm segments
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