Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  1. empty map makes Java implementation the smallest
  2. with 8 elements have maps similar size
  3. from 256 elements the max saving for NonBlickingHashMapLong and Long2ObjectMap is achieved

Performance

Martin Thompson's style of PerfTest

2 consumers, 2 producers. Producers putting with key value pair that is their id and random object. Consumers removing with key that is their id. Basically a bunch of <1,O> or <2, O> putting and removing with <1> or <2>.

Code Block
titlePerformance
Java
_______________________
0 - 2 producers 2 consumers: 4,782,614 ops/sec - MapsPerfTest
1 - 2 producers 2 consumers: 4,194,545 ops/sec - MapsPerfTest
2 - 2 producers 2 consumers: 4,726,670 ops/sec - MapsPerfTest
3 - 2 producers 2 consumers: 5,339,190 ops/sec - MapsPerfTest
4 - 2 producers 2 consumers: 4,952,414 ops/sec - MapsPerfTest

Cliff's
______________________
0 - 2 producers 2 consumers: 23,030,573 ops/sec - MapsPerfTest
1 - 2 producers 2 consumers: 31,244,208 ops/sec - MapsPerfTest
2 - 2 producers 2 consumers: 30,630,539 ops/sec - MapsPerfTest
3 - 2 producers 2 consumers: 28,825,699 ops/sec - MapsPerfTest
4 - 2 producers 2 consumers: 26,588,300 ops/sec - MapsPerfTest

Long2ObjectMap (FastUtil)
______________________
0 - 2 producers 2 consumers: 5,569,578 ops/sec - MapsPerfTest
1 - 2 producers 2 consumers: 5,940,526 ops/sec - MapsPerfTest
2 - 2 producers 2 consumers: 5,883,532 ops/sec - MapsPerfTest
3 - 2 producers 2 consumers: 5,798,396 ops/sec - MapsPerfTest
4 - 2 producers 2 consumers: 5,537,185 ops/sec - MapsPerfTest
Using JMH Approach 1

2 consumers, 2 producers. Map is initially empty. Producers execute put with random long 0-10. Consumer are removing with random long 0-10.

Code Block
     [java] Benchmark                                                           Mode  Samples      Score      Error   Units
     [java] i.n.i.ThreadSafeMapsPerfTest.concurrentHashMap                     thrpt        5  17205.845 ± 1549.392  ops/ms
     [java] i.n.i.ThreadSafeMapsPerfTest.concurrentHashMap:putChm              thrpt        5   8031.802 ±  627.409  ops/ms
     [java] i.n.i.ThreadSafeMapsPerfTest.concurrentHashMap:removeChm           thrpt        5   9174.043 ±  938.380  ops/ms
     [java] i.n.i.ThreadSafeMapsPerfTest.nonBlockingHashMapLong                thrpt        5  22120.230 ± 1674.090  ops/ms
     [java] i.n.i.ThreadSafeMapsPerfTest.nonBlockingHashMapLong:putNbhml       thrpt        5  10369.226 ±  505.723  ops/ms
     [java] i.n.i.ThreadSafeMapsPerfTest.nonBlockingHashMapLong:removeNbhml    thrpt        5  11751.004 ± 1391.759  ops/ms
Using JMH Approach 2

3 threads.. Map is filled with 1000 elements. Each tread removes the element with random 0-1000 remove and then puts back the removed element to the map right away with same key.

Code Block
     [java] Benchmark                                               Mode  Samples      Score     Error   Units
     [java] i.n.i.ThreadSafeMapsPerfTest.concurrentHashMap         thrpt        5  16033.299 ± 642.117  ops/ms
     [java] i.n.i.ThreadSafeMapsPerfTest.nonBlockingHashMapLong    thrpt        5  27084.222 ± 323.981  ops/ms

Saving With NonBlockingHashMapLong

Taking the map sizes reported by the indexing structure, we can easily check what is the expected size of indexing structure if the map would be changed to NonBlockingHashMapLong:

Map #Number of elementsApp. CocnurrentHashMap sizeApp. NonBlockingHashMapSize
1172451,380,273478,677
230077824,073,9898,348,829
34554364,497126,407
4329652,638,487915,024
564451,72118,348
610604848,734294,339
759848,02617,038
810604848,734294,339

Total

37799230,254,46110,493,001

As seen with change to high scale lib we would gain the storage optimization of almost 20MB (for given example), or decrease of 67%.

Further options to optimize indexing tree size

Simplest option would be to decrease the number of elements indexed. We can re-think on our use-cases and real need to index every single element that is in the buffer (timers and SQLs we often need in aggregated mode only).

The other option to optimize the indexing tree size would be to go away from the maps and implement different structure.

The additional option would be not to map the element ID with the element it self (that's what we store in maps). Because the element ID is only needed for direct element retrieval and  this use case we have only for invocation sequences. Thus for everything else we could spare that space by holding the elements in the array list for example.