Skip to content

Size the gr buffer pool to the dataset and profile LSQB on SF1 - #53

Open
tamnd wants to merge 2 commits into
mainfrom
profile-lsqb-sf1
Open

Size the gr buffer pool to the dataset and profile LSQB on SF1#53
tamnd wants to merge 2 commits into
mainfrom
profile-lsqb-sf1

Conversation

@tamnd

@tamnd tamnd commented Jun 27, 2026

Copy link
Copy Markdown
Owner

Profiling gr on the real LDBC SNB SF1 graph (3.0M nodes, 17.2M edges, a 1 GB database) found both the bulk load and the heavy LSQB queries bottlenecked on the pager, not on the query plan.
A quarter of the load sat in buffer-pool eviction, and the slowest query's stack was dominated by pread re-reading store pages the pool had just dropped.
The cause was gr's default 1024-page pool, about 4 MB, holding 0.4% of a 1 GB database resident. A 4 MB cache in front of a 1 GB database is a misconfiguration, not a number worth reporting.

This sizes the pool to the data. The adapter computes a page count from the database file size on disk (and from the input CSV bytes for the bulk loader's build pool), with a quarter headroom and a 4 GiB cap, and passes it through gr's new MaxPoolPages option.
pool_pages overrides the auto-sizing with a fixed count; pool_max_bytes overrides the cap.
Sizing the pool to hold the working set drops the heaviest measured query from 15.1s to 8.0s, a 1.9x win that is pure removed disk I/O.

Depends on gr PR #229, which exposes MaxPoolPages on gr.Options and loader.Options (the adapter builds against the local gr replace).

Adds TestProfileLSQBOnSF1, gated behind GRAPH_BENCH_SF1:

  • loads SF1 into gr once and caches the loaded database so later runs skip the twelve-minute load
  • times every LSQB query, streaming each p50 and count as it lands
  • takes GRAPH_BENCH_ONLY / GRAPH_BENCH_SKIP comma-separated substring filters to isolate or step around one query while it is optimized
  • writes a query-phase CPU profile when GRAPH_BENCH_QUERY_PROFILE is set

After the pool fix the slow queries (q3, q6, q7) sample with zero pread: they are now fully CPU-bound in the join and enumeration.
The bottleneck moved from the pager to the planner, which is the next frontier and a separate change. Full write-up in notes/Spec/2060/bench/implementation/lsqb-sf1-buffer-pool-profiling.md.

tamnd added 2 commits June 27, 2026 18:32
Profiling gr on the real LDBC SNB SF1 graph (3.0M nodes, 17.2M edges, a
1 GB database) showed both the bulk load and the heavy queries bottlenecked
on the pager. A quarter of the load sat in buffer-pool eviction, and the
slowest query's stack was dominated by pread re-reading store pages the
pool had just dropped. The cause was gr's default 1024-page pool, about
4 MB, holding 0.4% of a 1 GB database resident.

Size the pool to the data instead. The adapter computes a page count from
the database file size on disk (and from the input CSV bytes for the bulk
loader's build pool), with headroom and a memory cap, and passes it through
gr's new MaxPoolPages option. An explicit pool_pages config value overrides
the auto-sizing; pool_max_bytes overrides the cap. Sizing the pool to hold
the working set drops the heaviest measured query from 15.1s to 8.0s, pure
removed disk I/O.

Add TestProfileLSQBOnSF1, gated behind GRAPH_BENCH_SF1: it loads SF1 into
gr once (caching the loaded database so later runs skip the load), times
every LSQB query, streams each p50 and count, takes ONLY/SKIP substring
filters to isolate one query, and writes a query-phase CPU profile. It is
the inner loop for the planner work the profile points to next, where the
slow queries are now CPU-bound in the join and enumeration with no I/O left.
The profiler shows which query is slow; this shows why. TestExplainLSQBOnSF1
prints gr's chosen plan for each LSQB query on the real SF1 graph, so a query
that falls out of the fused count into a materializing Intersect is visible in
the plan tree rather than inferred from the timing. Both it and the profiler
take GRAPH_BENCH_ONLY and GRAPH_BENCH_SKIP so a single pathological query can be
explained or stepped around in isolation.
@tamnd

tamnd commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

Leaving this open but it will not merge as it stands.

Every file it touches except the test lives in adapter/gr/, and #55 deleted adapter/ when it replaced it with engine/. The rewrite also has no gr engine: engine/ holds bolt, ladybug, memgraph, neo4j and zu. So there is nothing here for the diff to apply to.

It also does not build against the current tamnd/gr, which does not have MaxPoolPages on Options (gr#229 is still open).

The profiling result stands on its own and is worth keeping. Landing it means writing a gr engine against the v0.3 SPI and carrying the pool sizing into it, which is its own change. Say the word and I will do that as a fresh PR.

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