Skip to main content

Benchmark Results

For evaluators who want a quick performance picture before reading the full benchmarking workflow.

These charts use reviewed live Linux VM runs. They are not universal performance claims. They are reproducible snapshots from isolated environments, with five 30-second rounds per target and one PostgreSQL instance per target.

The latest result on this page is the July 24, 2026 io_uring simple-query run.

The comparison uses capacity-matched benchmark settings: each PostgreSQL backend accepts up to 512 connections, pg-kinetic uses PG_KINETIC_MAX_BACKENDS=512 and PG_KINETIC_POOL_MAX_SIZE=512, and PgBouncer and PgDog use default_pool_size=512. Detailed phase timing and debug trace sampling were disabled for the run.

Latest io_uring Simple Query

Higher throughput is better. Lower latency is better.

Targetc=64 median TPSc=64 median msc=256 median TPSc=256 median ms
direct PostgreSQL105,358.80.607111,780.22.290
PgBouncer31,614.12.02428,097.99.111
PgDog25,787.22.48224,787.710.328
pg-kinetic thread_per_core54,259.81.18057,807.44.428
pg-kinetic io_uring59,969.51.06765,327.03.919

In this run, io_uring is about 10.5% faster than thread_per_core at c=64 and about 13.0% faster at c=256. It is about 132.5% faster than PgBouncer and about 163.6% faster than PgDog at c=256. Direct PostgreSQL remains the throughput ceiling.

Prior thread_per_core Simple Query

Higher is better.

Targetc=64 TPSc=64 avg msc=256 TPSc=256 avg ms
direct PostgreSQL54,523.91.17449,748.05.146
PgBouncer23,698.42.70123,475.210.905
PgDog21,111.73.03119,886.112.873
pg-kinetic32,808.21.95138,099.26.719

Prior thread_per_core Prepared Statement

Higher is better.

Targetc=64 TPSc=64 avg msc=256 TPSc=256 avg ms
direct PostgreSQL68,834.30.93065,225.83.925
PgBouncer22,328.82.86622,058.811.605
PgDog20,957.43.05420,353.612.578
pg-kinetic40,984.71.56250,572.95.062

Prior thread_per_core Tail Latency

Lower is better.

WorkloadTargetc=256 p95 msc=256 p99 ms
Simple querydirect PostgreSQL10.20613.597
Simple queryPgBouncer14.84318.072
Simple queryPgDog17.84620.687
Simple querypg-kinetic12.61317.308
Prepared statement reusedirect PostgreSQL7.2039.321
Prepared statement reusePgBouncer14.56516.728
Prepared statement reusePgDog17.24919.827
Prepared statement reusepg-kinetic10.00713.833

How To Read This

Direct PostgreSQL is the ceiling for proxy overhead, not a drop-in comparison for connection-storm behavior. It does not provide the proxy boundary, route-aware backpressure, admin views, or pooling behavior being evaluated.

PgBouncer and PgDog are included as directional comparison targets because the benchmark stack starts one isolated PostgreSQL backend per target. These numbers do not claim broad feature parity or global superiority.

In the July 24 io_uring snapshot, pg-kinetic is the fastest pooler target for the simple-query workload at both c=64 and c=256. In the July 23 thread_per_core snapshot, pg-kinetic is the fastest pooler target for both simple and prepared read-only workloads. Direct PostgreSQL remains the throughput ceiling in both snapshots.

Transaction-pool write-heavy results are intentionally excluded from the headline table. The current TPC-B style write workload is dominated by PostgreSQL commit and fsync behavior, so it is not a clean proxy-overhead comparison.

Prior thread_per_core Commands

The July 23 thread_per_core run used the compose benchmark stack with the comparison profile:

export PGPASSWORD=postgres
export PG_KINETIC_RUNTIME_ENGINE=thread_per_core
export PG_KINETIC_PHASE_TIMING_SAMPLE_RATE=0.0
export PG_KINETIC_DEBUG_TRACE_SAMPLING_RATE=0.0
export PG_KINETIC_MAX_BACKENDS=512
export PG_KINETIC_POOL_MAX_SIZE=512

sudo -E docker compose -f bench/compose.yml --profile comparison up -d --wait --build

For the Linux io_uring benchmark target, build the benchmark image with the io-uring cargo feature and opt in to the runtime explicitly:

export PG_KINETIC_BENCH_FEATURES=io-uring
export PG_KINETIC_RUNTIME_ENGINE=io_uring
export PG_KINETIC_EXPERIMENTAL_RUNTIME_ENABLED=true
export PG_KINETIC_PHASE_TIMING_SAMPLE_RATE=0.0

sudo -E docker compose -f bench/compose.yml up -d --wait --build pg-kinetic driver

The benchmark compose service runs pg-kinetic with seccomp=unconfined because Docker's default seccomp profile blocks the io_uring_setup syscall used by monoio.

Each isolated PostgreSQL backend was initialized before measurement:

sudo docker compose -f bench/compose.yml exec -T -e PGPASSWORD=postgres driver \
pgbench -i -s 10 -h pg-direct -p 5432 -U postgres pgkinetic

sudo docker compose -f bench/compose.yml exec -T -e PGPASSWORD=postgres driver \
pgbench -i -s 10 -h pg-bouncer-db -p 5432 -U postgres pgkinetic

sudo docker compose -f bench/compose.yml exec -T -e PGPASSWORD=postgres driver \
pgbench -i -s 10 -h pg-dog-db -p 5432 -U postgres pgkinetic

sudo docker compose -f bench/compose.yml exec -T -e PGPASSWORD=postgres driver \
pgbench -i -s 10 -h pg-kinetic-db -p 5432 -U postgres pgkinetic

The simple-query workload was run for each target, each concurrency, and each of five interleaved rounds:

pgbench -h 127.0.0.1 -p <port> -U postgres \
-c <64-or-256> -j 8 -T 30 --log --log-prefix <outside-git-path> \
-n -S pgkinetic

The prepared-statement workload used the same matrix with prepared query mode:

pgbench -h 127.0.0.1 -p <port> -U postgres \
-c <64-or-256> -j 8 -T 30 --log --log-prefix <outside-git-path> \
-n -M prepared -S pgkinetic

The target ports were:

TargetPort
direct PostgreSQL55432
PgBouncer56432
PgDog57432
pg-kinetic58432

The stack was stopped after collection:

sudo docker compose -f bench/compose.yml --profile comparison down --volumes --remove-orphans

Reproduce Or Update

The checked-in baseline reports used by the regression score gate are:

  • bench/baselines/simple-query.json
  • bench/baselines/transaction-pool.json
  • bench/baselines/prepared.json

The July 23, 2026 capacity-matched VM run and the July 24, 2026 io_uring run were collected as raw benchmark output outside Git. Read Benchmarking before updating these numbers. Do not replace checked-in baselines with dry-run output or a single local measurement.

No reviewed io_uring flamegraph is currently published with these results. When profiling a new io_uring run, retain the raw perf, folded-stack, and flamegraph artifacts outside Git and summarize the top costs beside the throughput and tail-latency tables.