Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The procedure is [`spec/20-benchmarks.md`](https://github.com/tamnd/rupg/blob/ma

## Status

Early. The crate builds and CI is green. TPC-H, YCSB and pgbench run, and the other suites do not run yet. `rupg-bench gates` prints the twelve gates of spec/02 section 2.10, `rupg-bench pins` prints the pinned versions, `rupg-bench measure` runs the cgroup v2 runner, `rupg-bench load` runs the load cases, `rupg-bench answers` checks answer sets, `rupg-bench report` writes the report files, `rupg-bench pgbench` runs the pgbench smoke run with its check, `rupg-bench instructions` counts the instructions of each query, `rupg-bench tpch` runs TPC-H, and `rupg-bench ycsb` runs YCSB. The first milestone, M0, builds the harness and measures every baseline that a later gate uses. Every command below is the planned interface from the spec.
Early. The crate builds and CI is green. TPC-H, TPC-C, YCSB and pgbench run, and the other suites do not run yet. `rupg-bench gates` prints the twelve gates of spec/02 section 2.10, `rupg-bench pins` prints the pinned versions, `rupg-bench measure` runs the cgroup v2 runner, `rupg-bench load` runs the load cases, `rupg-bench answers` checks answer sets, `rupg-bench report` writes the report files, `rupg-bench pgbench` runs the pgbench smoke run with its check, `rupg-bench instructions` counts the instructions of each query, `rupg-bench tpch` runs TPC-H, `rupg-bench ycsb` runs YCSB, and `rupg-bench tpcc` runs TPC-C. The first milestone, M0, builds the harness and measures every baseline that a later gate uses. Every command below is the planned interface from the spec.

## The gates

Expand Down Expand Up @@ -80,7 +80,7 @@ The commands below are the planned interface. The harness is one Rust crate with
cargo run --release -- machine up 4xl
cargo run --release -- clickbench --machine 4xl --rows full
cargo run --release -- tpch --scale 100 --machine tpch
cargo run --release -- tpcc --form procedures --machine oltp
cargo run --release -- tpcc --unit postgresql@19-main --steps procedures,statements --sync on,off
cargo run --release -- ycsb --unit postgresql@19-main --workloads a --rows 16
cargo run --release -- connections --count 1000
cargo run --release -- load --case a
Expand Down Expand Up @@ -123,11 +123,13 @@ rupg-bench report --result idle.json --suite idle-base --machine server3 --smoke
rupg-bench pgbench --unit postgresql@19-main --scale 1 --clients 4 --time 30 --smoke --report reports --machine server3
```

`rupg-bench instructions` is the instruction count runner of spec/21 section 21.14. It runs each query of a set under `perf stat -e instructions`. For DuckDB, perf counts the `duckdb` process with one thread. For a server, perf counts the cgroup of the server on all CPUs while `psql` sends the query, so the count is the work of the server and not the work of the client. Each query runs three times and the minimum counts. The count of `SELECT 1` in the same way is subtracted, so the net count is the work of the query. A set is a file with one query on each line, named `q0` to `q42` for ClickBench, or a directory of `<name>.sql` files. A server needs `--engine NAME`, and the report name has the set and the engine. `--ratchet ratchet.toml` fails when one query rises by more than 3 percent or the total by more than 1 percent. `--save` writes the table for the ratchet. The ratchet is filled only on the dedicated runner, so [`ratchet.toml`](ratchet.toml) has no table yet.
`rupg-bench instructions` is the instruction count runner of spec/21 section 21.14. It runs each query of a set under `perf stat -e instructions`. For DuckDB, perf counts the `duckdb` process with one thread. For a server, perf counts the cgroup of the server on all CPUs while `psql` reads the query on its standard input and sends each statement, so the count is the work of the server and not the work of the client. `--password-file` gives `psql` a password in `PGPASSWORD`. Each query runs three times and the minimum counts. The count of `SELECT 1` in the same way is subtracted, so the net count is the work of the query. A set is a file with one query on each line, named `q0` to `q42` for ClickBench, or a directory of `<name>.sql` files. A server needs `--engine NAME`, and the report name has the set and the engine. `--ratchet ratchet.toml` fails when one query rises by more than 3 percent or the total by more than 1 percent. `--save` writes the table for the ratchet. The ratchet is filled only on the dedicated runner, so [`ratchet.toml`](ratchet.toml) has no table yet. `rupg-bench fixed-set --out DIR` writes the YCSB and TPC-C parts of the fixed set: `DIR/ycsb/read1000.sql` has 1,000 point reads with scrambled zipfian keys, and `DIR/tpcc/neword100.sql` has 100 New-Orders in plain statements, with 5 + 2n statements each. The ClickBench part is the 43 queries on the first 1,000,000 rows of `hits`, and the TPC-H part is the 22 queries of `qgen -d` at SF 0.1. Each New-Order set adds 100 orders, so the database grows a little with each run.

```sh
rupg-bench instructions --set clickbench --queries queries.sql --duckdb hits.db --duckdb-bin duckdb
rupg-bench instructions --set clickbench --queries queries.sql --engine postgresql --unit postgresql@19-main --ratchet ratchet.toml
rupg-bench fixed-set --out fixed
rupg-bench instructions --set tpcc --queries fixed/tpcc --engine postgresql --unit postgresql@19-main --conn "user=tpcc dbname=tpcc" --password-file /etc/rupg-bench/tpcc.pass
```

`rupg-bench tpch` is the TPC-H driver of spec/20 section 20.7. `machines/install/tpch-tools.sh` builds `dbgen` and `qgen` 3.0.1 from the pin. The step `gen` runs `dbgen` into the data directory and writes the 22 queries of `qgen -d` to `DATA/queries`. Q15 uses the approved variant A of the kit (a `WITH` clause in place of the view). The step `load` creates the 8 tables with the types, primary keys and foreign keys of the specification and loads the same `.tbl` files into each system. For a server it adds the keys after the rows, then runs `VACUUM ANALYZE` and `CHECKPOINT`. The step `run` runs each query 3 times. The first run is cold: the driver drops the page cache, and for a server it also restarts the unit. The hot time of a query is the smallest of the other runs. Each query runs in its own cgroup, or in the cgroup of the server unit, and the result has the counters of each run. `--answers` checks the answers against the `.out` files of the kit at SF1, or against `.tsv` files from `--save-answers` of another run.
Expand All @@ -143,6 +145,12 @@ rupg-bench tpch --tools tpch_tools_3.0.1/dbgen --scale 1 --data sf1 --engine pos
rupg-bench ycsb --unit postgresql@19-main --records 1000000 --rows 1,16,16x64 --time 60 --sync on
```

`rupg-bench tpcc` is the TPC-C driver of spec/20 section 20.8. It has two forms on the schema that HammerDB builds. The form `procedures` runs HammerDB TPROC-C, which calls the stored procedures that HammerDB makes in the database. The form `statements` is a driver in the harness, because HammerDB has no form with plain statements for PostgreSQL. Its terminals send prepared statements, so a New-Order makes 5 + 2n round trips: the customer and warehouse read with `BEGIN`, the district update, the insert into `orders`, the insert into `new_order`, a read of each item and an update of each stock row, and one insert of all order lines with `COMMIT`. The items are sorted, so two New-Orders do not wait on each other in a cycle, and 1 percent of New-Orders roll back on an unused item. The mix is the HammerDB mix, with no keying or think time. The step `build` drops the database `tpcc` and builds `--warehouses` with HammerDB. Each run has a ramp of `--rampup` minutes and counts `--duration` minutes, for each count of `--vu` and each value of `--sync`. NOPM is the change of `sum(d_next_o_id)` over the counted minutes, as HammerDB counts it. The server cgroup is measured over the same minutes, with the idle base first, so the result has NOPM per core, the server CPU and the device write bytes for each New-Order, and `memory.peak`. The statement form gives the p50, p95 and p99 of each transaction, and the procedure form gives the time profile of HammerDB. For a run with `synchronous_commit` on, the result prints the sync bound `0.45 x 60 x T / s`, with `s` the `fdatasync` p50 that the driver measures next to the data directory. The conditions 1 to 4 of clause 3.3.2 are checked before the runs and after each run, and a run that fails one is not a result. The step `check` only checks them. HammerDB logs in with a password, so run `machines/install/hammerdb.sh` and `machines/install/tpcc-roles.sh` first.

```sh
rupg-bench tpcc --unit postgresql@19-main --warehouses 100 --vu 16 --rampup 5 --duration 20 --sync on,off
```

## The reporting rules

1. A claim has five parts: one named machine, one metric, a baseline that we measured, the same transport on both sides, and the ratio. A claim without all five is not made.
Expand Down
33 changes: 33 additions & 0 deletions machines/install/hammerdb.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash
# Install the HammerDB release of pins.toml into $RUPG_BENCH_OPT/hammerdb.
#
# rupg-bench tpcc runs hammerdbcli from there for the procedure form of TPC-C (spec/20 section 20.8). HammerDB reaches PostgreSQL through libpq, so the script installs libpq5.
set -euo pipefail
# shellcheck source=machines/lib.sh
. "$(dirname "$0")/../lib.sh"

version=$(pin hammerdb version)
url=$(pin hammerdb url)
sha=$(pin hammerdb sha256)
dir=$RUPG_BENCH_OPT/hammerdb
mkdir -p "$RUPG_BENCH_OPT/download"

apt_install libpq5
tarball=$RUPG_BENCH_OPT/download/$(basename "$url")
fetch "$url" "$sha" "$tarball"
if [ ! -x "$dir/hammerdbcli" ] || [ "$(cat "$dir/VERSION" 2>/dev/null)" != "$version" ]; then
rm -rf "$dir" "$dir.part"
mkdir -p "$dir.part"
tar -xzf "$tarball" -C "$dir.part" --strip-components 1
echo "$version" >"$dir.part/VERSION"
mv "$dir.part" "$dir"
fi
[ -x "$dir/hammerdbcli" ] || die "$dir has no hammerdbcli"
# librarycheck prints whether HammerDB can load libpq. hammerdbcli waits for more input at the end of stdin, so the input ends with exit.
check=$(cd "$dir" && printf 'librarycheck\nexit\n' | timeout 120 ./hammerdbcli 2>&1 | grep -A1 'library for PostgreSQL' || true)
case $check in
*Success*) ;;
*) die "HammerDB cannot load libpq: $check" ;;
esac
log "HammerDB $version in $dir"
printf '%s\n' "$dir"
43 changes: 43 additions & 0 deletions machines/install/tpcc-roles.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/bash
# Make the roles that HammerDB needs in the PostgreSQL 19 cluster: hammerdb, a superuser that builds the schema, and tpcc, the owner of the schema.
#
# Usage: tpcc-roles.sh [CLUSTER]. The cluster is main by default. HammerDB makes the database tpcc and the role tpcc itself, so it needs a superuser. The roles log in on the Unix socket with a password, not with trust, because a superuser with trust would let every user of the machine in. The password is random and is kept in /etc/rupg-bench/tpcc.pass, which only root can read. rupg-bench tpcc reads it from there.
set -euo pipefail
# shellcheck source=machines/lib.sh
. "$(dirname "$0")/../lib.sh"
need_root

major=19
cluster=${1:-main}
passfile=/etc/rupg-bench/tpcc.pass
mkdir -p "$(dirname "$passfile")"
if [ ! -s "$passfile" ]; then
(umask 077 && head -c 24 /dev/urandom | base64 | tr -dc 'A-Za-z0-9' >"$passfile")
fi
pass=$(cat "$passfile")
port=$(pg_lsclusters -h | awk -v v="$major" -v c="$cluster" '$1 == v && $2 == c { print $3 }')
[ -n "$port" ] || die "there is no cluster $major/$cluster"

# The rules for the socket. They go first, so the peer rule of the package does not reject the roles. The method password asks the client for the password in clear text over the socket, so the small client of rupg-bench can use it too.
hba=/etc/postgresql/$major/$cluster/pg_hba.conf
for role in tpcc hammerdb; do
if ! grep -qE "^local[[:space:]]+all[[:space:]]+${role}[[:space:]]+password" "$hba"; then
sed -i "1i local all $role password" "$hba"
fi
done
psql_su() {
sudo -u postgres psql -h /var/run/postgresql -p "$port" -qAt "$@"
}
psql_su -c "SELECT pg_reload_conf()" >/dev/null
if [ "$(psql_su -c "SELECT count(*) FROM pg_roles WHERE rolname = 'hammerdb'")" = 0 ]; then
psql_su -c "CREATE ROLE hammerdb LOGIN SUPERUSER"
fi
# The password goes on standard input, so it is not on a command line that ps shows. It has only letters and digits, so the quotes are safe.
set_password() {
printf "ALTER ROLE %s PASSWORD '%s';\n" "$1" "$pass" | psql_su -v ON_ERROR_STOP=1 -f -
}
set_password hammerdb
if [ "$(psql_su -c "SELECT count(*) FROM pg_roles WHERE rolname = 'tpcc'")" != 0 ]; then
set_password tpcc
fi
log "roles hammerdb and tpcc in $major/$cluster on port $port, password in $passfile"
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"suite": "instructions-tpcc-postgresql",
"machine": "server3",
"date": "2026-10-07",
"commit": "b41f7e63",
"smoke": true,
"note": "smoke run: it shows that the runner works, it is not the ratchet",
"set": "tpcc",
"engine_name": "postgresql",
"queries_from": "/root/work/fixed2/tpcc",
"repeat": 3,
"kernel": "6.8.0-106-generic",
"engine": {
"mode": "server cgroup",
"cgroup": "system.slice/system-postgresql.slice/postgresql@19-ycsb.service",
"client": [
"/usr/lib/postgresql/19/bin/psql",
"-X",
"-q",
"-v",
"ON_ERROR_STOP=1",
"-h",
"/var/run/postgresql",
"-p",
"5433",
"-U",
"tpcc",
"-d",
"tpcc",
"-o",
"/dev/null",
"-f",
"-"
]
},
"counts": {
"base_runs": [52594897, 52581519, 47058645],
"base": 47058645,
"total_net": 870376156
},
"queries": [
{
"query": "neword100",
"net": 870376156,
"runs": [956960680, 918670439, 917434801]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# instructions-tpcc-postgresql on server3, 2026-10-07

**This is a smoke run.** It shows that the driver works. It ran on a small scale or on a shared machine, so its numbers are not baselines and no claim may use them.

| Field | Value |
|---|---|
| suite | instructions-tpcc-postgresql |
| machine | server3 |
| date | 2026-10-07 |
| commit | b41f7e63 |
| smoke | true |
| note | smoke run: it shows that the runner works, it is not the ratchet |
| set | tpcc |
| engine_name | postgresql |
| queries_from | /root/work/fixed2/tpcc |
| repeat | 3 |
| kernel | 6.8.0-106-generic |

## engine

| Field | Value |
|---|---|
| mode | server cgroup |
| cgroup | system.slice/system-postgresql.slice/postgresql@19-ycsb.service |
| client | /usr/lib/postgresql/19/bin/psql, -X, -q, -v, ON_ERROR_STOP=1, -h, /var/run/postgresql, -p, 5433, -U, tpcc, -d, tpcc, -o, /dev/null, -f, - |

## counts

| Field | Value |
|---|---|
| base_runs | 52594897, 52581519, 47058645 |
| base | 47058645 |
| total_net | 870376156 |

## queries

| query | net | runs |
|---|---|---|
| neword100 | 870376156 | 956960680, 918670439, 917434801 |

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"suite": "instructions-ycsb-postgresql",
"machine": "server3",
"date": "2026-10-07",
"commit": "b41f7e63",
"smoke": true,
"note": "smoke run: it shows that the runner works, it is not the ratchet",
"set": "ycsb",
"engine_name": "postgresql",
"queries_from": "/root/work/fixed2/ycsb",
"repeat": 3,
"kernel": "6.8.0-106-generic",
"engine": {
"mode": "server cgroup",
"cgroup": "system.slice/system-postgresql.slice/postgresql@19-ycsb.service",
"client": [
"/usr/lib/postgresql/19/bin/psql",
"-X",
"-q",
"-v",
"ON_ERROR_STOP=1",
"-h",
"/var/run/postgresql",
"-p",
"5433",
"-U",
"bench",
"-d",
"bench",
"-o",
"/dev/null",
"-f",
"-"
]
},
"counts": {
"base_runs": [11591789, 8824882, 9880131],
"base": 8824882,
"total_net": 197406645
},
"queries": [
{
"query": "read1000",
"net": 197406645,
"runs": [830706694, 206231527, 238045194]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# instructions-ycsb-postgresql on server3, 2026-10-07

**This is a smoke run.** It shows that the driver works. It ran on a small scale or on a shared machine, so its numbers are not baselines and no claim may use them.

| Field | Value |
|---|---|
| suite | instructions-ycsb-postgresql |
| machine | server3 |
| date | 2026-10-07 |
| commit | b41f7e63 |
| smoke | true |
| note | smoke run: it shows that the runner works, it is not the ratchet |
| set | ycsb |
| engine_name | postgresql |
| queries_from | /root/work/fixed2/ycsb |
| repeat | 3 |
| kernel | 6.8.0-106-generic |

## engine

| Field | Value |
|---|---|
| mode | server cgroup |
| cgroup | system.slice/system-postgresql.slice/postgresql@19-ycsb.service |
| client | /usr/lib/postgresql/19/bin/psql, -X, -q, -v, ON_ERROR_STOP=1, -h, /var/run/postgresql, -p, 5433, -U, bench, -d, bench, -o, /dev/null, -f, - |

## counts

| Field | Value |
|---|---|
| base_runs | 11591789, 8824882, 9880131 |
| base | 8824882 |
| total_net | 197406645 |

## queries

| query | net | runs |
|---|---|---|
| read1000 | 197406645 | 830706694, 206231527, 238045194 |

Loading
Loading