Arena Map Benchmark: ChaosTree vs JDK, Fastutil, Eclipse

One repeatable mixed workload of get, put and remove on sorted maps, at 10K, 100K and 1M entries. Score is time per operation (ns/op), single-threaded. Lower is better.

Violet marks the winner. Error (JMH 99.9% confidence interval) is drawn at lower opacity than the data.

1. What this benchmark measures

The map is filled once with size keys, inserted by plain put in shuffled order (seed 42). Then every invocation runs 100,000 operations read from a pre-generated pool of 2M packed (op, key) entries. Keys are uniform over 0 … 2×size-1. The cursor advances between invocations, so the map evolves and no rebuild happens between them. Keys and values are pre-boxed Integers, so the timed loop does no RNG work and allocates nothing. Results go to a Blackhole. The op stream is identical for every map at a given seed and mix.

A mix such as 50,25,25 means 50% get, 25% put, 25% remove. Mixes with equal put and remove (50,25,25, 20,40,40, 80,10,10) hold the tree near half full. Mixes with 0% remove saturate the tree, so they measure lookup and overwrite on a full tree.

2. System and reproduction

CPU Intel Core i5-13450HX
Heap Pinned: -Xms4g -Xmx4g -XX:+AlwaysPreTouch
GC -XX:+UseParallelGC, the same for every map
JMH settings 3 forks, 10 warmup x 1s, 10 measurement x 1s (30 samples per row). @OperationsPerInvocation(100000), so scores are ns/op.
Mixes [50,25,25] [20,40,40] [80,10,10] [70,30,0] [50,50,0] [30,70,0]
Maps ChaosBPlusTree and ChaosBTree (degree 64), ChaosAVL, ChaosRBT, JDK TreeMap, JDK ConcurrentSkipListMap (single-thread reference only), Fastutil AVL/RBT (Object2Object), Eclipse TreeSortedMap, and Fastutil Int2IntAVLTreeMap / Int2IntRBTreeMap (class ArenaPrimitive, primitive int keys, no boxing)
I did ArenaObject in multiple files (10k,100K,1M) as the ETA: 3hr
java -jar ct-benchmark/target/benchmarks.jar ArenaObject \
  -p size=10000,100000,1000000 -f 3 -wi 10 -w 1s -i 10 -r 1s \
  -jvmArgsAppend "-Xms4g -Xmx4g -XX:+AlwaysPreTouch -XX:+UseParallelGC"
java -jar ct-benchmark/target/benchmarks.jar ArenaPrimitive \
  -p size=10000,100000,1000000 -f 3 -wi 10 -w 1s -i 10 -r 1s \
  -jvmArgsAppend "-Xms4g -Xmx4g -XX:+AlwaysPreTouch -XX:+UseParallelGC"

3. Results

Time per operation by mix, 100K entries (ns/op)

get 50% put 25% remove 25% 0 200 400 600 ChaosBTree 207.7 ±1.6 ChaosBPlusTree 211.3 ±0.6 FastutilAVLIntNative 284.1 ±2.7 FastutilRBTIntNative 292.8 ±3.4 JDKTreeMap 344.8 ±2.3 EclipseRBT 355.6 ±17.0 ChaosRBT 382.7 ±26.0 FastutilRBTObj 383.3 ±3.6 FastutilAVLObj 388.0 ±14.5 ChaosAVL 397.9 ±5.4 JDKConcurrentSkipListMap 625.6 ±17.9
get 20% put 40% remove 40% 0 200 400 600 ChaosBPlusTree 217.1 ±0.9 ChaosBTree 217.9 ±1.6 FastutilAVLIntNative 299.2 ±4.4 FastutilRBTIntNative 305.3 ±2.6 EclipseRBT 400.4 ±23.2 JDKTreeMap 401.3 ±26.9 FastutilRBTObj 402.7 ±3.9 FastutilAVLObj 409.9 ±14.4 ChaosRBT 412.5 ±21.1 ChaosAVL 434.3 ±9.1 JDKConcurrentSkipListMap 651.8 ±7.7
get 80% put 10% remove 10% 0 200 400 600 ChaosBTree 200.8 ±2.2 ChaosBPlusTree 202.9 ±2.5 FastutilRBTIntNative 236.4 ±1.5 FastutilAVLIntNative 238.0 ±1.9 JDKTreeMap 298.4 ±3.0 ChaosRBT 324.0 ±3.9 FastutilAVLObj 334.0 ±1.4 EclipseRBT 336.3 ±41.2 ChaosAVL 337.5 ±2.3 FastutilRBTObj 346.0 ±13.9 JDKConcurrentSkipListMap 563.4 ±7.0
get 70% put 30% remove 0% 0 200 400 600 FastutilRBTIntNative 208.2 ±2.1 FastutilAVLIntNative 212.3 ±5.0 ChaosBTree 215.2 ±3.8 ChaosBPlusTree 221.9 ±5.6 FastutilRBTObj 301.5 ±1.4 FastutilAVLObj 308.3 ±3.0 JDKTreeMap 314.2 ±2.5 ChaosAVL 316.9 ±3.0 ChaosRBT 329.7 ±3.9 EclipseRBT 357.1 ±24.7 JDKConcurrentSkipListMap 543.0 ±2.6
get 50% put 50% remove 0% 0 200 400 600 ChaosBPlusTree 210.8 ±3.1 FastutilRBTIntNative 215.6 ±3.6 ChaosBTree 216.6 ±3.1 FastutilAVLIntNative 220.5 ±1.9 FastutilRBTObj 310.7 ±1.6 ChaosAVL 311.5 ±5.6 JDKTreeMap 320.9 ±2.3 FastutilAVLObj 322.2 ±4.7 ChaosRBT 334.6 ±13.4 EclipseRBT 403.8 ±40.2 JDKConcurrentSkipListMap 551.0 ±4.6
get 30% put 70% remove 0% 0 200 400 600 ChaosBPlusTree 215.0 ±4.2 FastutilRBTIntNative 223.9 ±4.0 ChaosBTree 225.0 ±10.2 FastutilAVLIntNative 226.2 ±1.8 ChaosAVL 315.0 ±18.9 FastutilRBTObj 319.3 ±2.6 JDKTreeMap 322.2 ±3.2 ChaosRBT 326.9 ±2.6 FastutilAVLObj 329.4 ±2.4 EclipseRBT 337.6 ±10.2 JDKConcurrentSkipListMap 565.5 ±9.4

Time table, 100K (ns/op)

Map 50,25,25 20,40,40 80,10,10 70,30,0 50,50,0 30,70,0 Mean
ChaosBPlusTree 211.3 ±0.6 217.1 ±0.9 202.9 ±2.5 221.9 ±5.6 210.8 ±3.1 215.0 ±4.2 213.2 ±1.4
ChaosBTree 207.7 ±1.6 217.9 ±1.6 200.8 ±2.2 215.2 ±3.8 216.6 ±3.1 225.0 ±10.2 213.8 ±2.0
FastutilAVLIntNative 284.1 ±2.7 299.2 ±4.4 238.0 ±1.9 212.3 ±5.0 220.5 ±1.9 226.2 ±1.8 246.7 ±1.3
FastutilRBTIntNative 292.8 ±3.4 305.3 ±2.6 236.4 ±1.5 208.2 ±2.1 215.6 ±3.6 223.9 ±4.0 247.0 ±1.2
JDKTreeMap 344.8 ±2.3 401.3 ±26.9 298.4 ±3.0 314.2 ±2.5 320.9 ±2.3 322.2 ±3.2 333.6 ±4.6
FastutilRBTObj 383.3 ±3.6 402.7 ±3.9 346.0 ±13.9 301.5 ±1.4 310.7 ±1.6 319.3 ±2.6 343.9 ±2.5
FastutilAVLObj 388.0 ±14.5 409.9 ±14.4 334.0 ±1.4 308.3 ±3.0 322.2 ±4.7 329.4 ±2.4 348.6 ±3.6
ChaosRBT 382.7 ±26.0 412.5 ±21.1 324.0 ±3.9 329.7 ±3.9 334.6 ±13.4 326.9 ±2.6 351.7 ±6.1
ChaosAVL 397.9 ±5.4 434.3 ±9.1 337.5 ±2.3 316.9 ±3.0 311.5 ±5.6 315.0 ±18.9 352.2 ±3.8
EclipseRBT 355.6 ±17.0 400.4 ±23.2 336.3 ±41.2 357.1 ±24.7 403.8 ±40.2 337.6 ±10.2 365.1 ±11.6
JDKConcurrentSkipListMap 625.6 ±17.9 651.8 ±7.7 563.4 ±7.0 543.0 ±2.6 551.0 ±4.6 565.5 ±9.4 583.4 ±3.9

Score ± JMH error. Rows sorted by mean over the six mixes.

4. How to read this page

Violet bar / violet bold cell Lowest mean in that column. The winner.
Outlined bar / violet cell Its error interval overlaps the winner's. Treat as a statistical tie.
Black bar Slower than the winner beyond the error.
Pale whisker / pale ±value JMH error, at lower opacity than the data.

5. Caveats

6. Findings:

← Back to ChaosTree