Skip to content

Commit df3c339

Browse files
authored
Use per-file compression (#131)
1 parent 9738dd8 commit df3c339

3 files changed

Lines changed: 73 additions & 60 deletions

File tree

.github/workflows/process_results.yaml

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,18 @@ jobs:
4848
ref: main
4949
path: asv-runner-code/
5050

51-
# Idempotent migration from the legacy loose-files layout to compressed
52-
# tarballs. No-op once the tarballs exist.
51+
# Migrate from legacy loose uncompressed JSON/YAML files to per-file
52+
# zstd. Idempotent.
5353
- name: Migrate legacy storage layout
5454
run: |
55-
if [ -d asv-runner/data/results ] && [ ! -f asv-runner/data/results.tar.zst ]; then
56-
tar -C asv-runner/data -I 'zstd -19' -cf asv-runner/data/results.tar.zst results
55+
if [ -d asv-runner/data/results/asvrunner ]; then
56+
find asv-runner/data/results/asvrunner -name '*.json' ! -name 'machine.json' -print0 |
57+
xargs -0 -r -P 4 -n 50 zstd --rm -19 -q
5758
fi
58-
if [ -d asv-runner/data/envs ] && [ ! -f asv-runner/data/envs.tar.zst ]; then
59-
tar -C asv-runner/data -I 'zstd -19' -cf asv-runner/data/envs.tar.zst envs
59+
if [ -d asv-runner/data/envs ]; then
60+
find asv-runner/data/envs -name '*.yml' -print0 |
61+
xargs -0 -r -P 4 -n 50 zstd --rm -19 -q
6062
fi
61-
rm -rf asv-runner/data/results asv-runner/data/envs
6263
6364
- name: Setup Python
6465
uses: actions/setup-python@v6
@@ -74,14 +75,21 @@ jobs:
7475
- name: Show environment packages
7576
run: uv pip freeze
7677

77-
# Extract results.tar.zst into asv_bench/ so `asv publish` and
78-
# process_results.py see the same paths as before. Extract envs.tar.zst
79-
# back under asv-runner/data/envs/ so make_issues.py can read per-SHA
80-
# env files. The extracted dirs are gitignored.
81-
- name: Extract result and env archives
78+
# Decompress per-SHA results into asv_bench/results/asvrunner/ where
79+
# asv publish and process_results.py expect them. benchmarks.json
80+
# and machine.json are stored uncompressed and copied as-is. Envs are
81+
# decompressed in place under data/envs/ so make_issues.py can read
82+
# <sha>.yml directly; the decompressed *.yml files are gitignored.
83+
# Single batched zstd invocation per group amortizes process startup.
84+
- name: Decompress results and envs
8285
run: |
83-
tar -I zstd -xf asv-runner/data/results.tar.zst -C asv_bench/
84-
tar -I zstd -xf asv-runner/data/envs.tar.zst -C asv-runner/data/
86+
mkdir -p asv_bench/results/asvrunner
87+
cp asv-runner/data/results/benchmarks.json asv_bench/results/
88+
cp asv-runner/data/results/asvrunner/machine.json asv_bench/results/asvrunner/
89+
find asv-runner/data/results/asvrunner -name '*.json.zst' -print0 |
90+
xargs -0 -r zstd -d -q --output-dir-flat asv_bench/results/asvrunner
91+
find asv-runner/data/envs -name '*.yml.zst' -print0 |
92+
xargs -0 -r zstd -d -q --output-dir-flat asv-runner/data/envs
8593
8694
- name: Publish ASV Benchmarks
8795
run: cd asv_bench && asv publish
@@ -97,10 +105,10 @@ jobs:
97105
env:
98106
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
99107

100-
# Save our parquet+docs, refetch the latest tarballs (a concurrent
101-
# run_asvs merge may have updated them while asv publish was running),
102-
# restore our parquet+docs over the fresh tarballs, then orphan
103-
# force-push. Retry on lease failure.
108+
# Save our parquet+docs, refetch the latest tree (a concurrent
109+
# run_asvs merge may have added new <sha>.json.zst files while
110+
# asv publish was running), restore our parquet+docs over the fresh
111+
# tree, then orphan force-push. Retry on lease failure.
104112
- name: Push results
105113
run: |
106114
SAVE=$(mktemp -d)
@@ -114,16 +122,18 @@ jobs:
114122
git config user.name "github-actions[bot]"
115123
git config user.email "github-actions[bot]@users.noreply.github.com"
116124
117-
# Idempotent migration from legacy loose-files layout.
118-
if [ -d data/results ] && [ ! -f data/results.tar.zst ]; then
119-
tar -C data -I 'zstd -19' -cf data/results.tar.zst results
125+
# Migrate from legacy loose uncompressed files to per-file zstd.
126+
# Idempotent.
127+
if [ -d data/results/asvrunner ]; then
128+
find data/results/asvrunner -name '*.json' ! -name 'machine.json' -print0 |
129+
xargs -0 -r -P 4 -n 50 zstd --rm -19 -q
120130
fi
121-
if [ -d data/envs ] && [ ! -f data/envs.tar.zst ]; then
122-
tar -C data -I 'zstd -19' -cf data/envs.tar.zst envs
131+
if [ -d data/envs ]; then
132+
find data/envs -name '*.yml' -print0 |
133+
xargs -0 -r -P 4 -n 50 zstd --rm -19 -q
123134
fi
124-
rm -rf data/results data/envs
125135
126-
# Restore our parquet+docs over the freshly fetched tarballs.
136+
# Restore our parquet+docs over the freshly fetched tree.
127137
rm -rf data/results.parquet docs
128138
cp -r "$SAVE/results.parquet" data/results.parquet
129139
cp -r "$SAVE/docs" docs

.github/workflows/run_asvs_2026_01_04.yaml

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,18 @@ jobs:
6868
git config user.name "github-actions[bot]"
6969
git config user.email "github-actions[bot]@users.noreply.github.com"
7070
71-
# One-shot migration from the legacy loose-files layout. Idempotent.
72-
if [ -d data/results ] && [ ! -f data/results.tar.zst ]; then
73-
tar -C data -I 'zstd -19' -cf data/results.tar.zst results
71+
# Migrate from legacy loose uncompressed JSON/YAML files to
72+
# per-file zstd. Idempotent: subsequent runs find no *.json
73+
# (besides machine.json, excluded) or *.yml and the find
74+
# produces no input.
75+
if [ -d data/results/asvrunner ]; then
76+
find data/results/asvrunner -name '*.json' ! -name 'machine.json' -print0 |
77+
xargs -0 -r -P 4 -n 50 zstd --rm -19 -q
7478
fi
75-
if [ -d data/envs ] && [ ! -f data/envs.tar.zst ]; then
76-
tar -C data -I 'zstd -19' -cf data/envs.tar.zst envs
79+
if [ -d data/envs ]; then
80+
find data/envs -name '*.yml' -print0 |
81+
xargs -0 -r -P 4 -n 50 zstd --rm -19 -q
7782
fi
78-
rm -rf data/results data/envs
7983
8084
cd ..
8185
sha="$(python3 asv-runner-code/ci/find_commit_to_run.py --input-path=asv-runner/data/ --repo-path=.)"
@@ -116,7 +120,8 @@ jobs:
116120
117121
# Build pandas at the claimed SHA and run the ASV suite. No concurrency
118122
# lock here — multiple workflow runs benchmark different SHAs in parallel.
119-
# Outputs are uploaded as a workflow artifact for the merge job.
123+
# The new <sha>.json and <sha>.yml are zstd-compressed before upload so
124+
# the merge job can drop them into the storage tree as-is.
120125
benchmark:
121126
name: Run benchmarks
122127
needs: claim
@@ -160,17 +165,20 @@ jobs:
160165
cp asv_bench/results/asvrunner/machine.json /tmp/upload/results/asvrunner/
161166
cp asv_bench/results/asvrunner/${SHORT_SHA}-existing*.json /tmp/upload/results/asvrunner/${SHA}.json
162167
pixi list -e asv --fields name,version > /tmp/upload/envs/${SHA}.yml
168+
# Compress per-SHA files. benchmarks.json and machine.json stay
169+
# uncompressed (small, overwritten each run, read directly).
170+
zstd --rm -19 -q /tmp/upload/results/asvrunner/${SHA}.json
171+
zstd --rm -19 -q /tmp/upload/envs/${SHA}.yml
163172
164173
- name: Upload artifact
165174
uses: actions/upload-artifact@v4
166175
with:
167176
name: asv-results-${{ needs.claim.outputs.sha }}
168177
path: /tmp/upload/
169178

170-
# Layer this run's results into the latest tarballs and orphan force-push.
171-
# If a concurrent merge wins the race (lease fails), refetch — that
172-
# winner's data is now in the tarballs we extract — re-add ours on top
173-
# and try again.
179+
# Drop this run's compressed files into the storage tree and orphan
180+
# force-push. If a concurrent merge wins the race (lease fails), refetch
181+
# — that winner's data is already on disk after the fetch — and redo.
174182
merge:
175183
name: Merge into storage branch
176184
needs: [claim, benchmark]
@@ -205,31 +213,23 @@ jobs:
205213
git config user.name "github-actions[bot]"
206214
git config user.email "github-actions[bot]@users.noreply.github.com"
207215
208-
# Idempotent migration from legacy loose-files layout.
209-
if [ -d data/results ] && [ ! -f data/results.tar.zst ]; then
210-
tar -C data -I 'zstd -19' -cf data/results.tar.zst results
216+
# Migrate from legacy loose uncompressed files to per-file zstd.
217+
# Idempotent.
218+
if [ -d data/results/asvrunner ]; then
219+
find data/results/asvrunner -name '*.json' ! -name 'machine.json' -print0 |
220+
xargs -0 -r -P 4 -n 50 zstd --rm -19 -q
211221
fi
212-
if [ -d data/envs ] && [ ! -f data/envs.tar.zst ]; then
213-
tar -C data -I 'zstd -19' -cf data/envs.tar.zst envs
222+
if [ -d data/envs ]; then
223+
find data/envs -name '*.yml' -print0 |
224+
xargs -0 -r -P 4 -n 50 zstd --rm -19 -q
214225
fi
215-
rm -rf data/results data/envs
216226
217-
WORK=$(mktemp -d)
218-
mkdir -p "$WORK/results/asvrunner" "$WORK/envs"
219-
if [ -f data/results.tar.zst ]; then
220-
tar -I zstd -xf data/results.tar.zst -C "$WORK"
221-
fi
222-
if [ -f data/envs.tar.zst ]; then
223-
tar -I zstd -xf data/envs.tar.zst -C "$WORK"
224-
fi
225-
226-
cp /tmp/new/results/benchmarks.json "$WORK/results/"
227-
cp /tmp/new/results/asvrunner/machine.json "$WORK/results/asvrunner/"
228-
cp /tmp/new/results/asvrunner/${SHA}.json "$WORK/results/asvrunner/"
229-
cp /tmp/new/envs/${SHA}.yml "$WORK/envs/"
230-
231-
tar -C "$WORK" -I 'zstd -19' -cf data/results.tar.zst results
232-
tar -C "$WORK" -I 'zstd -19' -cf data/envs.tar.zst envs
227+
# Drop in this run's new files.
228+
mkdir -p data/results/asvrunner data/envs
229+
cp /tmp/new/results/benchmarks.json data/results/
230+
cp /tmp/new/results/asvrunner/machine.json data/results/asvrunner/
231+
cp /tmp/new/results/asvrunner/${SHA}.json.zst data/results/asvrunner/
232+
cp /tmp/new/envs/${SHA}.yml.zst data/envs/
233233
234234
EXPECTED=$(git rev-parse origin/${BRANCH_NAME})
235235
git checkout --orphan fresh

data/.gitignore

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
results/
2-
envs/
1+
# Transient decompressed files: storage uses *.json.zst / *.yml.zst,
2+
# decompression at workflow time produces *.json / *.yml in place.
3+
results/asvrunner/*.json
4+
!results/asvrunner/machine.json
5+
envs/*.yml

0 commit comments

Comments
 (0)