Skip to content

Commit a394e13

Browse files
ci: handle missing benchmark baselines
Signed-off-by: Francesco Gargiulo <gargiulo.fr@gmail.com>
1 parent 3906551 commit a394e13

3 files changed

Lines changed: 55 additions & 8 deletions

File tree

.github/workflows/bench-pr.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ jobs:
3333
build_args: "--features lance"
3434
- id: compress-bench
3535
name: Compression
36+
- id: string-bench
37+
name: String Encoding
38+
run_args: "--suite both"
3639
steps:
3740
- uses: runs-on/action@v2
3841
if: github.event.pull_request.head.repo.fork == false
@@ -104,7 +107,8 @@ jobs:
104107
VORTEX_EXPERIMENTAL_PATCHED_ARRAY: "1"
105108
FLAT_LAYOUT_INLINE_ARRAY_NODE: "1"
106109
run: |
107-
bash scripts/bench-taskset.sh target/release_debug/${{ matrix.benchmark.id }} -d gh-json -o results.json
110+
bash scripts/bench-taskset.sh target/release_debug/${{ matrix.benchmark.id }} \
111+
${{ matrix.benchmark.run_args }} -d gh-json -o results.json
108112
109113
- name: Setup AWS CLI
110114
if: github.event.pull_request.head.repo.fork == false

scripts/compare-benchmark-jsons.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,12 @@ def read_jsonl_rows_for_commit(path: str, commit_id: str) -> pd.DataFrame:
184184

185185

186186
def read_latest_baseline_rows(path: str, pr: pd.DataFrame) -> pd.DataFrame:
187-
"""Read rows from the latest history commit matching the PR benchmark."""
187+
"""Read rows from the latest history commit matching the PR benchmark.
188+
189+
A benchmark can be new to the PR workflow and therefore have no baseline
190+
yet. Return an empty frame with the PR schema in that case so the report
191+
can show the measurements without comparison.
192+
"""
188193

189194
pr_identities = set(benchmark_identity_rows(pr)["benchmark_identity"])
190195
if not pr_identities:
@@ -202,7 +207,7 @@ def read_latest_baseline_rows(path: str, pr: pd.DataFrame) -> pd.DataFrame:
202207
baseline_commit_id = commit_id
203208

204209
if baseline_commit_id is None:
205-
raise ValueError("No baseline rows found for the benchmark under test")
210+
return pr.iloc[0:0].copy()
206211

207212
return read_jsonl_rows_for_commit(path, baseline_commit_id)
208213

@@ -230,7 +235,7 @@ def select_latest_baseline_rows(base: pd.DataFrame, pr: pd.DataFrame) -> pd.Data
230235
matches = base_identities[base_identities["benchmark_identity"].isin(pr_identities)]
231236
matches = matches[matches["commit_id"].notna()]
232237
if matches.empty:
233-
raise ValueError("No baseline rows found for the benchmark under test")
238+
return base.iloc[0:0].copy()
234239

235240
baseline_commit_id = matches["commit_id"].iloc[-1]
236241
return base[base["commit_id"] == baseline_commit_id].copy()
@@ -256,6 +261,7 @@ def normalize_measurement_rows(df: pd.DataFrame) -> pd.DataFrame:
256261
columns=["engine", "file_format", "query"],
257262
index=df.index,
258263
)
264+
df["query"] = pd.array(df["query"], dtype="Int64")
259265
return df
260266

261267

@@ -914,11 +920,11 @@ def main() -> None:
914920
title = format_title(benchmark_name, pr)
915921
base = read_latest_baseline_rows(sys.argv[1], pr)
916922

917-
base_commit_id = set(base["commit_id"].unique())
923+
base_commit_ids = set(base["commit_id"].unique())
918924
pr_commit_id = set(pr["commit_id"].unique())
919-
assert len(base_commit_id) == 1, base_commit_id
925+
assert len(base_commit_ids) <= 1, base_commit_ids
920926
assert len(pr_commit_id) == 1, pr_commit_id
921-
base_commit_id = next(iter(base_commit_id))
927+
base_commit_id = next(iter(base_commit_ids), None)
922928
pr_commit_id = next(iter(pr_commit_id))
923929

924930
base_file_sizes, base = split_file_size_rows(base)
@@ -990,13 +996,17 @@ def main() -> None:
990996
if summary_fields:
991997
print("<br>".join(summary_fields))
992998
print("")
999+
if base_commit_id is None:
1000+
print("_No baseline is available for this benchmark yet; PR measurements are shown without comparison._")
1001+
print("")
9931002
if verdict is not None or engine_summary is not None:
9941003
print(format_report_help())
9951004
print("")
9961005
print("---")
9971006
print("")
9981007

9991008
grouped_tables = df3.groupby(["engine", "file_format", "unit"], dropna=False, sort=False)
1009+
base_label = str(base_commit_id)[:8] if base_commit_id is not None else "none"
10001010
for engine, file_format, unit in sorted(grouped_tables.groups.keys(), key=group_sort_key):
10011011
group_df = grouped_tables.get_group((engine, file_format, unit)).sort_values("name")
10021012
group_performance = format_performance(
@@ -1014,7 +1024,7 @@ def main() -> None:
10141024
for name, ratio in zip(group_df["name"], group_df["ratio"])
10151025
],
10161026
f"PR {pr_commit_id[:8]} ({unit})": group_df["value_pr"].map(format_measurement_value),
1017-
f"base {base_commit_id[:8]} ({unit})": group_df["value_base"].map(format_measurement_value),
1027+
f"base {base_label} ({unit})": group_df["value_base"].map(format_measurement_value),
10181028
"ratio (PR/base)": group_df["ratio"].map(format_comparison_ratio),
10191029
}
10201030
)

scripts/tests/test_benchmark_reporting.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,39 @@ def test_comparison_report_groups_by_target_and_unit(tmp_path: Path) -> None:
254254
]
255255

256256

257+
def test_comparison_report_handles_missing_benchmark_baseline(tmp_path: Path) -> None:
258+
base_rows = [stored_custom_row("base-sha", "other timing/fixture", "ms", 12.5)]
259+
pr_rows = [stored_custom_row("pr-sha", "new timing/fixture", "ms", 3.125)]
260+
261+
report = render_report(tmp_path, base_rows, pr_rows, "New benchmark")
262+
263+
assert "No baseline is available for this benchmark yet" in report
264+
assert "base none (ms)" in report
265+
assert markdown_row(report, "new timing/fixture") == [
266+
"new timing/fixture",
267+
"3.125",
268+
"—",
269+
"no baseline",
270+
]
271+
272+
273+
def test_comparison_report_handles_mixed_query_types_in_baseline(tmp_path: Path) -> None:
274+
base_rows = [
275+
stored_custom_row("base-sha", "random-access/fixture", "ms", 12.5),
276+
stored_timing_row("base-sha", "tpch_q01/datafusion:parquet", 100),
277+
]
278+
pr_rows = [stored_custom_row("pr-sha", "random-access/fixture", "ms", 13.0)]
279+
280+
report = render_report(tmp_path, base_rows, pr_rows, "Random Access")
281+
282+
assert markdown_row(report, "random-access/fixture") == [
283+
"random-access/fixture",
284+
"13",
285+
"12.5",
286+
"1.04",
287+
]
288+
289+
257290
def test_comparison_report_retains_sql_analysis(tmp_path: Path) -> None:
258291
targets = [
259292
("parquet", "parquet", 100, 105),

0 commit comments

Comments
 (0)