Skip to content

perf: split CommandComplete tags on char (instead of String) - #2011

Open
jkaczman wants to merge 1 commit into
jk-bench-lru-fixed-seedfrom
jk-command-complete-tag-char
Open

jkaczman wants to merge 1 commit into
jk-bench-lru-fixed-seedfrom
jk-command-complete-tag-char

Conversation

@jkaczman

Copy link
Copy Markdown
Contributor

Postgres sends CommandComplete messages with the command at the end of all queries (e.g., INSERT 0 5 after an INSERT of 5 rows). Then, we use Stats::rows_affected to look at the tag of these CommandComplete messages (e.g., INSERT in INSERT 0 5) via the method CommandComplete::tag.

Previously, CommandComplete::tag was splitting the message via a 1-character string (" ") to find the tag. Rust's standard library searches for strings with TwoWaySearcher, the general substring search, which does extra work, such as analyzing the string before searching, which costs extra instructions.

Even in release builds with all optimizations on, the compiler doesn't replace the string " " with the char ' '.

This is now fixed to split on the char ' ', which runs about 56 CPU instructions per call instead of about 224

@jkaczman
jkaczman added this pull request to stack #2012 November 11, 2026 14:23
@codecov

codecov Bot commented Nov 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Metal bench (arm64) passed. All 517 measures within bounds.

suite throughput cpu/txn user cycles/txn user instr/txn kernel cycles/txn kernel instr/txn ctx/txn
pooler 19.05 (+0.1% ± 1.1%) 18,552 (+0.3% ± 0.8%) 31,925 (-0.4% ± 0.08%) 30,159 (-0.1% ± 2.4%) 51,077 (-0.1% ± 0.5%)
lb 19.66 (+0.4% ± 1.2%) 19,161 (+0.2% ± 0.5%) 32,811 (-0.4% ± 0.07%) 30,838 (+0.7% ± 2.0%) 52,134 (-0.0% ± 0.2%)
sharding-w2 31.38 (+0.0% ± 1.2%) 42,829 (+0.0% ± 1.2%) 97,315 (-0.1% ± 0.02%) 38,515 (-0.2% ± 2.6%) 53,748 (+0.0% ± 0.2%) 1.552 (+0.1% ± 0.2%)
sharding-w8 250,620 (+0.2% ± 3.8%) 28.4 (-0.4% ± 3.9%) 43,424 (-0.4% ± 2.6%) 52,835 (-0.2% ± 0.08%) 34,987 (-0.3% ± 5.6%) 42,408 (-0.0% ± 0.2%) 0.1728 (-0.1% ± 3.0%)
Counters per txn
suite frontend stall l1i refill backend stall
pooler 7,964 (+1.4% ± 2.2%) 2,650 (+0.3% ± 0.9%)
lb 8,294 (+1.5% ± 1.4%) 2,707 (+0.3% ± 0.6%)
sharding-w2 16,327 (-0.5% ± 2.8%) 3,923 (-0.2% ± 1.8%)
sharding-w8 17,892 (-1.8% ± 4.2%) 3,780 (-1.2% ± 2.3%)

Microbench: all 504 measures within bounds.

Hot code per txn
path base head change
pooler 111.4 KB 111.7 KB +0.2 KB
sharding-w2 164.6 KB 163.7 KB -0.9 KB

pooler:

crate base head change
pgdog::frontend::client::query_engine 19.4 KB 19.5 KB +0.1 KB
tokio 18.4 KB 18.3 KB -0.1 KB
pgdog::backend::pool 17.4 KB 17.6 KB +0.2 KB
aws-lc (TLS crypto) 10.7 KB 10.3 KB -0.4 KB
rustls (TLS) 8.1 KB 8.4 KB +0.3 KB
pgdog::frontend (other) 7.8 KB 7.8 KB +0.1 KB
pgdog::backend::server 7.3 KB 7.2 KB -0.1 KB
other 6.2 KB 6.4 KB +0.2 KB
everything else 16.1 KB 16.1 KB -0.1 KB
function head change
pgdog::frontend::client::Client::run::{{closure}} 5.5 KB +0.0 KB
pgdog::frontend::client::query_engine::query::<impl pgdog::frontend::client::query_engine: 5.2 KB +0.1 KB
pgdog::frontend::client::query_engine::QueryEngine::handle::{{closure}} 4.1 KB +0.1 KB
tokio::runtime::task::raw::poll 3.2 KB +0.0 KB
pgdog::backend::server::Server::read::{{closure}} 2.9 KB +0.1 KB

sharding-w2:

crate base head change
pgdog::frontend::router 28.6 KB 28.1 KB -0.5 KB
pgdog::frontend::client::query_engine 20.6 KB 20.5 KB -0.1 KB
tokio 18.4 KB 18.4 KB +0.1 KB
pgdog::backend::pool 18.3 KB 17.8 KB -0.5 KB
aws-lc (TLS crypto) 13.2 KB 13.0 KB -0.2 KB
other 9.7 KB 9.9 KB +0.2 KB
pgdog::frontend (other) 8.4 KB 8.6 KB +0.1 KB
rustls (TLS) 8.1 KB 7.9 KB -0.2 KB
everything else 39.2 KB 39.4 KB +0.2 KB
function head change
pgdog::frontend::client::Client::run::{{closure}} 6.0 KB +0.0 KB
pgdog::frontend::client::query_engine::query::<impl pgdog::frontend::client::query_engine: 5.1 KB +0.1 KB
pgdog::frontend::client::query_engine::QueryEngine::handle::{{closure}} 3.9 KB -0.2 KB
pgdog::frontend::router::parser::query::select::<impl pgdog::frontend::router::parser::que 3.3 KB -0.1 KB
tokio::runtime::task::raw::poll 3.2 KB +0.1 KB
lb flamegraph vs a2b6aa9

lb

Open interactive for hover, zoom and search.

lb removed

Open interactive.

microbench flamegraph vs a2b6aa9

microbench

Open interactive for hover, zoom and search.

microbench removed

Open interactive.

pooler flamegraph vs a2b6aa9

pooler

Open interactive for hover, zoom and search.

pooler removed

Open interactive.

sharding-w2 flamegraph vs a2b6aa9

sharding-w2

Open interactive for hover, zoom and search.

sharding-w2 removed

Open interactive.

sharding-w8 flamegraph vs a2b6aa9

sharding-w8

Open interactive for hover, zoom and search.

sharding-w8 removed

Open interactive.

Logs

lb, microbench, pooler, sharding-w2, sharding-w8, verdict.json

Compared b47ea9b with a2b6aa9 on m8g.metal-24xl (spot).

@github-actions

github-actions Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Metal bench (x86) passed. All 517 measures within bounds.

suite throughput cpu/txn user cycles/txn user instr/txn kernel cycles/txn kernel instr/txn ctx/txn
pooler 34.53 (-0.2% ± 0.2%) 22,555 (-0.4% ± 0.3%) 33,810 (-0.5% ± 0.02%) 57,648 (-0.2% ± 0.3%) 38,540 (+0.1% ± 0.2%)
lb 35.55 (+0.1% ± 0.3%) 23,662 (-0.0% ± 0.9%) 34,758 (-0.2% ± 0.8%) 58,644 (+0.2% ± 0.3%) 39,202 (-0.0% ± 0.2%)
sharding-w2 55.57 (-0.3% ± 0.1%) 51,790 (-0.4% ± 1.0%) 101,191 (-0.2% ± 0.08%) 71,841 (-0.3% ± 1.2%) 43,124 (+0.0% ± 0.4%) 1.398 (+0.1% ± 0.3%)
sharding-w8 149,345 (-0.1% ± 0.6%) 48.02 (+0.0% ± 0.6%) 58,130 (+0.1% ± 1.2%) 56,625 (-0.3% ± 0.02%) 63,734 (-0.0% ± 0.4%) 34,219 (+0.0% ± 0.2%) 0.1697 (+0.1% ± 0.6%)
Counters per txn
suite frontend stall l1i refill backend stall
pooler 71,308 (-0.5% ± 1.2%) 3,595 (-0.6% ± 0.2%)
lb 73,761 (+0.1% ± 1.0%) 3,716 (-0.5% ± 0.10%)
sharding-w2 146,715 (-0.1% ± 1.2%) 5,850 (-0.7% ± 0.9%)
sharding-w8 119,228 (-0.5% ± 2.9%) 4,825 (-0.4% ± 0.6%)

Microbench: all 504 measures within bounds.

Hot code per txn
path base head change
pooler 101.8 KB 103.4 KB +1.6 KB
sharding-w2 157.9 KB 157.7 KB -0.2 KB

pooler:

crate base head change
pgdog::frontend::client::query_engine 19.2 KB 19.9 KB +0.7 KB
tokio 17.3 KB 17.6 KB +0.2 KB
pgdog::backend::pool 16.8 KB 17.2 KB +0.4 KB
pgdog::frontend (other) 8.8 KB 9.1 KB +0.3 KB
rustls (TLS) 6.9 KB 6.9 KB +0.1 KB
aws-lc (TLS crypto) 6.9 KB 6.9 KB +0.0 KB
pgdog::backend::server 6.2 KB 6.4 KB +0.2 KB
other 5.9 KB 5.6 KB -0.3 KB
everything else 13.9 KB 13.8 KB -0.1 KB
function head change
pgdog::frontend::client::Client::run::{{closure}} 6.9 KB +0.4 KB
pgdog::frontend::client::query_engine::query::<impl pgdog::frontend::client::query_engine: 6.0 KB +0.4 KB
pgdog::frontend::client::query_engine::QueryEngine::handle::{{closure}} 4.6 KB +0.1 KB
tokio::runtime::task::raw::poll 3.6 KB +0.0 KB
pgdog::frontend::client::query_engine::query::<impl pgdog::frontend::client::query_engine: 2.8 KB -0.1 KB

sharding-w2:

crate base head change
pgdog::frontend::router 27.2 KB 26.9 KB -0.2 KB
pgdog::frontend::client::query_engine 22.1 KB 22.1 KB +0.1 KB
tokio 17.9 KB 18.2 KB +0.3 KB
pgdog::backend::pool 17.8 KB 17.9 KB +0.1 KB
aws-lc (TLS crypto) 10.0 KB 9.9 KB -0.1 KB
other 9.7 KB 9.9 KB +0.2 KB
pgdog::frontend (other) 10.2 KB 9.9 KB -0.3 KB
rustls (TLS) 7.3 KB 7.3 KB +0.0 KB
everything else 35.8 KB 35.5 KB -0.2 KB
function head change
pgdog::frontend::client::Client::run::{{closure}} 7.4 KB -0.2 KB
pgdog::frontend::client::query_engine::query::<impl pgdog::frontend::client::query_engine: 5.8 KB +0.1 KB
pgdog::frontend::client::query_engine::QueryEngine::handle::{{closure}} 5.0 KB +0.1 KB
pgdog::frontend::router::parser::query::select::<impl pgdog::frontend::router::parser::que 4.1 KB +0.1 KB
tokio::runtime::task::raw::poll 3.8 KB +0.0 KB
lb flamegraph vs a2b6aa9

lb

Open interactive for hover, zoom and search.

lb removed

Open interactive.

microbench flamegraph vs a2b6aa9

microbench

Open interactive for hover, zoom and search.

microbench removed

Open interactive.

pooler flamegraph vs a2b6aa9

pooler

Open interactive for hover, zoom and search.

pooler removed

Open interactive.

sharding-w2 flamegraph vs a2b6aa9

sharding-w2

Open interactive for hover, zoom and search.

sharding-w2 removed

Open interactive.

sharding-w8 flamegraph vs a2b6aa9

sharding-w8

Open interactive for hover, zoom and search.

sharding-w8 removed

Open interactive.

Logs

lb, microbench, pooler, sharding-w2, sharding-w8, verdict.json

Compared b47ea9b with a2b6aa9 on c7a.metal-48xl (spot).

@jkaczman
jkaczman force-pushed the jk-command-complete-tag-char branch from 7a4141c to 60712ec Compare November 11, 2026 18:29
@jkaczman
jkaczman force-pushed the jk-command-complete-tag-char branch from 60712ec to b47ea9b Compare November 11, 2026 20:54

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant