Skip to content

Commit dff55e8

Browse files
authored
Merge pull request #724 from dolthub/bench/textpk-extra
sysbench: split TEXT PK into a separate Benchmark Extra workflow
2 parents 294022c + 84333be commit dff55e8

4 files changed

Lines changed: 624 additions & 77 deletions

File tree

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
name: Benchmark Extra
2+
3+
# Companion to Benchmark. Runs the TEXT PK variant of the sysbench suite
4+
# (test/sysbench_compare_textpk.sh) — every workload against tables with
5+
# a 32-char hex TEXT PRIMARY KEY. Reporting only; no ceiling check until
6+
# the non-INTKEY perf work brings ratios in.
7+
8+
on:
9+
push:
10+
branches: [master]
11+
pull_request:
12+
branches: [master]
13+
14+
permissions:
15+
contents: read
16+
issues: write
17+
pull-requests: write
18+
19+
jobs:
20+
benchmark-extra:
21+
runs-on: ubuntu-latest
22+
timeout-minutes: 15
23+
24+
steps:
25+
- uses: actions/checkout@v4
26+
27+
- name: Install dependencies
28+
run: |
29+
sudo apt-get update
30+
sudo apt-get install -y tcl-dev build-essential zlib1g-dev
31+
32+
- name: Configure
33+
run: |
34+
mkdir -p build && cd build
35+
TCL_CONFIG=$(find /usr -name tclConfig.sh 2>/dev/null | head -1)
36+
if [ -n "$TCL_CONFIG" ]; then
37+
../configure --with-tcl=$(dirname $TCL_CONFIG)
38+
else
39+
../configure
40+
fi
41+
42+
- name: Build doltlite and stock SQLite
43+
run: |
44+
cd build
45+
make doltlite
46+
make DOLTLITE_PROLLY=0 sqlite3
47+
48+
- name: Run benchmark
49+
run: |
50+
cd build
51+
bash ../test/sysbench_compare_textpk.sh | tee /tmp/bench_textpk_results.md
52+
53+
- name: Comment PR with results
54+
continue-on-error: true
55+
uses: actions/github-script@v7
56+
with:
57+
script: |
58+
// Read from file so the multi-line markdown (and any backticks /
59+
// template-literal-unsafe chars in it) never has to round-trip
60+
// through YAML scalars or JS template-literal parsing.
61+
const fs = require('fs');
62+
const body = fs.readFileSync('/tmp/bench_textpk_results.md', 'utf8');
63+
64+
if (!context.issue.number) {
65+
console.log('No PR context (push event) — skipping comment');
66+
return;
67+
}
68+
69+
// Find existing benchmark-extra comment.
70+
const comments = await github.rest.issues.listComments({
71+
owner: context.repo.owner,
72+
repo: context.repo.repo,
73+
issue_number: context.issue.number,
74+
});
75+
const botComment = comments.data.find(c =>
76+
c.body.includes('<!-- benchmark:textpk -->') ||
77+
c.body.includes('## Sysbench-Style Benchmark (TEXT PK): Doltlite vs SQLite')
78+
);
79+
80+
if (botComment) {
81+
await github.rest.issues.updateComment({
82+
owner: context.repo.owner,
83+
repo: context.repo.repo,
84+
comment_id: botComment.id,
85+
body: body,
86+
});
87+
} else {
88+
await github.rest.issues.createComment({
89+
owner: context.repo.owner,
90+
repo: context.repo.repo,
91+
issue_number: context.issue.number,
92+
body: body,
93+
});
94+
}

.github/workflows/benchmark.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,15 @@ jobs:
6161
return;
6262
}
6363
64-
// Find existing benchmark comment
64+
// Find existing classic benchmark comment
6565
const comments = await github.rest.issues.listComments({
6666
owner: context.repo.owner,
6767
repo: context.repo.repo,
6868
issue_number: context.issue.number,
6969
});
7070
const botComment = comments.data.find(c =>
71-
c.body.includes('Sysbench-Style Benchmark')
71+
c.body.includes('<!-- benchmark:classic -->') ||
72+
c.body.includes('## Sysbench-Style Benchmark: Doltlite vs SQLite')
7273
);
7374
7475
if (botComment) {

test/sysbench_compare.sh

Lines changed: 3 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,6 @@ import random, string, os
3232
3333
random.seed($SEED)
3434
R = $ROWS
35-
# TEXT-PK section uses smaller row/op counts so the bench job stays
36-
# within CI's 15-minute limit. Each non-INTKEY insert on doltlite
37-
# currently goes through a per-statement flush whose cost scales with
38-
# tree size, so full-scale R blows the budget in the prepare phase
39-
# alone. Smaller TPR/TPN still surfaces the regression.
40-
TPR = max(R // 10, 100)
41-
TPN = max(R // 10, 100)
4235
d = '$TMPDIR'
4336
4437
def rint(a, b):
@@ -96,25 +89,6 @@ def prep_with_types(f):
9689
write_prepare(f)
9790
write_prepare_types(f)
9891
99-
def write_prepare_textpk(f):
100-
# Same shape as sbtest1, but PK is a 32-char hex string (UUID-shaped).
101-
# Lights up the non-INTKEY mutmap-flush path (issue #718).
102-
# Sized smaller than the INTKEY suite (TPR rows vs R) because each
103-
# non-INTKEY insert on doltlite goes through a per-statement flush
104-
# whose cost scales with tree size, and the section's job is to
105-
# surface the regression — full-scale R would push the bench job
106-
# past CI's 15-minute limit. Keep the workload N relative to TPR
107-
# so per-test wall time stays comparable to the INTKEY tests.
108-
f.write("CREATE TABLE sbtest_textpk(id TEXT PRIMARY KEY, k INTEGER NOT NULL DEFAULT 0, c TEXT NOT NULL DEFAULT '', pad TEXT NOT NULL DEFAULT '');\n")
109-
f.write("CREATE INDEX k_idx_textpk ON sbtest_textpk(k);\n")
110-
f.write("BEGIN;\n")
111-
for i in range(1, TPR+1):
112-
f.write(f"INSERT INTO sbtest_textpk VALUES('{i:032x}',{rint(1,TPR)},'{rstr(60)}','{rstr(30)}');\n")
113-
f.write("COMMIT;\n")
114-
115-
def prep_textpk(f):
116-
write_prepare_textpk(f)
117-
11892
# --- Tests ---
11993
12094
def w_bulk_insert(f):
@@ -363,41 +337,6 @@ def w_read_write_autocommit(f):
363337
f.write(f"DELETE FROM sbtest1 WHERE id={id};\n")
364338
f.write(f"INSERT OR REPLACE INTO sbtest1 VALUES({id},{rint(1,R)},'{rstr(60)}','{rstr(30)}');\n")
365339
366-
# TEXT-PK writes: same workload shapes as the INTEGER-PK writes, but the
367-
# PK is a 32-char hex string. Issue #718: non-INTKEY tables route through
368-
# mergeWalk on every flush, which is 10-1000x slower than streamingMerge.
369-
# Reporting only (not gated) until the fix lands.
370-
def w_update_index_textpk(f):
371-
f.write("BEGIN;\n")
372-
for _ in range(TPN):
373-
f.write(f"UPDATE sbtest_textpk SET k={rint(1,TPR)} WHERE id='{rint(1,TPR):032x}';\n")
374-
f.write("COMMIT;\n")
375-
376-
def w_update_non_index_textpk(f):
377-
f.write("BEGIN;\n")
378-
for _ in range(TPN):
379-
f.write(f"UPDATE sbtest_textpk SET c='{rstr(60)}' WHERE id='{rint(1,TPR):032x}';\n")
380-
f.write("COMMIT;\n")
381-
382-
def w_oltp_insert_textpk(f):
383-
f.write("BEGIN;\n")
384-
for i in range(TPR+1, TPR+TPN+1):
385-
f.write(f"INSERT INTO sbtest_textpk VALUES('{i:032x}',{rint(1,TPR)},'{rstr(60)}','{rstr(30)}');\n")
386-
f.write("COMMIT;\n")
387-
388-
def w_delete_insert_textpk(f):
389-
f.write("BEGIN;\n")
390-
for _ in range(TPN):
391-
i = rint(1, TPR)
392-
f.write(f"DELETE FROM sbtest_textpk WHERE id='{i:032x}';\n")
393-
f.write(f"INSERT OR REPLACE INTO sbtest_textpk VALUES('{i:032x}',{rint(1,TPR)},'{rstr(60)}','{rstr(30)}');\n")
394-
f.write("COMMIT;\n")
395-
396-
make_test("oltp_update_index_textpk", prep_textpk, w_update_index_textpk)
397-
make_test("oltp_update_non_index_textpk", prep_textpk, w_update_non_index_textpk)
398-
make_test("oltp_insert_textpk", prep_textpk, w_oltp_insert_textpk)
399-
make_test("oltp_delete_insert_textpk", prep_textpk, w_delete_insert_textpk)
400-
401340
make_test("oltp_bulk_insert_ac", prep_main, w_bulk_insert_autocommit)
402341
make_test("oltp_insert_ac", prep_main, w_oltp_insert_autocommit)
403342
make_test("oltp_update_index_ac", prep_main, w_update_index_autocommit)
@@ -442,9 +381,8 @@ else:
442381
}
443382

444383
bench_runs_for_test() {
445-
# BENCH_RUNS=1 for fast local iteration; default 7 for stable median
446-
# while keeping the bench job under CI's 15-minute limit.
447-
echo "${BENCH_RUNS:-7}"
384+
# BENCH_RUNS=1 for fast local iteration; default 11 for stable median.
385+
echo "${BENCH_RUNS:-11}"
448386
}
449387

450388
median_us() {
@@ -479,7 +417,6 @@ run_bench_stable() {
479417
READ_TESTS="oltp_point_select oltp_range_select oltp_sum_range oltp_order_range oltp_distinct_range oltp_index_scan select_random_points select_random_ranges covering_index_scan groupby_scan index_join index_join_scan types_table_scan table_scan oltp_read_only"
480418
WRITE_TESTS="oltp_bulk_insert oltp_insert oltp_update_index oltp_update_non_index oltp_delete_insert oltp_write_only types_delete_insert oltp_read_write"
481419
WRITE_TESTS_AC="oltp_bulk_insert_ac oltp_insert_ac oltp_update_index_ac oltp_update_non_index_ac oltp_delete_insert_ac oltp_write_only_ac types_delete_insert_ac oltp_read_write_ac"
482-
WRITE_TESTS_TEXTPK="oltp_update_index_textpk oltp_update_non_index_textpk oltp_insert_textpk oltp_delete_insert_textpk"
483420

484421
# ============================================================
485422
# Output markdown table
@@ -515,6 +452,7 @@ run_section() {
515452
echo "| Average | | | ${avg_ratio} |"
516453
}
517454

455+
echo "<!-- benchmark:classic -->"
518456
echo "## Sysbench-Style Benchmark: Doltlite vs SQLite"
519457
echo ""
520458
echo "### In-Memory"
@@ -555,16 +493,6 @@ echo "#### Writes"
555493
echo ""
556494
run_section "$WRITE_TESTS_AC" "/tmp/bench_file" "/tmp/bench_file"
557495

558-
echo ""
559-
echo "### File-Backed (TEXT PK writes)"
560-
echo ""
561-
echo "_Same workload shapes as the File-Backed Writes section, but on a_"
562-
echo "_table with a 32-char hex \`TEXT PRIMARY KEY\`. Surfaces the non-INTKEY_"
563-
echo "_mutmap-flush path (issue #718). Reporting only — not gated by the_"
564-
echo "_ceiling check below until the fix lands._"
565-
echo ""
566-
run_section "$WRITE_TESTS_TEXTPK" "/tmp/bench_file" "/tmp/bench_file"
567-
568496
echo ""
569497
echo "_${ROWS} rows, single CLI invocation per test, workload-only timing via SQL timestamps._"
570498

0 commit comments

Comments
 (0)