71 lines
4.6 KiB
Markdown
71 lines
4.6 KiB
Markdown
A data structure for optimistic concurrency control on ranges of bitwise-lexicographically-ordered keys.
|
|
|
|
Intended as an alternative to FoundationDB's skip list.
|
|
|
|
Hardware for all benchmarks is an AMD Ryzen 9 7900 with (2x32GB) 5600MT/s CL28-34-34-89 1.35V RAM.
|
|
|
|
```
|
|
$ clang++ --version
|
|
|
|
Ubuntu clang version 20.0.0 (++20241119082716+7e85cb8a8a9d-1~exp1~20241119082825.551)
|
|
Target: x86_64-pc-linux-gnu
|
|
Thread model: posix
|
|
InstalledDir: /usr/lib/llvm-20/bin
|
|
```
|
|
|
|
# Microbenchmark
|
|
|
|
## Skip list
|
|
|
|
| ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark
|
|
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|
|
| 175.88 | 5,685,575.81 | 0.0% | 3,014.03 | 883.13 | 3.413 | 504.59 | 0.0% | 2.10 | `point reads`
|
|
| 173.35 | 5,768,718.52 | 0.0% | 2,954.16 | 869.59 | 3.397 | 490.17 | 0.0% | 2.07 | `prefix reads`
|
|
| 251.74 | 3,972,274.68 | 0.1% | 3,592.41 | 1,265.71 | 2.838 | 629.31 | 0.0% | 3.01 | `range reads`
|
|
| 472.13 | 2,118,079.83 | 0.2% | 4,450.57 | 2,377.84 | 1.872 | 707.92 | 2.3% | 5.60 | `point writes`
|
|
| 471.34 | 2,121,609.91 | 0.0% | 4,410.22 | 2,372.55 | 1.859 | 694.74 | 2.3% | 5.61 | `prefix writes`
|
|
| 306.69 | 3,260,650.68 | 0.0% | 2,315.38 | 1,550.33 | 1.493 | 396.69 | 3.3% | 3.68 | `range writes`
|
|
| 502.70 | 1,989,277.15 | 0.9% | 6,999.33 | 2,527.47 | 2.769 | 1,251.74 | 1.3% | 0.06 | `monotonic increasing point writes`
|
|
| 138,097.67 | 7,241.25 | 0.7% | 807,445.67 | 699,899.00 | 1.154 | 144,584.50 | 0.8% | 0.01 | `worst case for radix tree`
|
|
| 46.29 | 21,605,126.00 | 1.0% | 902.00 | 230.73 | 3.909 | 132.00 | 0.0% | 0.01 | `create and destroy`
|
|
|
|
## Radix tree (this implementation)
|
|
|
|
|
|
| ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark
|
|
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|
|
| 14.04 | 71,216,855.01 | 0.1% | 245.98 | 70.38 | 3.495 | 31.49 | 0.6% | 0.17 | `point reads`
|
|
| 14.57 | 68,630,592.89 | 0.1% | 297.83 | 72.93 | 4.084 | 40.34 | 0.5% | 0.17 | `prefix reads`
|
|
| 35.28 | 28,347,588.39 | 0.2% | 783.70 | 176.57 | 4.438 | 107.65 | 0.2% | 0.42 | `range reads`
|
|
| 20.64 | 48,453,280.08 | 0.0% | 378.97 | 103.31 | 3.668 | 49.92 | 0.7% | 0.25 | `point writes`
|
|
| 39.14 | 25,551,096.17 | 0.0% | 672.00 | 196.08 | 3.427 | 101.28 | 0.3% | 0.47 | `prefix writes`
|
|
| 39.88 | 25,075,121.85 | 0.0% | 738.26 | 199.71 | 3.697 | 111.59 | 0.1% | 0.49 | `range writes`
|
|
| 79.36 | 12,601,312.65 | 0.5% | 1,447.65 | 398.77 | 3.630 | 275.61 | 0.1% | 0.01 | `monotonic increasing point writes`
|
|
| 307,037.33 | 3,256.93 | 0.3% | 4,043,060.50 | 1,549,199.33 | 2.610 | 714,828.00 | 0.1% | 0.01 | `worst case for radix tree`
|
|
| 97.00 | 10,309,246.47 | 0.2% | 1,986.00 | 487.06 | 4.078 | 315.00 | 0.0% | 0.01 | `create and destroy`
|
|
|
|
# "Real data" test
|
|
|
|
Point queries only. Gc ratio is the ratio of time spent doing garbage collection to time spent adding writes or doing garbage collection. Lower is better.
|
|
|
|
## skip list
|
|
|
|
```
|
|
Check: 4.66163 seconds, 361.716 MB/s, Add: 3.97534 seconds, 144.726 MB/s, Gc ratio: 33.3998%, Peak idle memory: 5.61007e+06
|
|
```
|
|
|
|
## radix tree
|
|
|
|
```
|
|
Check: 1.01776 seconds, 1656.77 MB/s, Add: 1.2718 seconds, 452.38 MB/s, Gc ratio: 38.626%, Peak idle memory: 2.05667e+06
|
|
```
|
|
|
|
## hash table
|
|
|
|
(The hash table implementation doesn't work on range queries, and its purpose is to provide an idea of how fast point queries can be)
|
|
|
|
```
|
|
Check: 0.859188 seconds, 1962.54 MB/s, Add: 0.714174 seconds, 805.596 MB/s, Gc ratio: 34.9552%, Peak idle memory: 0
|
|
```
|
|
|