Quickstart¶
See also: setup, overview, guides/evaluation-runbook
This guide walks you through your first PBT tuning session and explains what's happening at each step. Targeted at someone who has just run setup.md successfully and wants to confirm the system works.
Time required: about 5 minutes for a minimal run on modern hardware.
What you'll learn: how to launch a tuning run, where the artefacts go, and how to read the session JSON without parsing it programmatically.
Prerequisites¶
You have:
- Run setup successfully (
.venvactive,.envconfigured, sysbench 1.1.0 inPATH). - Either Docker running (recommended) or a local PostgreSQL 14+ accepting connections.
Verify:
source .venv/bin/activate
python -m src.tuners pbt --help # should print the CLI help
docker info >/dev/null && echo OK # should print "OK"
If docker info fails, the run will automatically fall back to bare-metal PostgreSQL with a reduced-isolation warning. That's fine for a first quickstart.
Step 1 — Launch the smallest possible PBT run¶
What this does, line by line:
| Argument | Effect |
|---|---|
--tier minimal |
Tunes only the 5 highest-impact knobs (shared_buffers, effective_cache_size, work_mem, random_page_cost, max_parallel_workers_per_gather). The other tiers (core, standard, extensive) are larger search spaces with longer runtimes. |
--config rapid |
A pre-configured PBTConfig profile with short evaluation durations. The other profiles (standard, thorough) are slower but produce stronger results. |
--population 2 |
Two workers in parallel. Each gets its own PostgreSQL instance on its own port (5440, 5441). |
--generations 5 |
Maximum five generations. The session may stop earlier if convergence or early-stopping triggers. |
The CLI prints a startup banner and begins evaluating. On a typical laptop you should see the first generation complete within roughly a minute.
Step 2 — What's happening during a generation¶
The terminal output is colour-coded; the same content goes to an HTML log under results/. A generation looks like this:
═══════ Generation 1 / 5 ═══════
▶ Worker 0 | applying config (B2)
▶ Worker 1 | applying config (B2)
▶ Worker 0 | config_applied — wait barrier (B2)
▶ Worker 1 | config_applied — wait barrier (B2)
▶ Worker 0 | measurement window 30s (B9)
▶ Worker 1 | measurement window 30s (B9)
...
▶ Worker 0 | score: 0.642 (lat_p95=43ms tps=1820 mem=0.31)
▶ Worker 1 | score: 0.715 (lat_p95=39ms tps=1980 mem=0.35)
✓ Generation 1 complete best=0.715 mean=0.679 std=0.052
The B2, B9 etc. markers are the lockstep generation barriers. Every worker waits at every marker until all workers have arrived — that's how the framework guarantees the workers' measurement windows overlap, eliminating scheduling artefacts from the score.
If you only see one worker, the population is too small for barriers to do anything useful — that's fine for a quickstart but always run --population >= 4 for a real campaign.
Step 3 — Find the session artefacts¶
When the run finishes (or hits convergence), the CLI prints the output paths:
✓ Session complete — best score 0.842 (Worker 1, generation 4)
JSON: results/oltp/oltp_read_write/pbt_runs/minimal/tuning_sessions/pbt_results_20260607_1842.json
HTML: results/oltp/oltp_read_write/pbt_runs/minimal/logs/pbt_session_20260607_1842.html
The HTML log is the easiest way to inspect what happened — it's the same colour-coded transcript you saw on the terminal, but persistent and shareable.
The JSON is the canonical artefact. Open it in any JSON viewer:
python -m json.tool results/oltp/oltp_read_write/pbt_runs/minimal/tuning_sessions/pbt_results_*.json | less
Look for these top-level keys:
| Key | What it tells you |
|---|---|
tuning_session.benchmark / workload_type / seed |
What the session was, deterministically. |
tuning_session.scoring_policy / scoring_policy_version |
Which scoring formula evaluated this session. |
best_configuration.knobs |
The configuration that won. This is the actionable output. |
best_configuration.score_breakdown |
Resolved weights + per-metric utilities + reliability gate. Read this to understand why the winning config won. |
generation_history[] |
Per-generation snapshot — best/mean/std scores, exploit count, per-worker metrics. |
system_info, worker_resources |
Reproducibility metadata: host CPU/RAM, per-worker resource slice, Python and PostgreSQL versions. |
The schema is documented exhaustively in reference/session-json-schema.
Step 4 — Verify the tuned config beats the default¶
A tuning session by itself only tells you which configurations PBT explored — it doesn't tell you whether the winner is statistically better than the PostgreSQL default under controlled conditions. The post-hoc evaluation suite answers that:
python -m src.evaluation \
--session results/oltp/oltp_read_write/pbt_runs/minimal/tuning_sessions/pbt_results_<timestamp>.json \
--repetitions 5
This runs the default and tuned configurations against the same workload with paired seeds, then computes Wilcoxon, bootstrap CI, and Cohen's d on the differences. The output JSON in results/oltp/oltp_read_write/comparisons/minimal/ is what you'd cite in a paper or pull request.
For the runbook including all flags, scoring-policy overrides, and reproducibility checklist, see guides/evaluation-runbook.
Common first-run hiccups¶
| Symptom | Likely cause | Fix |
|---|---|---|
Docker unavailable, falling back to Bare Metal warning |
Docker daemon not running or not reachable. | Start Docker, or accept reduced isolation (fine for development; not for publication). |
connection refused on port 5440 |
A previous session left an instance behind. | python -m src.scripts.cleanup_instances |
DB_PASSWORD environment variable is required |
.env not loaded or missing the variable. |
Re-check setup §3; confirm the .env exists in the project root. |
sysbench: command not found |
sysbench 1.1.0 not installed (the prepackaged 1.0.20 is not sufficient). | Follow setup §Sysbench. |
| First generation takes far longer than later ones | TPC-H dbgen is compiling and generating data the first time. |
Expected — only happens once per scale factor. |
Where to go next¶
- Run something more realistic.
--tier core --config standard --population 4 --generations 30is a typical configuration. Expect ~15-20 minutes on modern hardware. - Tune for your own workload. Author a JSON template — see guides/adding-workloads.
- Compare PBT against a Bayesian-Optimisation baseline. See guides/bo-baseline and guides/pbt-vs-bo-comparison.
- Understand what just happened. Read architecture/overview, then drill down into specific subsystems.