serialbench 0.8.2 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/scripts/format-status.sh +21 -0
- data/.github/scripts/push-to-data.sh +24 -10
- data/.github/workflows/benchmark-autoheal.yml +59 -0
- data/.github/workflows/benchmark.yml +69 -0
- data/.github/workflows/release.yml +3 -0
- data/Gemfile +3 -1
- data/docs/adr/0007-data-repo-checkpoint-ledger.md +14 -0
- data/lib/serialbench/serializers/json/yeptris_serializer.rb +49 -0
- data/lib/serialbench/serializers/toml/teptris_serializer.rb +49 -0
- data/lib/serialbench/serializers/xml/leptris_serializer.rb +2 -1
- data/lib/serialbench/serializers/yaml/yeptris_serializer.rb +58 -0
- data/lib/serialbench/serializers.rb +9 -3
- data/lib/serialbench/version.rb +1 -1
- metadata +7 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7bdffce4061d0423a29fd90e1b8e40d42375f2edb7fc939a07be4211c515d8ee
|
|
4
|
+
data.tar.gz: bcc951356f7189dec61b5beb12d477b5605aa00bf90e4fa9e2486befd7431e7a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 99346a600ad99b956bc9a92f4bdd7601e1cde5183b0b82877548dbd839bdda0aa535bd6c1628335005d0d82456c97dac41dcb4be7ceb3faf131cdbef9daec4b4
|
|
7
|
+
data.tar.gz: 7cfa20bcf32cdf3c100bd2e021fb6bf71239bbcdc99fe09c5b7b50b0ce7bd39bb2d5db8a6b99fc1495c8ca76bc2c103cbb7204162a63cf62419df9b62b773c57
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Exit 0 if this leg's format results are already in the data repo, 1 if not.
|
|
3
|
+
# The data repo is the checkpoint ledger: a present file means the format was
|
|
4
|
+
# measured and pushed; reruns skip it and only fill what is missing.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
FMT="$1"
|
|
8
|
+
RUBY_VERSION="$2"
|
|
9
|
+
PLATFORM="$3"
|
|
10
|
+
DATA_TOKEN="${DATA_REPO_TOKEN:-}"
|
|
11
|
+
DATE="${DATA_RUN_DATE:-$(date -u +%Y-%m-%d)}"
|
|
12
|
+
|
|
13
|
+
[ -n "$DATA_TOKEN" ] || exit 1
|
|
14
|
+
|
|
15
|
+
TARGET="runs/${DATE}/${PLATFORM}-ruby-${RUBY_VERSION}.${FMT}.yaml"
|
|
16
|
+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
17
|
+
-H "Authorization: Bearer ${DATA_TOKEN}" \
|
|
18
|
+
"https://api.github.com/repos/serialbench/data/contents/${TARGET}")
|
|
19
|
+
|
|
20
|
+
[ "$HTTP_CODE" = "200" ] && exit 0
|
|
21
|
+
exit 1
|
|
@@ -21,7 +21,9 @@ if [ ! -f "$RESULTS_FILE" ]; then
|
|
|
21
21
|
exit 0
|
|
22
22
|
fi
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
# The matrix start date (setup job output), so every push and rerun of one
|
|
25
|
+
# matrix lands in one dated directory; wall clock is only a fallback.
|
|
26
|
+
DATE="${DATA_RUN_DATE:-$(date -u +%Y-%m-%d)}"
|
|
25
27
|
TARGET_PATH="runs/${DATE}/${PLATFORM}-ruby-${RUBY_VERSION}.${FMT}.yaml"
|
|
26
28
|
CONTENT=$(base64 < "$RESULTS_FILE" | tr -d '\r\n')
|
|
27
29
|
|
|
@@ -37,19 +39,31 @@ HTTP_CODE=$(curl -s -o /tmp/data-push-resp.json -w "%{http_code}" -X PUT \
|
|
|
37
39
|
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "201" ]; then
|
|
38
40
|
echo "Pushed ${TARGET_PATH}"
|
|
39
41
|
elif [ "$HTTP_CODE" = "422" ]; then
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
# File exists: fetch its sha and update. 409 (sha race when the branch
|
|
43
|
+
# moves between fetch and put) is retried with a fresh sha.
|
|
44
|
+
UPDATE_CODE=409
|
|
45
|
+
for TRY in 1 2 3; do
|
|
46
|
+
SHA=$(curl -sf \
|
|
47
|
+
-H "Authorization: Bearer ${DATA_TOKEN}" \
|
|
48
|
+
"https://api.github.com/repos/serialbench/data/contents/${TARGET_PATH}" \
|
|
49
|
+
| grep -oE '"sha":\s*"[a-f0-9]+"' | head -1 | grep -oE '[a-f0-9]{40}')
|
|
50
|
+
if [ -z "$SHA" ]; then
|
|
51
|
+
echo "::warning::422 but couldn't get sha for ${TARGET_PATH}"
|
|
52
|
+
break
|
|
53
|
+
fi
|
|
54
|
+
UPDATE_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X PUT \
|
|
46
55
|
-H "Authorization: Bearer ${DATA_TOKEN}" \
|
|
47
56
|
-H "Accept: application/vnd.github+json" \
|
|
48
57
|
"https://api.github.com/repos/serialbench/data/contents/${TARGET_PATH}" \
|
|
49
|
-
-d "{\"message\": \"${PLATFORM} ruby-${RUBY_VERSION} ${FMT} (update)\", \"content\": \"${CONTENT}\", \"sha\": \"${SHA}\", \"branch\": \"main\"}"
|
|
58
|
+
-d "{\"message\": \"${PLATFORM} ruby-${RUBY_VERSION} ${FMT} (update)\", \"content\": \"${CONTENT}\", \"sha\": \"${SHA}\", \"branch\": \"main\"}")
|
|
59
|
+
[ "$UPDATE_CODE" = "200" ] && break
|
|
60
|
+
echo "update attempt $TRY got $UPDATE_CODE — refetching sha"
|
|
61
|
+
sleep 2
|
|
62
|
+
done
|
|
63
|
+
if [ "$UPDATE_CODE" = "200" ]; then
|
|
50
64
|
echo "Updated existing ${TARGET_PATH}"
|
|
51
|
-
|
|
52
|
-
echo "::warning::
|
|
65
|
+
elif [ -n "$SHA" ]; then
|
|
66
|
+
echo "::warning::could not update ${TARGET_PATH} ($UPDATE_CODE)"
|
|
53
67
|
fi
|
|
54
68
|
else
|
|
55
69
|
echo "::warning::Push failed (${HTTP_CODE}): $(cat /tmp/data-push-resp.json | head -c 200)"
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: benchmark-autoheal
|
|
2
|
+
|
|
3
|
+
# Reruns failed legs (runner evictions, OOM blips) of the latest benchmark
|
|
4
|
+
# matrix without human intervention. Capped: a run gets at most 5 attempts,
|
|
5
|
+
# and deliberately cancelled runs are never resurrected.
|
|
6
|
+
on:
|
|
7
|
+
# Heal immediately when a matrix completes (reliable event seam); the
|
|
8
|
+
# hourly cron below is only a backstop — GitHub drops cron ticks freely.
|
|
9
|
+
workflow_run:
|
|
10
|
+
workflows: [benchmark-weekly]
|
|
11
|
+
types: [completed]
|
|
12
|
+
schedule:
|
|
13
|
+
# hourly at :23 — off the busy top of the hour
|
|
14
|
+
- cron: '23 * * * *'
|
|
15
|
+
workflow_dispatch:
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
actions: write
|
|
19
|
+
|
|
20
|
+
concurrency:
|
|
21
|
+
group: benchmark-autoheal
|
|
22
|
+
cancel-in-progress: false
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
rerun-failed:
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
timeout-minutes: 5
|
|
28
|
+
steps:
|
|
29
|
+
- name: Rerun failed benchmark legs (capped)
|
|
30
|
+
env:
|
|
31
|
+
GH_TOKEN: ${{ github.token }}
|
|
32
|
+
run: |
|
|
33
|
+
set -euo pipefail
|
|
34
|
+
RUN_ID=$(gh run list -R "$GITHUB_REPOSITORY" --workflow=benchmark.yml --limit 1 --json databaseId --jq '.[0].databaseId')
|
|
35
|
+
[ -n "$RUN_ID" ] || { echo "no benchmark run found"; exit 0; }
|
|
36
|
+
|
|
37
|
+
STATUS=$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$RUN_ID" --jq '.status')
|
|
38
|
+
if [ "$STATUS" != "completed" ]; then
|
|
39
|
+
echo "latest run $RUN_ID still $STATUS — nothing to do"
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
CONCLUSION=$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$RUN_ID" --jq '.conclusion // ""')
|
|
44
|
+
if [ "$CONCLUSION" != "failure" ]; then
|
|
45
|
+
echo "latest run concluded $CONCLUSION — nothing to rerun (cancelled runs are deliberate)"
|
|
46
|
+
exit 0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
ATTEMPT=$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$RUN_ID" --jq '.run_attempt')
|
|
50
|
+
if [ "$ATTEMPT" -ge 5 ]; then
|
|
51
|
+
echo "attempt cap reached ($ATTEMPT) — leaving for humans"
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
FAILED=$(gh run view "$RUN_ID" -R "$GITHUB_REPOSITORY" --json jobs --jq '[.jobs[] | select(.conclusion == "failure")] | length')
|
|
56
|
+
[ "$FAILED" -gt 0 ] || { echo "no failed legs"; exit 0; }
|
|
57
|
+
|
|
58
|
+
echo "rerunning $FAILED failed legs (attempt $ATTEMPT -> $((ATTEMPT + 1)))"
|
|
59
|
+
gh run rerun "$RUN_ID" -R "$GITHUB_REPOSITORY" --failed
|
|
@@ -25,15 +25,18 @@ concurrency:
|
|
|
25
25
|
jobs:
|
|
26
26
|
setup:
|
|
27
27
|
runs-on: ubuntu-latest
|
|
28
|
+
timeout-minutes: 5
|
|
28
29
|
outputs:
|
|
29
30
|
ruby-versions: ${{ steps.set-matrix.outputs.ruby-versions }}
|
|
30
31
|
platforms: ${{ steps.set-matrix.outputs.platforms }}
|
|
32
|
+
run-date: ${{ steps.set-matrix.outputs.run-date }}
|
|
31
33
|
steps:
|
|
32
34
|
- name: Set matrix configurations
|
|
33
35
|
id: set-matrix
|
|
34
36
|
run: |
|
|
35
37
|
echo 'ruby-versions=["3.2", "3.3", "3.4", "4.0"]' >> $GITHUB_OUTPUT
|
|
36
38
|
echo 'platforms=["ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-14", "macos-15", "macos-15-intel", "macos-26", "macos-26-intel", "windows-2022", "windows-2025", "windows-11-arm"]' >> $GITHUB_OUTPUT
|
|
39
|
+
echo "run-date=$(date -u +%Y-%m-%d)" >> $GITHUB_OUTPUT
|
|
37
40
|
|
|
38
41
|
# Cross-platform native benchmarks
|
|
39
42
|
benchmark:
|
|
@@ -113,6 +116,21 @@ jobs:
|
|
|
113
116
|
- name: Install gems
|
|
114
117
|
run: bundle install
|
|
115
118
|
|
|
119
|
+
- name: Point teptris at its vendored DLL (Windows)
|
|
120
|
+
if: startsWith(matrix.platform, 'windows-')
|
|
121
|
+
shell: bash
|
|
122
|
+
run: |
|
|
123
|
+
# teptris 0.1.0's mingw gem vendors the library as teptris.dll but
|
|
124
|
+
# its FFI loader searches libteptris.dll; TEPTRIS_LIB_PATH (the
|
|
125
|
+
# loader's first candidate) bridges until the ext-based gem ships.
|
|
126
|
+
DLL=$(bundle exec ruby -e "print File.join(Gem::Specification.find_by_name('teptris').gem_dir, 'lib', 'teptris.dll')" 2>/dev/null || true)
|
|
127
|
+
if [ -n "$DLL" ] && [ -f "$DLL" ]; then
|
|
128
|
+
echo "TEPTRIS_LIB_PATH=$DLL" >> "$GITHUB_ENV"
|
|
129
|
+
echo "TEPTRIS_LIB_PATH=$DLL"
|
|
130
|
+
else
|
|
131
|
+
echo "no vendored teptris.dll found — teptris stays unavailable on this leg"
|
|
132
|
+
fi
|
|
133
|
+
|
|
116
134
|
- name: Create environment config
|
|
117
135
|
run: |
|
|
118
136
|
mkdir -p config/environments
|
|
@@ -131,7 +149,13 @@ jobs:
|
|
|
131
149
|
shell: bash
|
|
132
150
|
env:
|
|
133
151
|
GITHUB_RUNNER_PLATFORM: ${{ matrix.platform }}
|
|
152
|
+
DATA_REPO_TOKEN: ${{ secrets.DATA_REPO_TOKEN }}
|
|
153
|
+
DATA_RUN_DATE: ${{ needs.setup.outputs.run-date }}
|
|
134
154
|
run: |
|
|
155
|
+
if [ "${{ github.run_attempt }}" -gt 1 ] && .github/scripts/format-status.sh json ${{ matrix.ruby-version }} ${{ matrix.platform }}; then
|
|
156
|
+
echo "json already in the data repo — skipping (gap-filling rerun)"
|
|
157
|
+
exit 0
|
|
158
|
+
fi
|
|
135
159
|
bundle exec serialbench environment execute \
|
|
136
160
|
config/environments/ci-ruby-${{ matrix.ruby-version }}.yml \
|
|
137
161
|
config/benchmarks/full-json.yml \
|
|
@@ -151,6 +175,7 @@ jobs:
|
|
|
151
175
|
continue-on-error: true
|
|
152
176
|
env:
|
|
153
177
|
DATA_REPO_TOKEN: ${{ secrets.DATA_REPO_TOKEN }}
|
|
178
|
+
DATA_RUN_DATE: ${{ needs.setup.outputs.run-date }}
|
|
154
179
|
run: .github/scripts/push-to-data.sh json ${{ matrix.ruby-version }} ${{ matrix.platform }}
|
|
155
180
|
shell: bash
|
|
156
181
|
|
|
@@ -159,7 +184,13 @@ jobs:
|
|
|
159
184
|
shell: bash
|
|
160
185
|
env:
|
|
161
186
|
GITHUB_RUNNER_PLATFORM: ${{ matrix.platform }}
|
|
187
|
+
DATA_REPO_TOKEN: ${{ secrets.DATA_REPO_TOKEN }}
|
|
188
|
+
DATA_RUN_DATE: ${{ needs.setup.outputs.run-date }}
|
|
162
189
|
run: |
|
|
190
|
+
if [ "${{ github.run_attempt }}" -gt 1 ] && .github/scripts/format-status.sh yaml ${{ matrix.ruby-version }} ${{ matrix.platform }}; then
|
|
191
|
+
echo "yaml already in the data repo — skipping (gap-filling rerun)"
|
|
192
|
+
exit 0
|
|
193
|
+
fi
|
|
163
194
|
bundle exec serialbench environment execute \
|
|
164
195
|
config/environments/ci-ruby-${{ matrix.ruby-version }}.yml \
|
|
165
196
|
config/benchmarks/full-yaml.yml \
|
|
@@ -179,6 +210,7 @@ jobs:
|
|
|
179
210
|
continue-on-error: true
|
|
180
211
|
env:
|
|
181
212
|
DATA_REPO_TOKEN: ${{ secrets.DATA_REPO_TOKEN }}
|
|
213
|
+
DATA_RUN_DATE: ${{ needs.setup.outputs.run-date }}
|
|
182
214
|
run: .github/scripts/push-to-data.sh yaml ${{ matrix.ruby-version }} ${{ matrix.platform }}
|
|
183
215
|
shell: bash
|
|
184
216
|
|
|
@@ -187,7 +219,13 @@ jobs:
|
|
|
187
219
|
shell: bash
|
|
188
220
|
env:
|
|
189
221
|
GITHUB_RUNNER_PLATFORM: ${{ matrix.platform }}
|
|
222
|
+
DATA_REPO_TOKEN: ${{ secrets.DATA_REPO_TOKEN }}
|
|
223
|
+
DATA_RUN_DATE: ${{ needs.setup.outputs.run-date }}
|
|
190
224
|
run: |
|
|
225
|
+
if [ "${{ github.run_attempt }}" -gt 1 ] && .github/scripts/format-status.sh toml ${{ matrix.ruby-version }} ${{ matrix.platform }}; then
|
|
226
|
+
echo "toml already in the data repo — skipping (gap-filling rerun)"
|
|
227
|
+
exit 0
|
|
228
|
+
fi
|
|
191
229
|
bundle exec serialbench environment execute \
|
|
192
230
|
config/environments/ci-ruby-${{ matrix.ruby-version }}.yml \
|
|
193
231
|
config/benchmarks/full-toml.yml \
|
|
@@ -207,6 +245,7 @@ jobs:
|
|
|
207
245
|
continue-on-error: true
|
|
208
246
|
env:
|
|
209
247
|
DATA_REPO_TOKEN: ${{ secrets.DATA_REPO_TOKEN }}
|
|
248
|
+
DATA_RUN_DATE: ${{ needs.setup.outputs.run-date }}
|
|
210
249
|
run: .github/scripts/push-to-data.sh toml ${{ matrix.ruby-version }} ${{ matrix.platform }}
|
|
211
250
|
shell: bash
|
|
212
251
|
|
|
@@ -217,7 +256,13 @@ jobs:
|
|
|
217
256
|
shell: bash
|
|
218
257
|
env:
|
|
219
258
|
GITHUB_RUNNER_PLATFORM: ${{ matrix.platform }}
|
|
259
|
+
DATA_REPO_TOKEN: ${{ secrets.DATA_REPO_TOKEN }}
|
|
260
|
+
DATA_RUN_DATE: ${{ needs.setup.outputs.run-date }}
|
|
220
261
|
run: |
|
|
262
|
+
if [ "${{ github.run_attempt }}" -gt 1 ] && .github/scripts/format-status.sh xml ${{ matrix.ruby-version }} ${{ matrix.platform }}; then
|
|
263
|
+
echo "xml already in the data repo — skipping (gap-filling rerun)"
|
|
264
|
+
exit 0
|
|
265
|
+
fi
|
|
221
266
|
bundle exec serialbench environment execute \
|
|
222
267
|
config/environments/ci-ruby-${{ matrix.ruby-version }}.yml \
|
|
223
268
|
config/benchmarks/full-xml.yml \
|
|
@@ -237,13 +282,37 @@ jobs:
|
|
|
237
282
|
continue-on-error: true
|
|
238
283
|
env:
|
|
239
284
|
DATA_REPO_TOKEN: ${{ secrets.DATA_REPO_TOKEN }}
|
|
285
|
+
DATA_RUN_DATE: ${{ needs.setup.outputs.run-date }}
|
|
240
286
|
run: .github/scripts/push-to-data.sh xml ${{ matrix.ruby-version }} ${{ matrix.platform }}
|
|
241
287
|
shell: bash
|
|
242
288
|
|
|
243
289
|
|
|
290
|
+
|
|
291
|
+
- name: Verify leg completeness
|
|
292
|
+
if: ${{ !cancelled() }}
|
|
293
|
+
shell: bash
|
|
294
|
+
env:
|
|
295
|
+
DATA_REPO_TOKEN: ${{ secrets.DATA_REPO_TOKEN }}
|
|
296
|
+
DATA_RUN_DATE: ${{ needs.setup.outputs.run-date }}
|
|
297
|
+
run: |
|
|
298
|
+
MISSING=""
|
|
299
|
+
for FMT in json yaml toml xml; do
|
|
300
|
+
if .github/scripts/format-status.sh "$FMT" "${{ matrix.ruby-version }}" "${{ matrix.platform }}"; then
|
|
301
|
+
echo "$FMT: in data repo"
|
|
302
|
+
else
|
|
303
|
+
echo "$FMT: MISSING from data repo"
|
|
304
|
+
MISSING="$MISSING $FMT"
|
|
305
|
+
fi
|
|
306
|
+
done
|
|
307
|
+
if [ -n "$MISSING" ]; then
|
|
308
|
+
echo "::error::formats never pushed:${MISSING} — failing the leg so autoheal fills the gap"
|
|
309
|
+
exit 1
|
|
310
|
+
fi
|
|
311
|
+
|
|
244
312
|
# Summary job
|
|
245
313
|
summary:
|
|
246
314
|
runs-on: ubuntu-latest
|
|
315
|
+
timeout-minutes: 5
|
|
247
316
|
needs: [setup, benchmark]
|
|
248
317
|
if: always()
|
|
249
318
|
steps:
|
data/Gemfile
CHANGED
|
@@ -12,7 +12,9 @@ unless Gem.win_platform? && RUBY_PLATFORM.include?('aarch64')
|
|
|
12
12
|
gem 'libxml-ruby'
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
gem 'leptris', '1.9.
|
|
15
|
+
gem 'leptris', '1.9.156.0' # precompiled platform gems bundle libleptris (darwin/linux/mingw)
|
|
16
|
+
gem 'yeptris', '0.2.0.1' # precompiled darwin/linux; no windows or darwin-intel gems yet
|
|
17
|
+
gem 'teptris', '0.1.0' # precompiled all platforms
|
|
16
18
|
gem 'benchmark' # Removed from stdlib in Ruby 4.0
|
|
17
19
|
gem 'base64' # Required for Ruby 3.4+
|
|
18
20
|
gem 'lutaml-model', '~> 0.7'
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# ADR-0007: The data repo is the checkpoint ledger
|
|
2
|
+
|
|
3
|
+
Date: 2026-09-02
|
|
4
|
+
|
|
5
|
+
## Context
|
|
6
|
+
A leg's format steps are continue-on-error, so a Benchmark step failing inside a green job was invisible: autoheal (job-level) never saw it, and the missing format file surfaced only as a coverage gap (19 of 184 missing on 2026-09-01). Rerunning whole green jobs to recover one format costs ~45 minutes of re-measurement per leg — deliberate duplicate work.
|
|
7
|
+
|
|
8
|
+
## Decision
|
|
9
|
+
The data repo is the source of truth for what a leg has delivered:
|
|
10
|
+
1. Every leg ends with a completeness check that queries the data repo for all four of its format files; any miss fails the leg, making gaps visible to autoheal.
|
|
11
|
+
2. Benchmark steps skip a format whose file already exists — but only on rerun attempts (`github.run_attempt > 1`), so first attempts always measure fresh code.
|
|
12
|
+
3. Consequently autoheal's reruns are surgical: pushed formats skip in seconds and only the missing format is measured — eviction windows shrink from ~45 minutes to a single format's runtime.
|
|
13
|
+
|
|
14
|
+
Gaps that survive the 5-attempt cap surface as red runs, never as silent holes.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_json_serializer'
|
|
4
|
+
|
|
5
|
+
module Serialbench
|
|
6
|
+
module Serializers
|
|
7
|
+
module Json
|
|
8
|
+
# Yeptris JSON side: parsing only — no dump in 0.2.x
|
|
9
|
+
class YeptrisSerializer < BaseJsonSerializer
|
|
10
|
+
def name
|
|
11
|
+
'yeptris-json'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def parse(json_string)
|
|
15
|
+
require 'yeptris'
|
|
16
|
+
Yeptris::JSON.load(json_string)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def capabilities
|
|
20
|
+
Set.new(%i[dom parse])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def available?
|
|
24
|
+
return @available if defined?(@available)
|
|
25
|
+
|
|
26
|
+
@available = begin
|
|
27
|
+
require 'yeptris'
|
|
28
|
+
Yeptris::JSON.load('{"probe":true}')
|
|
29
|
+
true
|
|
30
|
+
rescue StandardError, LoadError => e
|
|
31
|
+
warn "#{name} unavailable: #{e.class}: #{e.message}"
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def version
|
|
37
|
+
return 'unknown' unless available?
|
|
38
|
+
|
|
39
|
+
require 'yeptris'
|
|
40
|
+
Yeptris::VERSION
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def library_require_name
|
|
44
|
+
'yeptris'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_toml_serializer'
|
|
4
|
+
|
|
5
|
+
module Serialbench
|
|
6
|
+
module Serializers
|
|
7
|
+
module Toml
|
|
8
|
+
class TeptrisSerializer < BaseTomlSerializer
|
|
9
|
+
def name
|
|
10
|
+
'teptris'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def parse(toml_string)
|
|
14
|
+
require 'teptris'
|
|
15
|
+
Teptris::TOML.load(toml_string)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def generate(object, _options = {})
|
|
19
|
+
require 'teptris'
|
|
20
|
+
Teptris::TOML.dump(object)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def available?
|
|
24
|
+
return @available if defined?(@available)
|
|
25
|
+
|
|
26
|
+
@available = begin
|
|
27
|
+
require 'teptris'
|
|
28
|
+
Teptris::TOML.load("probe = true\n")
|
|
29
|
+
true
|
|
30
|
+
rescue StandardError, LoadError => e
|
|
31
|
+
warn "#{name} unavailable: #{e.class}: #{e.message}"
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def version
|
|
37
|
+
return 'unknown' unless available?
|
|
38
|
+
|
|
39
|
+
require 'teptris'
|
|
40
|
+
Teptris::VERSION
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def library_require_name
|
|
44
|
+
'teptris'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_yaml_serializer'
|
|
4
|
+
|
|
5
|
+
module Serialbench
|
|
6
|
+
module Serializers
|
|
7
|
+
module Yaml
|
|
8
|
+
class YeptrisSerializer < BaseYamlSerializer
|
|
9
|
+
def name
|
|
10
|
+
'yeptris-yaml'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def parse(yaml_string)
|
|
14
|
+
require 'yeptris'
|
|
15
|
+
Yeptris::YAML.load(yaml_string)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def generate(object, _options = {})
|
|
19
|
+
require 'yeptris'
|
|
20
|
+
Yeptris::YAML.dump(object)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def stream_parse(yaml_string, &block)
|
|
24
|
+
require 'yeptris'
|
|
25
|
+
Yeptris::YAML.load_stream(yaml_string).each { |doc| block.call(:document, doc) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def capabilities
|
|
29
|
+
super | Set.new(%i[streaming])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def available?
|
|
33
|
+
return @available if defined?(@available)
|
|
34
|
+
|
|
35
|
+
@available = begin
|
|
36
|
+
require 'yeptris'
|
|
37
|
+
Yeptris::YAML.load('probe: true')
|
|
38
|
+
true
|
|
39
|
+
rescue StandardError, LoadError => e
|
|
40
|
+
warn "#{name} unavailable: #{e.class}: #{e.message}"
|
|
41
|
+
false
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def version
|
|
46
|
+
return 'unknown' unless available?
|
|
47
|
+
|
|
48
|
+
require 'yeptris'
|
|
49
|
+
Yeptris::VERSION
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def library_require_name
|
|
53
|
+
'yeptris'
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -18,17 +18,20 @@ require_relative 'serializers/json/json_serializer'
|
|
|
18
18
|
require_relative 'serializers/json/oj_serializer'
|
|
19
19
|
require_relative 'serializers/json/yajl_serializer'
|
|
20
20
|
require_relative 'serializers/json/rapidjson_serializer'
|
|
21
|
+
require_relative 'serializers/json/yeptris_serializer'
|
|
21
22
|
|
|
22
23
|
# YAML Serializers
|
|
23
24
|
require_relative 'serializers/yaml/base_yaml_serializer'
|
|
24
25
|
require_relative 'serializers/yaml/psych_serializer'
|
|
25
26
|
require_relative 'serializers/yaml/syck_serializer'
|
|
27
|
+
require_relative 'serializers/yaml/yeptris_serializer'
|
|
26
28
|
|
|
27
29
|
# TOML Serializers
|
|
28
30
|
require_relative 'serializers/toml/base_toml_serializer'
|
|
29
31
|
require_relative 'serializers/toml/toml_rb_serializer'
|
|
30
32
|
require_relative 'serializers/toml/tomlib_serializer'
|
|
31
33
|
require_relative 'serializers/toml/tomlrb_serializer'
|
|
34
|
+
require_relative 'serializers/toml/teptris_serializer'
|
|
32
35
|
|
|
33
36
|
module Serialbench
|
|
34
37
|
module Serializers
|
|
@@ -46,16 +49,19 @@ module Serialbench
|
|
|
46
49
|
Json::JsonSerializer,
|
|
47
50
|
Json::OjSerializer,
|
|
48
51
|
Json::RapidjsonSerializer,
|
|
49
|
-
Json::YajlSerializer
|
|
52
|
+
Json::YajlSerializer,
|
|
53
|
+
Json::YeptrisSerializer
|
|
50
54
|
],
|
|
51
55
|
yaml: [
|
|
52
56
|
Yaml::PsychSerializer,
|
|
53
|
-
Yaml::SyckSerializer
|
|
57
|
+
Yaml::SyckSerializer,
|
|
58
|
+
Yaml::YeptrisSerializer
|
|
54
59
|
],
|
|
55
60
|
toml: [
|
|
56
61
|
Toml::TomlRbSerializer,
|
|
57
62
|
Toml::TomlibSerializer,
|
|
58
|
-
Toml::TomlrbSerializer
|
|
63
|
+
Toml::TomlrbSerializer,
|
|
64
|
+
Toml::TeptrisSerializer
|
|
59
65
|
]
|
|
60
66
|
}.freeze
|
|
61
67
|
|
data/lib/serialbench/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: serialbench
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose
|
|
@@ -256,7 +256,9 @@ executables:
|
|
|
256
256
|
extensions: []
|
|
257
257
|
extra_rdoc_files: []
|
|
258
258
|
files:
|
|
259
|
+
- ".github/scripts/format-status.sh"
|
|
259
260
|
- ".github/scripts/push-to-data.sh"
|
|
261
|
+
- ".github/workflows/benchmark-autoheal.yml"
|
|
260
262
|
- ".github/workflows/benchmark.yml"
|
|
261
263
|
- ".github/workflows/rake.yml"
|
|
262
264
|
- ".github/workflows/release.yml"
|
|
@@ -296,6 +298,7 @@ files:
|
|
|
296
298
|
- docs/adr/0004-explicit-workflow-steps.md
|
|
297
299
|
- docs/adr/0005-site-loader-stays-flat.md
|
|
298
300
|
- docs/adr/0006-operations-vocabulary.md
|
|
301
|
+
- docs/adr/0007-data-repo-checkpoint-ledger.md
|
|
299
302
|
- exe/serialbench
|
|
300
303
|
- lib/serialbench.rb
|
|
301
304
|
- lib/serialbench/benchmark_runner.rb
|
|
@@ -325,7 +328,9 @@ files:
|
|
|
325
328
|
- lib/serialbench/serializers/json/oj_serializer.rb
|
|
326
329
|
- lib/serialbench/serializers/json/rapidjson_serializer.rb
|
|
327
330
|
- lib/serialbench/serializers/json/yajl_serializer.rb
|
|
331
|
+
- lib/serialbench/serializers/json/yeptris_serializer.rb
|
|
328
332
|
- lib/serialbench/serializers/toml/base_toml_serializer.rb
|
|
333
|
+
- lib/serialbench/serializers/toml/teptris_serializer.rb
|
|
329
334
|
- lib/serialbench/serializers/toml/toml_rb_serializer.rb
|
|
330
335
|
- lib/serialbench/serializers/toml/tomlib_serializer.rb
|
|
331
336
|
- lib/serialbench/serializers/toml/tomlrb_serializer.rb
|
|
@@ -339,6 +344,7 @@ files:
|
|
|
339
344
|
- lib/serialbench/serializers/yaml/base_yaml_serializer.rb
|
|
340
345
|
- lib/serialbench/serializers/yaml/psych_serializer.rb
|
|
341
346
|
- lib/serialbench/serializers/yaml/syck_serializer.rb
|
|
347
|
+
- lib/serialbench/serializers/yaml/yeptris_serializer.rb
|
|
342
348
|
- lib/serialbench/test_data.rb
|
|
343
349
|
- lib/serialbench/version.rb
|
|
344
350
|
- lib/serialbench/yaml_validator.rb
|