Skip to content

Commit c9ef0dd

Browse files
fix ci fps percent change
1 parent 9dbe363 commit c9ef0dd

8 files changed

Lines changed: 117 additions & 23 deletions

File tree

.github/workflows/render.yml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ jobs:
9494
echo "scene_metrics_found=true" >> "$GITHUB_OUTPUT"
9595
fi
9696
97+
- name: Restore fps history
98+
id: restore_fps_history
99+
run: |
100+
scripts/ci/git-restore-artifact-branch-file "$FPS_HISTORY.csv"
101+
if compgen -G "/tmp/$FPS_HISTORY.csv" >/dev/null; then
102+
echo "fps_history_found=true" >> "$GITHUB_OUTPUT"
103+
fi
104+
97105
- name: Restore FPS metrics
98106
if: steps.restore_metric_history.outputs.scene_metrics_found != 'true'
99107
uses: actions/cache/restore@v5
@@ -124,12 +132,7 @@ jobs:
124132
run: scripts/ci/run-playwright-render
125133

126134
- name: Track FPS value
127-
run: |
128-
PREV=$(scripts/ci/previous-fps-value)
129-
echo "Previous value: $PREV fps"
130-
percent_change=$(scripts/ci/percent-change --new "$FPS_VALUE" --old "$PREV")
131-
echo "$FPS_VALUE fps ($percent_change% change)"
132-
echo "PERCENT_CHANGE=$percent_change" >> "$GITHUB_ENV"
135+
run: scripts/ci/track-fps-history
133136

134137
- name: Plot metric CSVs
135138
if: always()

scripts/ci/combine-render-images

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const screenshotName = requiredEnv('SCREENSHOT_NAME');
1818
const fpsSamplesName = requiredEnv('FPS_SAMPLES_NAME');
1919
const sceneMetricsName = requiredEnv('SCENE_METRICS_NAME');
2020
const feCoverageName = requiredEnv('FE_COVERAGE_NAME');
21+
const fpsHistoryName = requiredEnv('FPS_HISTORY');
2122
const renderImageScale = Number(process.env.COMBINED_RENDER_IMAGE_SCALE || 3);
2223
if (!Number.isFinite(renderImageScale) || renderImageScale <= 0) {
2324
console.error('COMBINED_RENDER_IMAGE_SCALE must be a positive number');
@@ -70,7 +71,11 @@ const rows = [
7071
screenshotCell('404'),
7172
screenshotCell('dropdown'),
7273
],
73-
[['fe coverage', imagePath(feCoverageName)], [], []],
74+
[
75+
['fe coverage', imagePath(feCoverageName)],
76+
['fps history', imagePath(fpsHistoryName)],
77+
[],
78+
],
7479
];
7580

7681
const escapeHtml = value => String(value)

scripts/ci/git-publish-render-artifacts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set -euo pipefail
55
: "${COMBINED_RENDER_IMAGE:?COMBINED_RENDER_IMAGE is required}"
66
: "${CHOSEN_FPS:?CHOSEN_FPS is required}"
77
: "${SCENE_METRICS_NAME:?SCENE_METRICS_NAME is required}"
8+
: "${FPS_HISTORY:?FPS_HISTORY is required}"
89
: "${FE_COVERAGE_NAME:?FE_COVERAGE_NAME is required}"
910
: "${GITHUB_REPOSITORY:?GITHUB_REPOSITORY is required}"
1011
: "${GITHUB_RUN_ID:?GITHUB_RUN_ID is required}"
@@ -28,11 +29,11 @@ for image in "$COMBINED_RENDER_IMAGE"; do
2829
done
2930
cp "/tmp/$CHOSEN_FPS.csv" "$worktree/build/latest/$CHOSEN_FPS.csv"
3031
cp "/tmp/$CHOSEN_FPS.csv" "$worktree/build/${GITHUB_RUN_ID}/$CHOSEN_FPS.csv"
31-
for metric in "/tmp/$SCENE_METRICS_NAME"*.csv "/tmp/$FE_COVERAGE_NAME.csv"; do
32+
for metric in "/tmp/$SCENE_METRICS_NAME"*.csv "/tmp/$FPS_HISTORY.csv" "/tmp/$FE_COVERAGE_NAME.csv"; do
3233
[ -f "$metric" ] && cp "$metric" "$worktree/$(basename "$metric")"
3334
done
3435
git -C "$worktree" add build
35-
for artifact in "$worktree/$SCENE_METRICS_NAME"*.csv "$worktree/$FE_COVERAGE_NAME.csv"; do
36+
for artifact in "$worktree/$SCENE_METRICS_NAME"*.csv "$worktree/$FPS_HISTORY.csv" "$worktree/$FE_COVERAGE_NAME.csv"; do
3637
[ -f "$artifact" ] && git -C "$worktree" add "$(basename "$artifact")"
3738
done
3839
git -C "$worktree" commit -m "Update CI image artifacts for ${GITHUB_RUN_ID}" || true

scripts/ci/previous-fps-value

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ def required_env(name):
1212
return value
1313

1414

15-
chosen_metrics = required_env("CHOSEN_METRICS")
15+
fps_history = required_env("FPS_HISTORY")
1616
fallback = required_env("FALLBACK_FPS_VALUE")
17-
path = f"/tmp/{chosen_metrics}.csv"
17+
path = f"/tmp/{fps_history}.csv"
1818

1919
try:
2020
with open(path, newline="") as f:
@@ -28,9 +28,9 @@ except FileNotFoundError:
2828
rows = []
2929

3030
values = []
31-
for row in rows[:-1]:
31+
for row in rows:
3232
try:
33-
values.append(float(row["FPS"]))
33+
values.append(float(row["fps"]))
3434
except (KeyError, TypeError, ValueError):
3535
pass
3636

scripts/ci/render-env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
: "${CHOSEN_FPS:=${FPS_SAMPLES_NAME}_${CHOSEN_NAME}}"
66
: "${SCENE_METRICS_NAME:=scene_metrics}"
77
: "${CHOSEN_METRICS:=${SCENE_METRICS_NAME}_${CHOSEN_NAME}}"
8+
: "${FPS_HISTORY:=fps_history}"
89
: "${COMBINED_RENDER_IMAGE:=render_summary}"
910
: "${COMBINED_RENDER_IMAGE_SCALE:=3}"
1011
: "${FE_COVERAGE_NAME:=fe_coverage}"

scripts/ci/test_python_scripts.py

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,35 +64,67 @@ def test_percent_change_handles_zero_old_value(self):
6464
self.assertEqual(code, 0)
6565
self.assertEqual(stdout, "n/a\n")
6666

67-
def test_previous_fps_value_reads_previous_row(self):
68-
metrics_name = f"scene_metrics_test_{os.getpid()}"
69-
path = Path("/tmp") / f"{metrics_name}.csv"
67+
def test_previous_fps_value_reads_latest_history_row(self):
68+
history_name = f"fps_history_test_{os.getpid()}"
69+
path = Path("/tmp") / f"{history_name}.csv"
7070
path.write_text(
71-
"epoch, FPS, Calls\n"
72-
"1, 80, 1\n"
73-
"2, 90, 1\n"
74-
"3, 100, 1\n",
71+
"fps,% change\n"
72+
"80,0.00\n"
73+
"90,12.50\n"
74+
"100,11.11\n",
7575
)
7676
try:
7777
code, stdout, stderr = run_script("previous-fps-value", env={
78-
"CHOSEN_METRICS": metrics_name,
78+
"FPS_HISTORY": history_name,
7979
"FALLBACK_FPS_VALUE": "100",
8080
})
8181
finally:
8282
path.unlink(missing_ok=True)
8383

8484
self.assertEqual(code, 0)
85-
self.assertEqual(stdout, "90.00\n")
85+
self.assertEqual(stdout, "100.00\n")
8686
self.assertEqual(stderr, "")
8787

8888
def test_previous_fps_value_uses_fallback_without_history(self):
8989
code, stdout, _stderr = run_script("previous-fps-value", env={
90-
"CHOSEN_METRICS": f"missing_metrics_{os.getpid()}",
90+
"FPS_HISTORY": f"missing_history_{os.getpid()}",
9191
"FALLBACK_FPS_VALUE": "100",
9292
})
9393
self.assertEqual(code, 0)
9494
self.assertEqual(stdout, "100\n")
9595

96+
def test_track_fps_history_appends_csv(self):
97+
history_name = f"fps_history_track_test_{os.getpid()}"
98+
path = Path("/tmp") / f"{history_name}.csv"
99+
github_env = Path("/tmp") / f"github_env_track_test_{os.getpid()}"
100+
path.write_text(
101+
"fps,% change,commit sha\n"
102+
"100.00,0.00,old123\n")
103+
try:
104+
code, stdout, stderr = run_script("track-fps-history", env={
105+
"FPS_HISTORY": history_name,
106+
"FPS_VALUE": "106.04",
107+
"FALLBACK_FPS_VALUE": "100",
108+
"GITHUB_SHA": "0123456789abcdef",
109+
"GITHUB_ENV": str(github_env),
110+
"PATH": os.environ["PATH"],
111+
})
112+
self.assertEqual(code, 0)
113+
self.assertEqual(
114+
stdout,
115+
"Previous value: 100.00 fps\n"
116+
"106.04 fps (6.04% change)\n")
117+
self.assertEqual(stderr, "")
118+
self.assertEqual(
119+
path.read_text(),
120+
"fps,% change,commit sha\n"
121+
"100.00,0.00,old123\n"
122+
"106.04,6.04,0123456789\n")
123+
self.assertEqual(github_env.read_text(), "PERCENT_CHANGE=6.04\n")
124+
finally:
125+
path.unlink(missing_ok=True)
126+
github_env.unlink(missing_ok=True)
127+
96128
def test_render_url_records_outputs_field_separated_records(self):
97129
with tempfile.NamedTemporaryFile("w", delete=False) as file:
98130
json.dump([{

scripts/ci/track-fps-history

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env python3
2+
import csv
3+
import os
4+
from pathlib import Path
5+
import subprocess
6+
7+
8+
fps_history = os.environ["FPS_HISTORY"]
9+
fps_value = os.environ["FPS_VALUE"]
10+
commit_sha = os.environ["GITHUB_SHA"][:10]
11+
github_env = os.environ["GITHUB_ENV"]
12+
csv_path = Path("/tmp") / f"{fps_history}.csv"
13+
csv_header = ["fps", "% change", "commit sha"]
14+
15+
previous = subprocess.check_output(
16+
["scripts/ci/previous-fps-value"],
17+
text=True,
18+
).strip()
19+
print(f"Previous value: {previous} fps")
20+
21+
percent_change = subprocess.check_output([
22+
"scripts/ci/percent-change",
23+
"--new",
24+
fps_value,
25+
"--old",
26+
previous,
27+
], text=True).strip()
28+
print(f"{fps_value} fps ({percent_change}% change)")
29+
30+
with open(github_env, "a") as env_file:
31+
env_file.write(f"PERCENT_CHANGE={percent_change}\n")
32+
33+
if not csv_path.exists():
34+
csv_path.write_text(",".join(csv_header) + "\n")
35+
36+
with csv_path.open("a", newline="") as csv_file:
37+
writer = csv.writer(csv_file)
38+
writer.writerow([fps_value, percent_change, commit_sha])

scripts/metric_plot.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ const title = (basename, prefix) => {
370370
const inferCsvPlot = ({ headers, rows }, filename = '') => {
371371
const basename = path.basename(filename);
372372
const isSceneMetricsCsv = /^scene_metrics(?:_[^/]+)?\.csv$/.test(basename);
373+
const isFpsHistoryCsv = basename === 'fps_history.csv';
373374
const firstHeader = headers[0];
374375
const xHeader = headers.find(header =>
375376
['elapsed seconds', 'elapsedSeconds'].includes(header));
@@ -405,6 +406,18 @@ const inferCsvPlot = ({ headers, rows }, filename = '') => {
405406
latestCommitSha: latestCommitShaFor(rows, ['percent']),
406407
};
407408
}
409+
if (isFpsHistoryCsv && headers.includes('fps')) {
410+
return {
411+
title: 'FPS history',
412+
xLabel: 'Runs',
413+
yMin: 0,
414+
yMaxBaseline: 200,
415+
yTickInterval: 100,
416+
decimalValues: true,
417+
samples: rows.map((row, index) => sampleFor(row, index, 'fps')),
418+
latestCommitSha: latestCommitShaFor(rows, ['fps']),
419+
};
420+
}
408421
if (headers.includes('FPS')) {
409422
if (isSceneMetricsCsv) {
410423
return {
@@ -495,6 +508,7 @@ function printUsage() {
495508
'',
496509
'Supported CSV inputs:',
497510
' fps_samples.csv Plots the fps column against elapsed seconds.',
511+
' fps_history.csv Plots historical fps values.',
498512
' fe_coverage.csv Plots the percent column.',
499513
' scene_metrics.csv Plots numeric columns.',
500514
'',

0 commit comments

Comments
 (0)