[dashboard] Configurable defaults + UI dialogs for py-spy/memray profiling params - #64806
[dashboard] Configurable defaults + UI dialogs for py-spy/memray profiling params#64806marwan116 wants to merge 15 commits into
Conversation
The dashboard profiling actions (stack trace, CPU flame graph, memory profiling) expose several parameters (native, subprocesses, idle, leaks, trace_python_allocators, duration, format) whose defaults were hardcoded. The only way to change one was to hand-edit the request URL, and there was no way for a cluster operator to set a different default cluster-wide. Add RAY_DASHBOARD_PROFILING_*_DEFAULT env vars so operators can configure each default on the head node. Parse sites in reporter_head fall back to these constants when the query param is absent; an explicit query param still wins, so behavior is unchanged unless an operator opts in. duration and format are split into CPU and memory variants because py-spy (CPU: flamegraph/raw/speedscope) and memray (memory: flamegraph/table) accept different valid format sets and different duration defaults; a single shared default would break CPU requests. native remains Linux-only. /api/profiling_enabled also returns the configured defaults so the dashboard UI can seed its profiling dialogs from them. AI assistance (Claude Code) was used to author this change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Marwan Sarieddine <sarieddine.marwan@gmail.com>
…faults Previously the Stack Trace and CPU Flame Graph buttons were bare links with a hardcoded native=0 in the URL, so a user could only change parameters by hand-editing the URL, and the hardcoded native=0 overrode the operator's configured default. Turn the Stack Trace and CPU Flame Graph buttons (worker and task variants) into parameter dialogs, mirroring the existing Memory Profiling dialog. All three profiling dialogs now render one shared ProfilingParamsDialog and seed their initial values from the defaults returned by /api/profiling_enabled. The hardcoded native=0 is removed; format options are profiler-correct (CPU: flamegraph/raw/speedscope, memory: flamegraph/table). Verified with tsc --noEmit and the ProfilingLink component tests (updated the existing memory-dialog assertion and added worker/task dialog tests). AI assistance (Claude Code) was used to author this change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Marwan Sarieddine <sarieddine.marwan@gmail.com>
There was a problem hiding this comment.
Code Review
This pull request introduces operator-configurable environment variables to set cluster-wide defaults for profiling parameters (such as duration, format, and various flags) on the Ray head node, updating both the backend and frontend to respect these defaults. The review feedback highlights critical validation and accessibility improvements: the backend endpoints in reporter_head.py should properly validate that profiling durations are between 1 and 60 seconds and raise clean HTTP 400 errors instead of uncaught ValueErrors (which cause HTTP 500s). On the frontend, the duration input field in ProfilingLink.tsx needs visual validation feedback, and invalid HTML nesting of a <Link> inside a <Button> should be resolved by rendering the button directly as an anchor.
Address code review feedback: - Validate the profiling `duration` query param (1-60 seconds) in a single `_query_duration` helper used by all three profiling endpoints, raising HTTP 400 (aiohttp.web.HTTPBadRequest) for a non-integer or out-of-range value. Previously an out-of-range duration raised a bare ValueError (surfacing as HTTP 500) on the CPU endpoints, and the memory endpoint had no upper bound at all. - Frontend: show inline error/helper text on the duration field and disable the submit action when the duration is out of range. - Frontend: render the submit button itself as the anchor (component="a") instead of nesting a <Link> inside a <Button>, which is invalid HTML and an accessibility issue. Added tests for the duration bounds (backend) and the invalid-duration disabled/error state (frontend). AI assistance (Claude Code) was used to author this change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Marwan Sarieddine <sarieddine.marwan@gmail.com>
|
Thanks for the review @gemini-code-assist. Addressed all five comments in 5a037a6:
Added tests for the duration bounds (backend) and the invalid-duration disabled/error state (frontend). Frontend verified locally: |
|
The consolidation of parsing and validation into the |
`test_profiling_enabled_endpoint_returns_defaults` passed the `http://`-prefixed URL from `format_web_url` into `wait_until_server_available`, whose `parse_address` call only handles `host:port` and returns None for a scheme-prefixed URL, raising `TypeError: cannot unpack non-iterable NoneType object`. Wait on the raw `webui_url` first, then format it for the request, matching the existing pattern elsewhere in this file. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Marwan Sarieddine <sarieddine.marwan@gmail.com>
…g durations Address review feedback on the configurable profiling defaults: - leaks default: RAY_DASHBOARD_PROFILING_LEAKS_DEFAULT defaulted to True, which silently put memray into leak mode for any request that omits `leaks`. The previous handler defaulted an omitted `leaks` to off (peak usage), so this was an unintended behavior change. Restore the default to False (and the frontend fallback + docs table to match) so behavior is unchanged unless an operator opts in. - duration clamping: the CPU/memory duration defaults were read with env_integer and never clamped, so a misconfigured head-node env value could bypass the endpoint's 1-60s cap -- and, because /api/profiling_enabled echoes those defaults to the UI, the dialog would seed the bad value and then 400 on submit. Clamp both defaults into [MIN_PROFILING_DURATION_S, MAX_PROFILING_DURATION_S] at load time and move the bounds into ray_constants as the single source of truth. Explicit out-of-range query params still return HTTP 400. Add test_clamp_profiling_duration (in-range pass-through + out-of-range clamping); update the frontend default-params test to expect leaks=0. AI assistance (Claude Code) was used to author this change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Marwan Sarieddine <sarieddine.marwan@gmail.com>
…g dialog on open Address the remaining review nits on the profiling dialogs: - Native checkbox (review nit): py-spy drops --native on non-Linux (see profile_manager), so a configured RAY_DASHBOARD_PROFILING_NATIVE_DEFAULT=1 would pre-check the box on a non-Linux dashboard where it is a silent no-op. /api/profiling_enabled now reports `pyspy_native_supported` (sys.platform == "linux"), and the CPU/stack-trace dialogs disable and force-off the Native checkbox when it is unsupported. memray (memory) native is cross-platform, so the memory dialog's Native checkbox is unchanged. - Dialog defaults (bugbot): ProfilingParamsDialog captured its initial state only at first mount. In practice the dialog only mounts once profiling is enabled -- after /api/profiling_enabled resolves, with the defaults cached in the same batch -- so it already seeds correctly, but reseed state on open anyway so it is robust to render timing. Add a frontend test for the disabled/forced-off Native behavior; add the new key to the profiling_enabled endpoint test. AI assistance (Claude Code) was used to author this change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Marwan Sarieddine <sarieddine.marwan@gmail.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7333e62. Configure here.
Signed-off-by: Marwan Sarieddine <sarieddine.marwan@gmail.com>
The profiling `duration` upper bound was a hardcoded 60s. Nothing in the stack actually enforces 60 (the profiling gRPC calls set no deadline and py-spy/memray are awaited without a timeout), so it was an arbitrary product choice, and too low for some legitimate cases -- memray leak detection over minutes, periodic CPU hotspots (py-spy's own docs use a 5-minute example). Make the cap operator-configurable via RAY_DASHBOARD_PROFILING_MAX_DURATION_S (default 300s), floored at the 1s minimum so a misconfigured value can never invert the range (which would otherwise reject every duration). The minimum stays a hard floor. /api/profiling_enabled now returns `max_duration` so the dashboard validates the Duration field against the real cap instead of a hardcoded one. Keeping a cap (rather than open-ended) is deliberate: a synchronous profile blocks the request for its whole duration and py-spy/memray output grows with it, and there is no backstop timeout, so an unbounded value is a footgun. AI assistance (Claude Code) was used to author this change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Marwan Sarieddine <sarieddine.marwan@gmail.com>
MortalHappiness
left a comment
There was a problem hiding this comment.
Please also update your stale PR descriptions. Thanks.
…s, docstrings Follow-up to review feedback on the configurable profiling defaults PR: - Default RAY_DASHBOARD_PROFILING_MAX_DURATION_S to 60 rather than 300, so the shipped cap matches the one the endpoints have always enforced. Operators still raise or lower it per cluster. - Warn when a configured duration is clamped into the accepted range, naming the env var that was ignored, and warn when the configured cap itself falls below the minimum. A silently adjusted value otherwise looks like the operator's setting took effect. - Make the valid format sets public and have profile_manager read them, so the formats py-spy and memray accept are declared in exactly one place instead of being duplicated between request validation and default validation. - Fix stale docstrings in reporter_head: duration errors are HTTP 400, not a bare ValueError or a 500, the duration/format/flag defaults are operator-configurable rather than fixed, and get_traceback and memory_profile now document the query params they parse. Adds TestProfilingFormatValidation, which mocks out subprocess execution so the shared format sets are covered on platforms where the live memray suite is skipped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Marwan Sarieddine <sarieddine.marwan@gmail.com>
|
Thanks for the review @MortalHappiness — all four comments addressed in efe7a93, replies inline. Description is refreshed. It had drifted in a few ways:
The Checks section now has re-run numbers (backend 30 + 1 + 13 passed, frontend 11 passed, |
MortalHappiness
left a comment
There was a problem hiding this comment.
LGTM for Python changes. I didn't review frontend and doc changes.
Resolved conflicts in ProfilingLink.tsx and ProfilingLink.component.test.tsx against #65126 (fix profiling status check behind a reverse proxy): - fetchProfilingEnabled() keeps master's get() helper from requestHandlers (reverse-proxy safe) and still merges profilingDefaults onto DEFAULT_PROFILING_DEFAULTS for partial/older payloads. - Consolidated the two test-only cache resets into master's _resetProfilingEnabledCache(), which now also clears cachedProfilingDefaults. - Test helper mockProfiling() switched from stubbing global.fetch to mocking get(), matching the production code path. Signed-off-by: Marwan Sarieddine <sarieddine.marwan@gmail.com>
dstrodtman
left a comment
There was a problem hiding this comment.
Docs style review (Anyscale docs team)
Run by Douglas Strodtman on the Anyscale docs team, with Claude Code assisting. I read every comment below and stand behind it.
Scope: style, grammar, and Ray docs conventions on the two files under doc/, checked against Ray's documentation style guide. I'm not a code owner here. Everything technical stays with @carolynwang and @MortalHappiness, and I noticed @MortalHappiness's approval explicitly excluded the doc changes, which is why I picked them up.
Nice work on the reference table. Cross-checking every row against ray_constants.py at 2f03aa9, all ten variable names, all ten defaults, the [1, 60] bound, the clamping behavior, the HTTP 400 on an out-of-range explicit duration, and both format sets are accurate. That's a better hit rate than most env-var tables in the docs, so the comments below are almost entirely prose mechanics.
Two things worth a look beyond style:
- The
nativerow's "only takes effect on Linux" may be scoped too narrowly.RAY_DASHBOARD_PROFILING_NATIVE_DEFAULTfeedsnativeon the memory endpoint too (reporter_head.py,memory_profile), and your own code comment says memray native is cross-platform while py-spy only appends--nativeon Linux. If that's right, the Linux caveat holds for stack trace and CPU profiling but not for memory profiling, and the table currently reads as though it applies to all three. Flagging rather than suggesting a fix, since you know the profiler behavior and I'm reading it off your comment. Details inline. - The PR title promises UI dialogs, and the docs only cover the env vars. A reader hitting the dashboard sees new parameter dialogs that no page describes. Is documenting them in scope here, or a deliberate follow-up? Not a blocker from me either way, just want it to be a decision rather than an oversight.
One out-of-diff note: profiling.md has no myst.html_meta.description front matter, which the style guide asks for on every page. Pre-existing and above the diff, so there's nothing to click, but it's a cheap add while you're in the file.
Happy to give this a docs-side stamp once you've picked through the comments. Posting as a comment, not a change request.
| ::: | ||
|
|
||
| (profiling-defaults)= | ||
| ### Configuring profiling defaults |
There was a problem hiding this comment.
Heading level and placement. This is an ### under ## Enabling dashboard profiling, which makes configuring defaults a subtask of enabling profiling. They read more like siblings to me: enabling is a security gate you pass once, configuring defaults is separate operator tuning, and this section sits right before ## CPU profiling. Worth considering promoting it to ## Configuring profiling defaults. Your call, and I can see the argument that both are head-node env vars so grouping them helps.
On the wording: the style guide asks for imperative task headings ("Configure profiling defaults"), but the H2 above it is a gerund, and internal consistency on the page wins over a global sweep. Leaving it as-is is fine.
| (profiling-defaults)= | ||
| ### Configuring profiling defaults | ||
|
|
||
| Each profiling request (stack trace, CPU flame graph, memory profile) accepts several parameters. When a request omits a parameter, the value falls back to a cluster-wide default. Set these environment variables on the Ray head node to change the defaults for every request that doesn't specify the parameter explicitly (an explicit query parameter always takes precedence). |
There was a problem hiding this comment.
Two parenthetical asides in one paragraph, and the style guide asks you to restructure rather than parenthesize. Folding the first into the sentence and promoting the second to its own sentence also gives the table a cleaner "the following" lead-in:
| Each profiling request (stack trace, CPU flame graph, memory profile) accepts several parameters. When a request omits a parameter, the value falls back to a cluster-wide default. Set these environment variables on the Ray head node to change the defaults for every request that doesn't specify the parameter explicitly (an explicit query parameter always takes precedence). | |
| Stack trace, CPU flame graph, and memory profile requests each accept several parameters. When a request omits a parameter, its value falls back to a cluster-wide default. Set the following environment variables on the Ray head node to change those defaults. An explicit query parameter always takes precedence. |
| - Meaning | ||
| - Default | ||
| * - `RAY_DASHBOARD_PROFILING_NATIVE_DEFAULT` | ||
| - Include native (C/C++) stack frames. Higher overhead; only takes effect on Linux. |
There was a problem hiding this comment.
Semicolon in prose. The style guide asks you to split instead:
| - Include native (C/C++) stack frames. Higher overhead; only takes effect on Linux. | |
| - Include native (C/C++) stack frames. Adds significant overhead. Only takes effect on Linux. |
Separately, and this is the technical question from the review body rather than a style point: I don't think "only takes effect on Linux" is true for all three request types. memory_profile in reporter_head.py also defaults its native flag from this variable, and your comment on the pyspy_native_supported field says memray native is cross-platform and only py-spy is Linux-gated. If so, a reader who sets this to 1 on macOS gets no change to stack traces or CPU profiles but does get native frames in memory profiles, which this row tells them not to expect.
I've deliberately kept the suggestion above to the semicolon and left the Linux claim exactly as you wrote it, because you know the profiler behavior and I don't want to restyle a scope claim into something more confident than I can verify. If the split is real, something like "Only takes effect on Linux for stack trace and CPU profiling. memray honors it on every platform." would cover it.
| - Also profile child processes of the target (stack trace and CPU profiling). | ||
| - `0` | ||
| * - `RAY_DASHBOARD_PROFILING_IDLE_DEFAULT` | ||
| - Include off-CPU / sleeping threads (CPU profiling only). |
There was a problem hiding this comment.
The style guide asks you to spell out separators in prose, so X / Y becomes "X or Y":
| - Include off-CPU / sleeping threads (CPU profiling only). | |
| - Include off-CPU or sleeping threads (CPU profiling only). |
| - Duration in seconds for memory profiling (clamped to `RAY_DASHBOARD_PROFILING_MAX_DURATION_S`). | ||
| - `10` | ||
| * - `RAY_DASHBOARD_PROFILING_MAX_DURATION_S` | ||
| - Maximum accepted profiling `duration` in seconds. A profile blocks the request for its whole duration, so it's capped rather than open-ended; raise or lower it per cluster. The minimum is always 1s. Explicit `duration` query values above this return HTTP 400. |
There was a problem hiding this comment.
This is the one cell doing four jobs, and it has a semicolon plus an abbreviated unit. Splitting it into sentences and spelling out the unit:
| - Maximum accepted profiling `duration` in seconds. A profile blocks the request for its whole duration, so it's capped rather than open-ended; raise or lower it per cluster. The minimum is always 1s. Explicit `duration` query values above this return HTTP 400. | |
| - Maximum accepted profiling `duration` in seconds. A profile blocks the request for its whole duration, so Ray caps it rather than leaving it open-ended. Raise or lower it per cluster. The minimum is always 1 second. An explicit `duration` query value above this maximum returns HTTP 400. |
I verified each claim in there against _profiling_duration_cap, _clamp_profiling_duration, and _query_duration, so this is a rewording only, not a change in meaning.
| - Maximum accepted profiling `duration` in seconds. A profile blocks the request for its whole duration, so it's capped rather than open-ended; raise or lower it per cluster. The minimum is always 1s. Explicit `duration` query values above this return HTTP 400. | ||
| - `60` | ||
| * - `RAY_DASHBOARD_PROFILING_CPU_FORMAT_DEFAULT` | ||
| - Output format for CPU profiling. One of `flamegraph`, `raw`, `speedscope`. |
There was a problem hiding this comment.
Small one: add the conjunction before the last item in each set, per the guide's Oxford comma rule.
| - Output format for CPU profiling. One of `flamegraph`, `raw`, `speedscope`. | |
| - Output format for CPU profiling. One of `flamegraph`, `raw`, or `speedscope`. |
| - Output format for CPU profiling. One of `flamegraph`, `raw`, `speedscope`. | ||
| - `flamegraph` | ||
| * - `RAY_DASHBOARD_PROFILING_MEMORY_FORMAT_DEFAULT` | ||
| - Output format for memory profiling. One of `flamegraph`, `table`. |
There was a problem hiding this comment.
Same here:
| - Output format for memory profiling. One of `flamegraph`, `table`. | |
| - Output format for memory profiling. One of `flamegraph` or `table`. |
| - `flamegraph` | ||
| ``` | ||
|
|
||
| For example, to make native frames the default for stack traces across the cluster (Linux only), set `RAY_DASHBOARD_PROFILING_NATIVE_DEFAULT=1` on the head node. Because `native` significantly increases profiling overhead, prefer leaving it off and enabling it only when sampling the Python layer alone isn't enough. |
There was a problem hiding this comment.
Three things in this paragraph:
- "prefer leaving it off and enabling it only when" is hedged. The guide asks you to turn hedging into direct advice, so make it an instruction and give the reason.
- "(Linux only)" repeats the table row two lines above.
- The overhead warning now appears three times across this PR: this paragraph, the table's
nativerow, and the new sentence indebug-hangs.rst. Once in the table plus once in the prose that a stack-trace reader actually lands on is enough.
| For example, to make native frames the default for stack traces across the cluster (Linux only), set `RAY_DASHBOARD_PROFILING_NATIVE_DEFAULT=1` on the head node. Because `native` significantly increases profiling overhead, prefer leaving it off and enabling it only when sampling the Python layer alone isn't enough. | |
| For example, to make native frames the default for stack traces across the cluster, set `RAY_DASHBOARD_PROFILING_NATIVE_DEFAULT=1` on the head node. Enable it only when sampling the Python layer alone isn't enough, because native frames significantly increase profiling overhead. |
| trace is shown. To show native code frames, set the URL parameter ``native=1`` (only supported on Linux). To make native | ||
| frames the default for every stack trace on the cluster, set the ``RAY_DASHBOARD_PROFILING_NATIVE_DEFAULT=1`` environment | ||
| variable on the Ray head node (see :ref:`Configuring profiling defaults <profiling-defaults>`). Because native frames add | ||
| significant profiling overhead, prefer enabling it only when sampling the Python layer alone isn't enough. |
There was a problem hiding this comment.
Two style points on the added sentences, plus one that isn't yours.
The (see :ref:...) parenthetical is the pattern the style guide asks you to restructure, and "prefer enabling it only when" is hedged where a direct instruction reads better. Moving the cross-reference to its own sentence at the end also makes it the obvious next click. I kept the existing hard wrap so the diff stays tight, and left the (only supported on Linux) parenthetical on line 14 alone since it predates this PR.
| trace is shown. To show native code frames, set the URL parameter ``native=1`` (only supported on Linux). To make native | |
| frames the default for every stack trace on the cluster, set the ``RAY_DASHBOARD_PROFILING_NATIVE_DEFAULT=1`` environment | |
| variable on the Ray head node (see :ref:`Configuring profiling defaults <profiling-defaults>`). Because native frames add | |
| significant profiling overhead, prefer enabling it only when sampling the Python layer alone isn't enough. | |
| trace is shown. To show native code frames, set the URL parameter ``native=1`` (only supported on Linux). To make native | |
| frames the default for every stack trace on the cluster, set the ``RAY_DASHBOARD_PROFILING_NATIVE_DEFAULT=1`` environment | |
| variable on the Ray head node. Native frames add significant profiling overhead, so enable them only when sampling the | |
| Python layer alone isn't enough. See :ref:`Configuring profiling defaults <profiling-defaults>`. |
Not from your diff, so there's nothing to click, but line 13 just above reads "Clicking "Stack Trace" will return the current stack trace sample" and the guide asks for present tense over "will" for things that are always true. "returns" would fix it if you feel like touching the line while you're here.
dstrodtman
left a comment
There was a problem hiding this comment.
Stamping with small doc feedback items.
|
Hi @marwan116 Can you check if this test failure related to your changes? https://buildkite.com/ray-project/premerge/builds/71537#019fd9d4-470c-4303-ac7a-b236c4d40838 I've synced with the master branch multiple times and retried the failed test multiple times but it always fails. |
…-profiling-defaults Signed-off-by: Marwan Sarieddine <sarieddine.marwan@gmail.com>
|
Thanks for checking @MortalHappiness — it's unrelated to this PR. The failing target is It broke on master in #65075, which regenerates a dataset's uuid on deserialization, and was fixed on master by #65290 (merged 2026-08-07 17:28 UTC). Build #71537 ran at 01:43 UTC that day, ~16h before the fix landed — the failure was deterministic, which is why the retries and master syncs never cleared it. I've merged current master (including f22677d) into the branch and pushed, so this target should be green on the next run. For completeness: this PR touches only the dashboard reporter, the profiling defaults in |

Why are these changes needed?
The Ray Dashboard's profiling actions — Stack Trace (py-spy), CPU Flame Graph (py-spy), and
Memory Profiling (memray) — expose several parameters (
native,subprocesses,idle,leaks,trace_python_allocators,duration,format) whose defaults were hardcoded. Theonly way to change one (e.g. to include native C/C++ frames in a stack trace) was to hand-edit the
request URL's query string, and there was no way for a cluster operator to change a default
cluster-wide. This came up from a user asking whether the default value of
nativecan beconfigured — today it can't.
This PR makes every profiling parameter's default configurable and gives the dashboard UI first-class
controls for them.
Backend
RAY_DASHBOARD_PROFILING_*environment variables, read on the Ray head node, let an operatorset each default. Parse sites in
reporter_headfall back to these constants only when the requestomits the parameter; an explicit query parameter still wins, so behavior is unchanged unless an
operator opts in.
durationandformatare split into CPU and memory variants, because py-spy (CPU:flamegraph/raw/speedscope) and memray (memory:flamegraph/table) accept differentvalid format sets and different duration defaults (5s vs 10s). A single shared default would break
CPU requests.
formatdefaults are validated against the correct set at load time, falling backto
flamegraphon a bad value.durationvalidation now returns HTTP 400, not 500. The endpoints previously raised a bareValueErrorfor an over-long duration, which surfaced as an uncaught HTTP 500._query_durationnow raises
aiohttp.web.HTTPBadRequestfor a non-integer or out-of-range value.durationrange is[1, RAY_DASHBOARD_PROFILING_MAX_DURATION_S], defaulting tothe 60s cap the endpoints have always enforced. Operators raise or lower it per cluster. Configured
duration defaults are clamped into that range at load time — with a warning naming the offending
env var — so a misconfigured head node can never bypass the endpoint cap.
nativeremains Linux-only regardless of the default (existing guard inprofile_manager)./api/profiling_enablednow also returns the configured defaults so the UI can seed its dialogs,including
maxDuration, so the duration field validates against the real cap instead of ahardcoded one.
ray_constantsand are now read by bothreporter_head(tovalidate the configured default) and
profile_manager(to validate the request), so the acceptedformats are declared in exactly one place.
New env vars, all documented in
profiling.md(10 total):RAY_DASHBOARD_PROFILING_NATIVE_DEFAULT,_SUBPROCESSES_DEFAULT,_IDLE_DEFAULT,_LEAKS_DEFAULT,_TRACE_PYTHON_ALLOCATORS_DEFAULT,_CPU_DURATION_DEFAULT,_MEMORY_DURATION_DEFAULT,_CPU_FORMAT_DEFAULT,_MEMORY_FORMAT_DEFAULT,RAY_DASHBOARD_PROFILING_MAX_DURATION_S.Frontend
bare links that hardcoded
native=0, which also overrode the operator's configured default.They are now parameter dialogs — the same UX as the existing Memory Profiling dialog — so users set
parameters in the UI instead of editing URLs.
ProfilingParamsDialogcomponent and seed theirinitial values from the defaults returned by
/api/profiling_enabled. The hardcodednative=0isgone; format options are profiler-correct; the duration field validates against the backend's
reported
maxDurationand disables submit with an inline error when out of range.Not a duplicate
Searched open PRs before starting — no PR addresses this area:
There is no existing mechanism for configuring dashboard profiling defaults;
RAY_DASHBOARD_ENABLE_PROFILINGonly gates the feature on/off.
Related issues
Checks
AI assistance (Claude Code) was used to author this change; every changed line was reviewed by the
submitter.
Backend — verified locally:
Tests in
test_reporter.py:test_query_flag,test_query_duration_valid,test_query_duration_invalid_raises_bad_request,test_clamp_profiling_duration,test_clamp_profiling_duration_warns_and_names_the_env_var,test_clamp_profiling_duration_silent_when_in_range,test_validated_profiling_format,test_validated_profiling_format_absent_uses_fallback,test_profiling_enabled_endpoint_returns_defaults. These cover that out-of-range durations surfaceas HTTP 400 rather than a bare
ValueError, that a misconfigured env default is clamped with awarning, and that the CPU/memory format split rejects
speedscopefor memray andtablefor py-spy.New
TestProfilingFormatValidationintest_profile_manager.pyasserts both profilers honor theshared format sets — every declared CPU format reaches the py-spy command, every declared memory
format maps to its memray subcommand, and each profiler rejects the other's formats. It mocks out
subprocess execution, so unlike the live
TestMemoryProfilingsuite it also runs on macOS.End-to-end against a live head node (
RAY_DASHBOARD_ENABLE_PROFILING=1):Frontend — verified locally:
The frontend tests assert, among other things, that the worker Stack Trace link produces
worker/traceback?...&native=1&subprocesses=0(reflecting a configurednativedefault), that itnever emits a hardcoded
native=0, and that an out-of-range duration disables submit with aninline error.
pre-commit run --files <changed>passes (ruff, black, pydoclint, docstyle, import-order, eslint,semgrep).
Notes for reviewers
RAY_DASHBOARD_ENABLE_PROFILINGsecuritygate — unchanged.
jax_profileis deliberately not migrated to the shared_query_durationhelper. It has neverenforced a duration cap, and routing it through the shared validator would newly reject durations
above the cap for JAX users — a behavior change unrelated to this PR's goal. Its docstring is
accurate as-is.
ProfilingLink.tsxkeeps its own copy of the format lists for the dropdown options, since thefrontend can't import the Python constants. Plumbing them through
/api/profiling_enabledwould bea reasonable follow-up.