Skip to content

test(b+tree): make the absl::btree_set comparison buildable, and widen it - #161

Open
psiha wants to merge 1 commit into
bt/7-devector-nodesfrom
bt/8-absl-bench
Open

test(b+tree): make the absl::btree_set comparison buildable, and widen it#161
psiha wants to merge 1 commit into
bt/7-devector-nodesfrom
bt/8-absl-bench

Conversation

@psiha

@psiha psiha commented Sep 9, 2026

Copy link
Copy Markdown
Owner

The benchmark already had an absl::btree_set arm behind #define HAVE_ABSL 0, with no way to turn it on. -DPSI_VM_BENCH_ABSL=ON now fetches abseil through CPM and defines it. absl::btree_set is the closest shipping container to this one — it also redistributes into a sibling before splitting — so it is the right thing to be measured against.

It also measures more than it did: sorted bulk insertion is every container's best case and is not the state a long-lived index is in, so there is now a one-by-one random insertion arm and a footprint column for both containers (nodes_reserved() here; a counting allocator for absl, which exposes bytes_used() only on the internal btree).

What it says

7.65M int, one box, Release + LTO. abseil's default node is 256 bytes (/*TargetNodeSize=*/256), so the 4096 column is a 16× geometry mismatch and the 512 column a 2× one.

psi::vm 512B absl 256B psi::vm 4096B absl 256B
sorted bulk insert 4 ns 7 ns 1.75× faster 4 ns 7 ns 1.75× faster
lookup after bulk 208 176 1.18× slower 284 188 1.51× slower
random one-by-one insert 163 161 parity 329 181 1.82× slower
lookup after random 202 206 parity 354 217 1.63× slower
bytes/key, bulk 4.30 4.33 4.04 4.33
bytes/key, random 4.91 5.07 4.49 5.07

At the default 512-byte geometry this container holds its own: parity on random insert and random lookup, 1.75× faster on sorted bulk insert, slightly smaller. The one loss is lookup on a freshly bulk-built — fully packed — tree.

At PSI_VM_BT_PAGE_SIZED_NODES it does not: 1.5–1.8× slower on lookups and one-by-one inserts, and 2× slower than itself at 512 bytes on random insertion. The likely mechanism is cache lines touched per node: 256 B is 4 lines and 512 B is 8, against 64 for a 4096-byte node — fewer tree levels, far more lines per descent.

⚠ Caveat worth stating rather than burying: with int/std::less, 512 bytes falls under linear_search_byte_limit and 4096 does not, so the two columns differ in node size and in intra-node search. Each is the right choice for its own geometry, so this is a fair end-to-end configuration comparison — but it is not an isolated node-size measurement.

Build note

psi.build's MSVC toolchain appends __GNUC__ to the global compile definitions (clang-cl does support the GNU-style extensions), and abseil reads that as "GNU platform" and builds its libsupc++ demangler, which wants cxxabi.h. The definition is dropped for abseil's subtree only, by filtering the directory property before CPMAddPackage — a subdirectory inherits it as it stands at the add_subdirectory() call.

Stacked on #159.

…n it

The benchmark already had an absl arm behind `#define HAVE_ABSL 0`, with no
way to turn it on.  `-DPSI_VM_BENCH_ABSL=ON` now fetches abseil through CPM
and defines it.  absl::btree_set is the closest shipping container to this one
- it also redistributes into a sibling before splitting - so it is the right
thing to be measured against.

One build detail worth recording: psi.build's MSVC toolchain defines __GNUC__
globally (clang-cl does support the GNU-style extensions), and abseil reads
that as "GNU platform" and tries to build its libsupc++ demangler, which wants
cxxabi.h.  The definition is dropped for abseil's subtree only, by filtering
the directory property before CPMAddPackage - a subdirectory inherits it as it
stands at the add_subdirectory() call.

The benchmark itself measured only sorted bulk insertion, which is every
container's best case and is not the state a long-lived index is in.  It now
also measures one-by-one insertion in random order, and the footprint of both
containers afterwards: psi::vm's from nodes_reserved(), absl's through a
counting allocator, since absl exposes bytes_used() only on the internal
btree.  Footprint is what the occupancy work is about, so it belongs here.
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