Bbtree: Fastest Ordered Map
Posted by aoli-al 4 days ago
Comments
Comment by nicknash 4 days ago
Also optimised stratified trees (van emde boas) implementations where key length permits.
Full comparison based structures are rarely necessary: ints, floats, strings, etc can be dealt with by lexicographic structures
Tries in particular work outrageously well on (unrealistic) uniform random data with log-logarithmic operation times
As a result, I’m skeptical of “fastest” here
B trees are great though, good work!
Comment by aidenn0 2 days ago
They do win in simplicity of implementation vs performace. A bog-standard critbit tree with no tricks is almost trivial to implement. Performace wise it stays in the running against anything not heavily optimized.
Comment by bollu 3 days ago
Comment by virtualritz 3 days ago
I tested this on a 3D boolean mesh kernel I am working on (this is swapping out std::BTreeMap, no other code changes):
┌────────────────────────────────────┬──────────────────────┐
│ bench 96..1536 faces │ change │
├────────────────────────────────────┼──────────────────────┤
│ union/difference, │ +11% to +21% slower │
├────────────────────────────────────┼──────────────────────┤
│ intersection stage, │ +16% to +34% slower │
└────────────────────────────────────┴──────────────────────┘
Then I thought, maybe this shines when you use big maps. I.e. more dense/complext meshes.So I used one of my test fixtures, a Nefretiti bust scan with a million vertex IDs:
┌──────────────────────────────────────┬───────┬────────┐
│ cage op (seconds, best of 3) │ std │ bbtree │
├──────────────────────────────────────┼───────┼────────┤
│ difference │ 84.2 │ 83.0 │
├──────────────────────────────────────┼───────┼────────┤
│ union │ 83.2 │ 85.6 │
├──────────────────────────────────────┼───────┼────────┤
│ intersection │ 61.3 │ 67.1 │
├──────────────────────────────────────┼───────┼────────┤
│ limit-surface difference (best of 2) │ 123.9 │ 147.2 │
└──────────────────────────────────────┴───────┴────────┘
I.e. a lot of the claims the post makes probably only hold under a specific and possibly narrow set of use cases the author tested agains.std::BTreeMap must hold ideally hold up well under any use case for such a map. That always means compromises must be made.
Comment by xiangpeng 3 days ago
Comment by virtualritz 3 days ago
I wasted more time on this, literally and figuratively.
InlinkeKey microbench results below.
Each row is one pass over n keys with three variants interleaved in one process:
┌──────────────────────┬────────┬────────┬─────────┐
│ n = 65536, │ std │ bbtree │ bbtree │
│ VertexId(u32) │ BTree- │ Auto │ Inline- │
│ │ Map │ │ Key │
├──────────────────────┼────────┼────────┼─────────┤
│ insert │ 18.3ms │ 12.3ms │ 20.8ms │
├──────────────────────┼────────┼────────┼─────────┤
│ get │ 14.0ms │ 9.2ms │ 16.6ms │
├──────────────────────┼────────┼────────┼─────────┤
│ iterate │ 0.74ms │ 0.05ms │ 0.10 ms │
├──────────────────────┼────────┼────────┼─────────┤
│ entry().or_default() │ 52ms │ 47ms │ 54 ms │
│ .push │ │ │ │
└──────────────────────┴────────┴────────┴─────────┘
The same pattern shows at 4k and 1M entries and for the (u32,u32) pair and a (u8,usize) tuple my crate uses. Adding InlineKey makes the narrow keys slower than bbtree without inline keys.It only beats the trait-less version on the 24-byte edge key. But there it still trails std!
Your post's proven (?) u64 impl is possibly the ceiling for this mechanism on my CPU (Rhyzen 6800H, 8 cores/16 threads). It is at parity with std at 4k to 65k on this CPU and about 10 percent ahead at 1M.
Iteration is where bbtree genuinely wins, 5-15x, but my kernel's time is not in iteration. And I guess that is true for most applications.
You eventually need to add and/or get/read data.
Comment by hugmynutus 4 days ago
Comment by xiangpeng 4 days ago
The inline key: yes, it applies to all kinds of integers and strings, and it exposes InlineKey traits that allow you to implement your own inline prefix.
The checklist items: I forget to cross them and they are all implemented, although I think the checklist item has nothing to do with bbtree. but this is definitely a flaw.
Comment by hugmynutus 4 days ago
I also appreciate your paper/work on bf-tree, I started a hobbyist filesystem based on it.
Comment by ytxm 4 days ago
For a map<String, usize> of /usr/share/dict/words (with the value being the dict offset), measuring this consistently using 40% more RAM than std::collections::BtreeMap. Their claim of less memory usage was specifically for integers, so this is more a data point than a refutation.
Comment by jared_hulbert 4 days ago
Comment by throwaway81523 3 days ago
Comment by elendilm 4 days ago
We have smart batching in Dip where we deduplicate work received in what we call a "batched" request. We use BTreeMap to deduplicate work in the preprocessing "scatter" phase.
This deduplication in smart batching is the slowest phase on most bulk write workloads (200k+ inserts in a single request) and takes sometimes up to 3x the time taken for the combined fanout + db writes + db commits + gather.
Will try out with Bbtree and see how it goes.
Comment by tyilo 4 days ago
Bold claim...
Comment by ashkankiani 4 days ago
I can almost guarantee that someone has built a custom btree for their specific domain which is faster than this; and that they probably have some or all of the techniques used in this library that are the main contributors to performance, as well. Prefetching is probably the main one they'll claim, and I know personally of some proprietary implementations which have it.
I would like to see some more humility, but I suppose that when you've already resigned your own potential to being below an LLM, then what's the point.
It's not possible or useful for them to grow anymore. Some new frontier model next week will outdo whatever ephemerally useful project this person writes, right? That's the logic?
Comment by 0c3ca83 4 days ago
This is only a statement that could be written by someone that doesn't read the code.
Comment by marci 3 days ago
* https://docs.rs/sanakirja-core
* https://pijul.org/posts/2021-02-06-rethinking-sanakirja#benc...
Comment by eumon 4 days ago
Comment by geraneum 4 days ago
What does model checking mean here?
Comment by aw1621107 4 days ago
Comment by geraneum 4 days ago
Comment by rurban 4 days ago
Comment by aw1621107 4 days ago
Incidentally, the docs don't seem to say what model checker was used. I don't think any of verus, shuffle, or ffs are technically model checkers (or at the very least they don't describe themselves as such)
Comment by ozgrakkurt 4 days ago
The quote at the top isn't related to what any of this is so it is pretty funny while being obnoxious
Comment by MiroslavPokorny 3 days ago
Comment by toccter 4 days ago
Comment by eumon 4 days ago
Comment by jackbeanstalk20 4 days ago