Skip to content

Commit 42f51c4

Browse files
authored
[MISC] Maintain order of parameters in perf report and add download csv link. (#1991)
* Maintain order of parameters as much as possible. * Add artifact download link to markdown report.
1 parent a56a8a8 commit 42f51c4

File tree

1 file changed

+60
-34
lines changed

1 file changed

+60
-34
lines changed

.github/workflows/alarm.yml

Lines changed: 60 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626

2727
- name: Install deps
2828
run: |
29-
python -m pip install --quiet --upgrade wandb
29+
python -m pip install --quiet --upgrade wandb frozendict
3030
3131
- name: Download artifacts from triggering run
3232
id: dl
@@ -71,6 +71,7 @@ jobs:
7171
7272
import os, sys, json, re, math, statistics
7373
import wandb
74+
from frozendict import frozendict
7475
from pathlib import Path
7576
import csv
7677
@@ -98,23 +99,44 @@ jobs:
9899
99100
METRIC_KEYS = ("compile_time", "runtime_fps", "realtime_factor")
100101
101-
def _normalize_kv_id(kv: dict) -> str:
102-
return "-".join(f"{k}={v}" for k, v in sorted(kv.items()))
103-
104-
def normalize_benchmark_id(bid: str) -> str:
105-
kv = dict(map(str.strip, token.split("=", 1)) for token in bid.split("-"))
106-
return _normalize_kv_id(kv)
107-
108-
def parse_norm_id(nbid: str) -> dict:
102+
def parse_benchmark_id(bid: str) -> dict:
109103
kv = {}
110-
if nbid:
111-
for token in nbid.split("-"):
104+
if bid:
105+
for token in bid.split("-"):
112106
token = token.strip()
113107
if token and "=" in token:
114108
k, v = token.split("=", 1)
115109
kv[k.strip()] = v.strip()
116110
return kv
117111
112+
def normalize_benchmark_id(bid: str) -> frozendict[str, str]:
113+
return frozendict(parse_benchmark_id(bid))
114+
115+
def get_param_names(bids: tuple[frozendict]) -> tuple[str, ...]:
116+
"""
117+
Merge a list of tuples into a single tuple of keys that:
118+
- Preserves the relative order of keys within each tuple
119+
- Gives precedence to later tuples when conflicts arise
120+
"""
121+
merged = list(bids[-1])
122+
merged_set = set(merged)
123+
for tup in bids[:-1]:
124+
for key in tup:
125+
if key not in merged_set:
126+
merged.append(key)
127+
merged_set.add(key)
128+
return tuple(merged)
129+
130+
def sort_key(d):
131+
key_list = []
132+
for col in params_name:
133+
if col in d:
134+
val = d[col]
135+
key_list.append((0, val))
136+
else:
137+
key_list.append((1, None))
138+
return key_list
139+
118140
def artifacts_parse_csv_summary(current_txt_path):
119141
out = {}
120142
for line in current_txt_path.read_text().splitlines():
@@ -125,8 +147,8 @@ jobs:
125147
record[k] = float(kv.pop(k))
126148
except (ValueError, TypeError, KeyError):
127149
pass
128-
bid = _normalize_kv_id(kv)
129-
out[bid] = record
150+
nbid = frozendict(kv)
151+
out[nbid] = record
130152
return out
131153
132154
def fmt_num(v, is_int: bool):
@@ -143,7 +165,7 @@ jobs:
143165
current_bm = {}
144166
for csv_path in current_csv_paths:
145167
current_bm |= artifacts_parse_csv_summary(csv_path)
146-
bids_set = set(current_bm.keys())
168+
bids_set = frozenset(current_bm.keys())
147169
assert bids_set
148170
149171
# ----- W&B baselines -----
@@ -199,7 +221,6 @@ jobs:
199221
# Extract benchmark ID and normalize it to make sure it does not depends on key ordering.
200222
# Note that the rigid body benchmark suite is the only one being supported for now.
201223
sid, bid = config["benchmark_id"].split("-", 1)
202-
nbid = normalize_benchmark_id(bid)
203224
if sid != "rigid_body":
204225
continue
205226
@@ -217,15 +238,15 @@ jobs:
217238
continue
218239
219240
# Store all the records into a dict
241+
nbid = normalize_benchmark_id(bid)
220242
records_by_rev.setdefault(rev, {})[nbid] = {
221243
metric: summary[metric] for metric in METRIC_KEYS
222244
}
223245
224246
# ----- build TWO tables -----
225247
226-
# Parse benchmark IDs into key-value dicts
227-
params_map_by_bid = {bid: parse_norm_id(bid) for bid in current_bm.keys()}
228-
params_name = sorted(set(e for kv in params_map_by_bid.values() for e in kv.keys()))
248+
# Parse benchmark IDs into key-value dicts while preserving order
249+
params_name = get_param_names(tuple((tuple(kv.keys())) for kv in current_bm.keys()))
229250
230251
reg_found = False
231252
tables = {}
@@ -244,13 +265,12 @@ jobs:
244265
header = "| " + " | ".join(header_cells) + " |"
245266
align = "|:------:|" + "|".join([":---" for _ in params_name]) + "|---:|---:|---:|"
246267
247-
for bid in sorted(current_bm.keys()):
268+
for bid in sorted(current_bm.keys(), key=sort_key):
248269
value_cur = current_bm[bid][metric]
249270
is_int = isinstance(value_cur, int) or value_cur.is_integer()
250271
value_repr = fmt_num(value_cur, is_int)
251272
252-
params_map = params_map_by_bid[bid]
253-
params_repr = [params_map.get(k, "-") for k in params_name]
273+
params_repr = [bid.get(k, "-") for k in params_name]
254274
info = {
255275
**dict(zip(params_name, params_repr)),
256276
"current": value_cur,
@@ -382,6 +402,16 @@ jobs:
382402
echo "CONCLUSION=$([ "$EXIT_CODE" = "0" ] && echo 'success' || echo 'failure')" >> "$GITHUB_ENV"
383403
echo "HAS_REGRESSIONS=$([ "$EXIT_CODE" = "$EXIT_CODE_REGRESSION" ] && echo 1 || echo 0)" >> "$GITHUB_ENV"
384404
405+
- name: Upload benchmark comparisons in CSV
406+
id: upload
407+
uses: actions/upload-artifact@v4
408+
with:
409+
name: benchmark-comparison-tables
410+
path: |
411+
runtime_fps.csv
412+
compile_time.csv
413+
if-no-files-found: warn
414+
385415
- name: Add PR comment
386416
if: ${{ env.SCRIPT_OUTPUT != '' }}
387417
uses: actions/github-script@v8
@@ -409,15 +439,21 @@ jobs:
409439
});
410440
411441
- name: Publish PR check
412-
if: always()
413442
uses: actions/github-script@v8
414443
env:
415444
CHECK_NAME: Benchmark Comparison
416-
CHECK_BODY: ${{ env.CHECK_OUTPUT }}
445+
CHECK_OUTPUT: ${{ env.CHECK_OUTPUT }}
417446
CONCLUSION: ${{ env.CONCLUSION }}
418447
HAS_REGRESSIONS: ${{ env.HAS_REGRESSIONS }}
448+
ARTIFACT_URL: ${{ steps.upload.outputs.artifact-url }}
419449
with:
420450
script: |
451+
const artifactUrl = process.env.ARTIFACT_URL || '';
452+
let body = process.env.CHECK_OUTPUT || '';
453+
if (body && artifactUrl) {
454+
body += `\n\n**Artifact:** [Download raw data](${artifactUrl})`;
455+
}
456+
421457
const summary = (process.env.HAS_REGRESSIONS || '0') === '1'
422458
? '🔴 Regressions detected. See tables below.'
423459
: '✅ No regressions detected. See tables below.';
@@ -431,16 +467,6 @@ jobs:
431467
output: {
432468
title: process.env.CHECK_NAME,
433469
summary,
434-
text: process.env.CHECK_BODY || undefined
470+
text: body || undefined
435471
}
436472
});
437-
438-
- name: Upload benchmark comparisons in CSV & JSONL
439-
if: always()
440-
uses: actions/upload-artifact@v4
441-
with:
442-
name: benchmark-comparison-tables
443-
path: |
444-
runtime_fps.csv
445-
compile_time.csv
446-
if-no-files-found: warn

0 commit comments

Comments
 (0)