Re: [PATCH] Refactor pgbench to make future improvements easier

From: Hannu Krosing <hannuk(at)google(dot)com>
To: Zsolt Parragi <zsolt(dot)parragi(at)percona(dot)com>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: [PATCH] Refactor pgbench to make future improvements easier
Date: 2026-10-18 15:16:39
Message-ID: CAMT0RQR5dQLo5FQ47CMXcf9GokzhBs4i22WtRgjYWUHkY10xEA@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

[PATCH v5 00/22]
* Modular pgbench refactoring,
* contrib/pgbench extension,
* advanced benchmark capabilities,
* and standard workload suites (pgbench-b, pgbench-c, pgbench-e,
pgbench-h, pgbench-ds, pgbench-htap)

Hi hackers,

This patch series presents a comprehensive modernization of pgbench,
transforming
it from a monolithic single-script driver into a modern, modular, multi-workload
benchmarking engine with native support for complex OLTP, OLAP, and
HTAP benchmarks.

See https://wiki.postgresql.org/wiki/Pgbench-modernization-2026 for
more background and rationale.

The series is organized into five logical parts across 22 clean, self-contained
commits rebased cleanly on latest master:

================================================================================
Part 1: Modular pgbench Refactoring (Patches 0001 - 0012)
================================================================================
pgbench.c had grown to over 7,400 lines combining distinct responsibilities:
statistics accumulation, variable management, event polling, script parsing,
meta-command execution, database initialization (-i), and the multi-threaded
state machine.

Patches 0001-0007 extract these modules without altering behavior or
public APIs:
- stats.c / stats.h: StatsData, latency tally, rate-limiting logic.
- variable.c / variable.h: Scoped variable store and value evaluation.
- poller.c / poller.h: Socket set polling abstraction (select/poll).
- script.c / script.h: Script parsing, AST nodes, expression evaluator.
- commands.c / commands.h: Meta-command handlers and prepared
statement helpers.
- init.c / init.h: Database initialization (-i) logic and data generators.
- engine.c / engine.h: Multi-threaded client state machine and event loop.

Patches 0008-0012 decouple remaining global dependencies cleanly:
- stats: add mergeStats() and decouple global flags.
- variable: introduce scoped variable store (VariableSpace).
- poller: encapsulate socket_set and provide poller API wrappers.
- script: decouple chooseScript() from TState.
- commands: introduce pluggable meta-command dispatch table.

================================================================================
Part 2: Code Extraction & In-Database Functions (Patches 0013 - 0014)
================================================================================
Patch 0013 extracts pgbench's mathematical and pseudo-random
generators (Gaussian,
Exponential, Zipfian, Permute, MurmurHash64) into src/common/pgbench_funcs.c,
making them reusable across both client and server binaries.

Patch 0014 introduces contrib/pgbench, a server-side extension that
exposes these
pseudo-random generators and helper functions directly to SQL under
SCHEMA pgbench.
This allows high-performance parallel in-database synthetic data
generation using
standard SQL (e.g. generate_series()) without relying on slow client roundtrips.

================================================================================
Part 3: Advanced Types, Functions, Control Flow & Pacing (Patches 0015 - 0019)
================================================================================
Patch 0015 extends PgBenchValue with text, timestamp, and array types,
along with
array operations (array_append, array_length, array_get, array_generate), text
concatenation, and timestamp arithmetic.

Patch 0016 adds standard benchmark helper functions to pgbench expressions and
contrib/pgbench:
- nurand(A, s, x, y): Non-uniform random distribution generator.
- c_last(num): Syllable-based customer last name generator.
- random_astring(min, max), random_nstring(min, max): Alphanumeric
and numeric strings.
- format_string(fmt, ...), date_add(ts, amt, unit), int_to_date(int).

Patch 0017 adds script control flow and exception handling:
- Loops: \for <var> <start> .. <end> [BY <step>], \while <expr>,
\break, \continue.
- Exception handling: \try ... \catch [<sqlstate>] ... \endtry,
\expect_error <sqlstate>.

Patch 0018 adds result set metadata inspection and array column parsing:
- \gset_meta <prefix>: Extracts query result status, error code,
rows affected, and timing.
- \aset and array-aware \gset: Maps multi-row query results into
client-side array variables.

Patch 0019 introduces dynamic client pacing:
- Dynamic \sleep expressions (e.g. \sleep random_exponential(1, 1000, 10) ms).
- \keying_time and \think_time commands for realistic transaction
pacing per specification.

================================================================================
Part 4: Heterogeneous Groups, Latency Percentiles & Reporting (Patches
0020 - 0021)
================================================================================
Patch 0020 introduces heterogeneous client groups via --group:
- Run concurrent mixes of different scripts with distinct client
counts and rates
(e.g., --group name=oltp,clients=10,weight=100 --group
name=olap,clients=2,sequential=true).
- Supports sequential stream execution for multi-query analytical streams.

Patch 0021 implements High Dynamic Range (HDR) latency histogram tracking:
- Configurable percentiles (p50, p90, p95, p99, p99.9).
- SLA validation via --sla target=<metric>,threshold=<value>.
- Metric computation for tpmC and QphH(at)SF(dot)
- Structured machine-readable JSON output via --json-report=<path>.

================================================================================
Part 5: Standard Workload Suites (Patch 0022)
================================================================================

<THIS WAS LEFT OUT FROM THIS EMAIL>

* Trademark & Naming Rationale:
These workloads are inspired by and modeled after industry-standard
specifications
(TPC-C, TPC-E, TPC-H, TPC-DS, and CH-benCHmark). To respect and
avoid infringing
upon Transaction Processing Performance Council (TPC) trademarks,
and to clearly
distinguish these community engineering tools from official
council-audited benchmarks,
they are explicitly named pgbench-b, pgbench-c, pgbench-e,
pgbench-h, pgbench-ds, and pgbench-htap.
Full background and guidelines are documented in
src/bin/pgbench/workloads/README.

* In-Database Parallel Loading:
Each workload includes an initialization script
(<workload>_init.sql) designed to
run in parallel across multiple worker sessions (-c N -j N -t 1 -D
num_workers=N).
Data generation is executed entirely within the database engine
using generate_series()
and contrib/pgbench SQL functions, achieving rapid parallel load
rates without external
file generation or ETL binaries.

Comprehensive documentation is provided in doc/src/sgml/ref/pgbench.sgml and
doc/src/sgml/pgbench-ext.sgml, and full end-to-end TAP coverage is added in
src/bin/pgbench/t/001_pgbench_with_server.pl (passing all tests across
all platforms).

Feedback, testing, and reviews are warmly welcomed!

Hannu Krosing (22):
Refactor pgbench: extract statistics structures and functions to
stats.c/h
Refactor pgbench: extract variable management and value types to
variable.c/h
Refactor pgbench: extract socket polling abstraction to poller.c/h
Refactor pgbench: extract script parsing, built-in scripts, and
expression evaluation to script.c/h
Refactor pgbench: extract meta-command execution and prepared
statement helpers to commands.c/h
Refactor pgbench: extract database initialization (-i) to init.c/h
Refactor pgbench: extract benchmark execution engine and client state
machine to engine.c/h
Refactor pgbench stats: add mergeStats() and decouple global flags
Refactor pgbench variables: introduce scoped variable store
Refactor pgbench poller: encapsulate socket_set and add poller API
aliases
Refactor pgbench script: decouple chooseScript() from TState
Refactor pgbench commands: introduce pluggable meta-command dispatch
Extract pgbench low-level functions into src/common
Add contrib/pgbench extension exposing benchmark functions in SCHEMA
pgbench
pgbench: Extend PgBenchValue with text, timestamp, and array types
pgbench: Add TPC-C NURand, syllable, string, date/timestamp, and array
functions
pgbench: Add script loops (\for, \while) and exception handling (\try,
\catch, \expect_error)
pgbench: Add \gset_meta and array column parsing in \gset and \aset
pgbench: Support dynamic \sleep expressions, \keying_time, and
\think_time
pgbench: Add heterogeneous client groups (--group) and sequential
streams
pgbench: Add HDR latency percentiles, --sla validation, tpmC/QphH
metrics, and --json-report
pgbench: Add pgbench-b, pgbench-c, pgbench-e, pgbench-h, pgbench-ds,
and pgbench-htap workload suites

---
Hannu

Attachment Content-Type Size
v5-0001-Refactor-pgbench-extract-statistics-structures-an.patch application/x-patch 24.2 KB
v5-0003-Refactor-pgbench-extract-socket-polling-abstracti.patch application/x-patch 15.8 KB
v5-0004-Refactor-pgbench-extract-script-parsing-built-in-.patch application/x-patch 267.3 KB
v5-0002-Refactor-pgbench-extract-variable-management-and-.patch application/x-patch 38.5 KB
v5-0006-Refactor-pgbench-extract-database-initialization-.patch application/x-patch 53.7 KB
v5-0005-Refactor-pgbench-extract-meta-command-execution-a.patch application/x-patch 33.4 KB
v5-0007-Refactor-pgbench-extract-benchmark-execution-engi.patch application/x-patch 151.5 KB
v5-0008-Refactor-pgbench-stats-add-mergeStats-and-decoupl.patch application/x-patch 8.5 KB
v5-0009-Refactor-pgbench-variables-introduce-scoped-varia.patch application/x-patch 19.2 KB
v5-0011-Refactor-pgbench-script-decouple-chooseScript-fro.patch application/x-patch 2.6 KB
v5-0010-Refactor-pgbench-poller-encapsulate-socket_set-an.patch application/x-patch 5.2 KB
v5-0012-Refactor-pgbench-commands-introduce-pluggable-met.patch application/x-patch 28.9 KB
v5-0013-Extract-pgbench-low-level-functions-into-src-comm.patch application/x-patch 27.1 KB
v5-0014-Add-contrib-pgbench-extension-exposing-benchmark-.patch application/x-patch 28.4 KB
v5-0016-pgbench-Add-TPC-C-NURand-syllable-string-date-tim.patch application/x-patch 75.9 KB
v5-0015-pgbench-Extend-PgBenchValue-with-text-timestamp-a.patch application/x-patch 62.8 KB
v5-0017-pgbench-Add-script-loops-for-while-and-exception-.patch application/x-patch 49.5 KB
v5-0018-pgbench-Add-gset_meta-and-array-column-parsing-in.patch application/x-patch 25.9 KB
v5-0019-pgbench-Support-dynamic-sleep-expressions-keying_.patch application/x-patch 27.3 KB
v5-0020-pgbench-Add-heterogeneous-client-groups-group-and.patch application/x-patch 30.0 KB
v5-0021-pgbench-Add-HDR-latency-percentiles-sla-validatio.patch application/x-patch 36.5 KB

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Greg Burd 2026-10-18 15:30:47 ILIKE '%' never matches a non-ASCII byte in single-byte C-ctype databases
Previous Message Jim Jones 2026-10-18 14:14:25 Re: Reject COPY TO of unlogged relations during recovery