Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ bash scripts/run-local.sh <branch>...

It starts the backend if it's down (`client-dev`, or `scylla-dev` plus `cargo run` when a target changes `scylla-server/`), and serves each target's client on the next free port; parallel runs (one per session or agent) each get their own. With no branches it reports what's running.

Report each branch's client URL and the backend. A failed compile or a stale-backend warning is a finding: show it to the user. Stop a client with `kill <pid>` from its line.
Report each branch's client URL and the backend. A failed compile or a stale-backend warning is a finding: show it to the user. Stop a client with `kill <pid>` from its line. When every port is taken it lists what holds each; clients from other checkouts are the user's, so ask before stopping them.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# port in 4200-4210, in the background, and print `<branch> client=<url> pid=<pid> log=<file>` once
# it has compiled. Re-running for a worktree that is still being served prints its existing client.
# Runs `npm ci` first if node_modules lacks ng (missing or half-installed). Exits 1, with the log's
# tail, if the build fails.
# tail, if the build fails, or with what holds each port if none is free.
set -euo pipefail
wt=$(cd "${1:?usage: serve.sh <argos-worktree>}" && pwd)
branch=$(git -C "$wt" rev-parse --abbrev-ref HEAD)
Expand All @@ -27,7 +27,14 @@ trap 'rmdir "$lock" 2>/dev/null || true' EXIT
claimed() { for f in "$state"/*.port; do [ -f "$f" ] && [ "$(cat "$f")" = "$1" ] && kill -0 "$(cat "${f%.port}.pid")" 2>/dev/null && return; done; return 1; }
port=
for p in $(seq 4200 4210); do up "$p" || claimed "$p" || { port=$p && break; }; done
[ -n "$port" ] || { echo "serve: no free port in 4200-4210" >&2 && exit 1; }
# Name what holds each port, so a stale client from another checkout can be stopped (lsof, where there is one).
holders() {
for p in $(seq 4200 4210); do
pid=$(lsof -nP -iTCP:"$p" -sTCP:LISTEN -t 2>/dev/null | head -1) || true
if [ -n "$pid" ]; then echo " $p pid=$pid $(lsof -a -p "$pid" -d cwd -Fn 2>/dev/null | sed -n 's/^n//p')"; fi
done
}
[ -n "$port" ] || { echo "serve: no free port in 4200-4210, held by:" >&2 && holders >&2 && exit 1; }
echo $$ >"$key.pid" && echo "$port" >"$key.port" # claimed by this script until ng serve's pid replaces it
rmdir "$lock" && trap - EXIT

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: Playwright CLI verification of the graph page — modes, controls,
user-invocable: true
---

Get the branch's client running with `run-local <branch>`; its URL is `BASE_URL`. Then run the base checks:
Get the branch's client running with `run-local <branch>`; its URL is `BASE_URL`. The scripts need `playwright-cli` (`npm i -g @playwright/cli`, then `playwright-cli install-browser chromium`; cloud containers use their preinstalled Chromium). Then run the base checks:

```
bash scripts/check.sh <branch> "$BASE_URL"
Expand All @@ -19,4 +19,6 @@ Go further where the diff points, by hand in the same session (`P="playwright-cl
- The seeded run: click Select Run, then `bash scripts/select-run.sh <branch> $(bash scripts/seed.sh)`.
- Screenshots: `$P screenshot --filename=pictures/<branch>/verify-graph/NN-<name>.png` (gitignored).

When the diff touches rendering or the live data path, measure it too: `bash scripts/perf.sh <branch> "$BASE_URL" [<topic>,…]` prints retained JS heap, allocation rate, frame rate and long tasks (`scripts/perf.js`), then the browser's GPU-process memory, where a WebGL chart's buffers show up. The numbers drift with machine load, so run the branch and its base side by side, twice, at the same topics. Calypso sends about one point a second per topic and has no rate setting, so the chart's own data is small next to the app's: a JS-heap gap of a few MB is noise, and more topics widen real ones.

When a hand check keeps coming back, add it to `check.js`. Report `check.sh`'s lines plus one line per hand check, and the screenshot folder. `$P close` at the end.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ async (page) => {
await button('Realtime').click();
await text('Real Time').waitFor({ timeout: 5000 });
await page.getByRole('combobox', { name: 'Quick Select' }).click();
await page.getByRole('option').first().waitFor({ timeout: 5000 });
const options = await page.getByRole('option').count();
if (options !== 11) throw new Error(`${options} Quick Select options, not 11`);
await page.getByRole('option', { name: '5 minutes', exact: true }).click();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
async (page) => {
// Live-mode cost of the graph page with __TOPICS__ selected: retained JS heap after a GC, how fast it allocates
// (heap growth between 100 ms samples, GC drops ignored), and frame rate. Compare branches at the same topics.
const topics = '__TOPICS__'.split(',');
await page.goto(`__URL__/graph?topics=${encodeURIComponent(topics.join(','))}`);
await page.getByText('Real Time').first().waitFor({ timeout: 30000 });
const cdp = await page.context().newCDPSession(page);
const heap = async (gc) => {
if (gc) await cdp.send('HeapProfiler.collectGarbage');
return (await cdp.send('Runtime.getHeapUsage')).usedSize / 1e6;
};
await page.waitForTimeout(20000); // fill the live window
let alloc = 0, prev = await heap(false);
const t0 = Date.now();
while (Date.now() - t0 < 20000) {
await page.waitForTimeout(100);
const h = await heap(false);
if (h > prev) alloc += h - prev;
prev = h;
}
const allocMBps = alloc / ((Date.now() - t0) / 1000);
const frames = await page.evaluate(() => new Promise((done) => {
let n = 0, worst = 0, longTasks = 0, last = performance.now();
const end = last + 10000;
new PerformanceObserver((l) => (longTasks += l.getEntries().length)).observe({ type: 'longtask' });
const tick = (t) => {
worst = Math.max(worst, t - last);
last = t;
n++;
if (t < end) requestAnimationFrame(tick);
else done({ fps: n / 10, worstFrameMs: Math.round(worst), longTasks });
};
requestAnimationFrame(tick);
}));
const retainedMB = await heap(true);
return `retained JS heap ${retainedMB.toFixed(1)} MB, allocating ${allocMBps.toFixed(1)} MB/s, ` +
`${frames.fps} fps, worst frame ${frames.worstFrameMs} ms, ${frames.longTasks} long tasks`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# perf.sh <branch> <base-url> [<topic>,…]: measure the graph page live in <branch>'s playwright-cli session
# (perf.js: JS heap, allocation rate, frames; about a minute), then its browser's GPU-process memory, where
# a WebGL chart's buffers show up. Default topics: four BMS ones. Numbers are relative: compare branches.
set -euo pipefail
here=$(cd "$(dirname "$0")" && pwd)
branch=${1:?usage: perf.sh <branch> <base-url> [<topic>,…]}; url=${2:?usage: perf.sh <branch> <base-url> [<topic>,…]}; url=${url%/}
topics=${3:-BMS/Segment_Total_Volt/0,BMS/PerCell/Alpha/3/Volts/5,BMS/PerCell/Alpha/3/Volts/4,BMS/PerCell/Alpha/4/Therms/0}
playwright-cli list | grep -q "^- $branch:" || bash "$here/open.sh" "$branch" "$url/graph" >/dev/null
code=$(sed -e "s|__URL__|$url|; s|__TOPICS__|$topics|g" "$here/perf.js")
playwright-cli -s="$branch" --raw run-code "$code" | node -e 'process.stdout.write(JSON.parse(require("fs").readFileSync(0, "utf8")) + "\n")'
# The session's daemon runs its browser; the browser's --type=gpu-process child holds GPU memory.
ps -axo pid=,ppid=,rss=,command= | awk -v s=" $branch " '
{ pid[NR] = $1; ppid[NR] = $2; rss[NR] = $3; cmd[NR] = $0 }
index($0, "cliDaemon") && index($0 " ", s) { daemon[$1] = 1 }
END {
for (i = 1; i <= NR; i++) if (daemon[ppid[i]]) browser[pid[i]] = 1
for (i = 1; i <= NR; i++) if (browser[ppid[i]] && index(cmd[i], "--type=gpu-process")) printf "GPU process %d MB\n", rss[i] / 1024
}'
Loading