Repository navigation
Conversation
…ighbour refill A rel scan decoded the CSR header span from the entry before a batch's first bound node to its last one. For bound nodes spread thinly over a node group that span is most of the header: LDBC SF1 q22 decoded 7.2M entries for 909 bound nodes. Every refill of the neighbour cache also copied the next 2048 CSR rows, whether the batch needed them or not. A batch whose span is at least 4x its bound nodes now decodes only clusters of the entries those nodes need, merging runs under 256 entries apart, in place in the full-size header buffer: at most 256 clusters, counted as one of the group's 16 partial decodes. The header records the decoded ranges and a whole-header flag, so a later batch re-decodes only when one of its nodes falls outside them, and nodes past the on-disk header read as empty lists. A batch out of offset order gets no clusters. The cluster list reuses the header's vector, and data-column scan states are initialized once per node group. A refill checks at most the next 4 bound lists, stops before the first that starts 256 or more rows past the lists before it, and otherwise fills the 2048-row window up to the batch's last list. It runs out of line from the loop that serves cached rows. With runtime checks the header buffer is poisoned on group entry and every header read asserts coverage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Freeze is targeted for Oct 19. main is still open. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This work was produced with the help of language models.
Follows up #1268.
Draft, opened early to coordinate with #1286 and #1291 on scan-state setup and per-execution allocations, not meant to merge before the freeze ends; it applies cleanly on top of #1286 with the same gains.
For bound nodes spread thinly over a node group the span from #1268 was still most of the CSR header: LDBC SNB SF1 q22 decoded 7.2M entries for 909 bound nodes, 43% of its instructions. Each neighbour-cache refill copied 2048 rows whether needed or not, 10% of q13.
Fix. A thinly spread batch decodes only clusters of the header entries its bound nodes need and records the ranges, so a later batch re-decodes only on a miss; a refill stops at a gap of 256 or more rows between lists. Clusters rely on
RelTable::initScanStatesorting bound nodes by offset, which #1286 keeps; data-column scan states are set up once per node group.Performance. LDBC SNB SF1, 1 thread, user instructions against main a7e923e, rows identical: the 30 benchmark queries 6,055M → 5,631M (−7.0%); engine-only IC12 −40%, IC7 −28%, IC4 −25%, IC8 −18%, the other measured IC queries within −2.6%…+0.2%; heavy whole-table queries −0.3%, filtered extends −1.4%, none outside −3.1%…+0.9%; malloc calls per execution +1 to +12.
Method
Both builds are wheel-like release builds of the Python module from the same worktree, on the prrao87/graph-benchmark-ldbc SF1 database. Each count is
perf stat -e instructions:uof a process running the query 4 times minus one running it once, divided by 3, at 1 thread; the rows of the last execution are compared between builds. Queries of 4–6M move ±5–13% between builds with no logic change; the largest increase is q29 3.9M → 4.4M. IC1, IC4, IC7–IC9 and IC11–IC14 are perf samples of the engine library, since the IC harness's polars part is too noisy for whole-process counts. Heavy queries are 1.2G–15G, filtered extends 10M–1.6G. Malloc calls are from anLD_PRELOADcounter over the whole process, driver included, so only the delta between builds is meaningful; the extra calls are the first growth of each new scan state's decoded-range vector. On top of #1286 (ad3f67a) the 30 queries go 5,804M → 5,379M (−7.3%) with the same per-query gains, heavy −0.3%, filtered extends −1.6%, allocations +1 to +14.Tests.
scan/csr_header_clusters.testcovers clustered and packed neighbour sets, node 0 and the last header node, an insert and a delete inside a cluster, bound nodes past the persistent header and a batch covered by an earlier one's clusters, across twoCHECKPOINTs. Performance-only, so it passes on main too; runtime checks fail it on reading an undecoded header entry, though it does not assert which decode path ran. Full suite withENABLE_RUNTIME_CHECKS: 3,101 tests pass; on top of #1286 only #1286's own two failures.