Pull requests / #2688
#2688 serve: the Profile tab in the web app (opt-in "profile": true): last request, the last 50, a measured run, the tuning with its before and after, the speed settings
open · @qiuzan2001 · 0 comentarios · En GitHub
BenchmarksSetup & installServer & APIAMD / HIPNVIDIA / CUDAModels & quantsSecurity
Descripción
## What it changes
With `"profile": true` (or `--profile`) the web app gets a fifth tab, **Profile**, next to About. It replaces the
standalone `/profile` page of #2661 with a tab, so the page and the tab do not show the same data twice. Its five cards:
1. **Last request**: the prompt read by phase, the decode window in ms, the hit rate, the PCIe share, KV streaming. A
line says when a request is running.
2. **Recent requests**: the last 50 requests' timings as three bar sparklines and a table.
3. **Measured run**: `tools/strata_profile.py` with one click: progress, then its three tables and the findings, each
finding with a chip per setting it names (loaded now / next load).
4. **Tune this PC**: setup's calibration with one click (after a confirm): the elapsed time, then a before/after table
of the calibrated flags, the calibration's tok/s and the server's note.
5. **Settings that matter for speed**: for 14 settings, the value the running engine reports, the value the next load
will use, the value the run config file has, one plain sentence and what the last run said about it.
Server side:
- `GET /profile/history` (new): the last 50 requests, read from the engine log (`ProfileHistory`, in memory, timings
only, no prompts or answers; driven by the `/metrics` poll).
- `GET /profile/settings` (new): the three columns above. It never shows `api_key`, another env value or a path
(`expert_profile_save` is only `"set"` or null).
- `/profile/status`: `report.findings` (each with the settings it names) and `tune.report` (summary, tok/s, before/after
rows).
- `GET /profile` is now a 302 to `./#profile` (`../#profile` for `/profile/`), relative, so it works behind a prefix.
- `/health` gains `"profile": true` only when the tab is on.
- `serve/web/profile.html` and `serve/web/profile.js` are deleted. No new file, no new dependency, no CDN.
Server data reaches the page through `textContent` only (a test checks the Profile section of `app.js` has no
`innerHTML`). Both POSTs keep the own-page check (JSON only, no foreign `Origin`, the key when one is set).
## What it leaves alone
The engine, `tools/strata_profile.py`, `tools/calibrate.py` and setup's calibration. No new run-config keys; speed flags
are not edited from the tab. Replicas and HIP are not supported for tuning, as in #2661 (`tune_unavailable` says so).
`/api-monitor` is unchanged.
## Stacked on #2660 and #2661
This branch is `8cd43878` (#2660's `tools/strata_profile.py` + #2661's page) plus one commit. It replaces #2661's
standalone page with the tab. The maintainer can take #2661 alone (the page) or both (the tab instead of the page);
the code is the same either way.
## The default stays as it was
- No line of the engine start path (`StrataEngine.start`, `child_env`) changes. `test_child_env_sets_them_only_with_the_key`
stays green.
- With no `profile` key: `/health` has no `profile` key. On the mock engine (`--engine mock`) `/health` is
byte-identical to `8cd43878` (same md5, `fa87eb45...`), and `/profile`, `/profile/history`, `/profile/settings` answer
404.
- The tab button is `hidden` in `index.html`; only `health.profile === true` shows it. No profile request is made when
it is off (checked in a browser: 0 fetches).
- `/metrics` never reads the history when it is off. `test_off_by_default` pins this and the `/health` key set. I
checked the test by mutation: removing the `if self.profile is not None` guard in `metrics()` fails it, and so does
making `/health` always send a `profile` key.
- Two changes on the default path, both named in the design: the help text of the `profile` key in `/config`
("... show the Profile tab ..."), and a `data-key` attribute on the About tab's Model settings inputs. One more:
typing `#profile` with the tab off now shows a card that says how to turn it on, instead of falling back to Chat.
- Words in two profile-only strings changed from "page" to "tab" (the 503 while tuning, `--profile` help).
## Tests
All without a GPU, from the repository root with `python3 -m unittest`:
| Suite | Result |
| --- | --- |
| `serve.test_profile` | 50 tests, OK (19 before this change) |
| `serve.test_runconfig` | 9, OK |
| `serve.test_monitor` | 10, OK |
| `serve.test_lifecycle` | 9, OK |
| `serve.test_security` | 23, OK |
| `tools.test_strata_profile` | 28, OK |
| `serve.test_server` | 314, 3 errors, the same 3 on `8cd43878` (`No module named 'regex'` in this environment) |
| `node --check serve/web/app.js` | OK |
New tests cover: the history (order, open entry, ring of 50, engine starts, whole lines and 1 MiB, a log that was
emptied or replaced, a long tail without a newline, a batch that cannot be parsed, lines written during a tuning),
`finding_settings` (and that every setting `strata_profile.findings` names is mapped, so a change of its wording fails),
the settings rows, the tune before/after (numbers compared as numbers, the table without the summary line), the
redirects, the key guards, and that the tab's ids are in `index.html` and `app.js`.
## Measured, on a named PC
RTX 5070 Ti 16 GB + Ryzen 7 5800X3D, Swift 1.5 IQ3_S, one run each:
- The timing switches (on while `profile` is on) cost 3.9-4.7% on an 8K-token prompt read, decode within its noise:
`bench/results/2026-10-15-timing-switches-rtx-5070-ti`.
- A profile run from the tab took 47 s with the model loaded.
- The tuning took 681 s and wrote `--pcie-frac 0.35 --spec-min-p 0.70 --adapt-every 1 --adapt-swaps 160
--adapt-decay 0.97` (96.6 tok/s by the calibration's own measurement). One run, no `bench/results` folder for it.
## Checked end to end on that PC
Headless Chromium against the running server with `"profile": true`: no console error, page error or failed request.
- `/health` has the key; the tab shows; `#profile` lands on it; the off card is hidden.
- A chat request: Last request shows its decode tok/s, hit rate and window split; while it runs the in-flight line shows
"A request is running (Generating · ...)"; the history row appears.
- Run the profile: "Running · 2 s" with the tool's step line; with the tab switched away for 13 s the page sent 2
`/profile/status` requests (the 10 s away poll); back on the tab: "Done in 47 s", the three tables, 9 findings with 9
setting chips, the report path.
- Tune: the confirm text appears and Cancel changes nothing.
- "Model settings" in the settings card opens About with the `vram_reserve_mib` input focused.
- `GET /profile` -> 302 `./#profile`, `/profile/` -> `../#profile`. Light and dark themes both render.
A sub-agent reviewer read the diff and ran the checks above on a second mock server and a headless browser; it gave 12
findings (the history filling with the calibration's requests during a tune, a wrong "no setting changed" after a
re-tune, parts of the page rebuilt every 2 s while a run goes, a misleading note for flags the server adds itself, and
smaller ones). All 12 are fixed in this commit, each with a test where the code can be tested. For the fourth I chose
the plain wording: the row says "the run config file has X; the server reads it when Strata starts", because the next
start's flags (`engine_args`, the shell's environment) are not the file's.
One thing in the design is wrong and is not followed: "If the summary says the defaults were already the fastest, the
table has no bold row". A second tuning puts earlier tuned values back to the defaults, so rows do change; the tab
says that in words.
The standalone companion, [Strata Profile Studio](https://github.com/qiuzan2001/strata-profile-studio) (Python standard library only), reads this tool's reports and compares runs against the noise floor of the PC, with a sign test over the agent turns.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
En el sitio
Enlaces a install, modelos, releases.