In a recent article I examined how using primitives and collections which support primitives natively instead of Wrappers and standard collections can reduce memory usage and improve performance.
Different way to have a Map of int/Integer
There are a number of ways you can use int/Integer and a number of collections you store them in. Depending on which approach you use can have a big difference on the performance and the amount of garbage produced.
Test
Performance Range
Memory used
Use Integer wrappers and HashMap
71 - 134 (ns)
53 MB/sec
Use int primitives and HashMap
45 - 76 (ns)
36 MB/sec
Use int primitives and FastMap
58 - 93 (ns)
28 MB/sec
Use int primitives and TIntIntHashMap
18 - 28 (ns)
nonimal
Use int primitives and simple hash map
6 - 9 (ns)
nonimal
The performance range was the typical (50%tile) and one of the higher (98%tile) timings. The garbage was the result of 900,000 loops per second.
Hi! I found your article very interesting. What do you mean by "Use int primitives and simple hash map", did you implemented your own Hash Map functions?
@akoskm, Yes, the simple HashMap implements just what is required for the test. Its code in in the "Directory of performance examples" link, or you can click SimpleHashMap
You still have to watch how many objects you create. This article looks at a benchmark passing events over TCP/IP at 4 billion events per minute using the net.openhft.chronicle.wire.channel package in Chronicle Wire and why we still avoid object allocations.. One of the key optimisations is creating almost no garbage. Allocation is a very cheap operation and collection of very short-lived objects is also very cheap. Does this really make a difference? What difference does one small object per event (44 bytes) make to the performance in a throughput test where GC pauses are amortised? While allocation is as efficient as possible, it doesn’t avoid the memory pressure on the L1/L2 caches of your CPUs and when many cores are busy, they are contending for memory in the shared L3 cache. Results Benchmark on a Ryzen 5950X with Ubuntu 22.10. JVM Vendor, Version No objects Throughput, Average Latency* One object per event Throughput, Average Latency* Azul Zulu 1.8.0_322 60.6 M event/s, 528
A Unique Identifier can be very useful for tracing. Those ids are even more useful when they contain a high-resolution timestamp. Not only do they record the time of an event, but if unique can help trace events as they pass through the system. Such unique timestamps however can be expensive depending on how they are implemented. This post explores a lightweight means of producing a unique, monotonically increasing system-wide nano-second resolution timestamp available in our open-source library. Uses for Unique Identifiers Unique identifiers can be useful to associate with a piece of information so that information can be referred to later unambiguously. This could be an event, a request, an order id, or a customer id. They can naturally be used as a primary key in a database or key/value store to retrieve that information later. One of the challenges of generating these identifiers is avoiding creating duplicates while not having an increasing cost. You could record every identi
I wrote an article on low latency microservices almost five years ago now. Chronicle Software has worked with a number of tier-one investment banks to implement and support those systems. What has changed in that time and what lessons have we learnt? Read this article and learn what we learned after five years of developing and supporting low latency microservices. Separation of Concerns Give Better Testability Microservices repeatedly demonstrated that testing and debugging business components were much easier with simple, stand-alone components with clear contracts between microservices. Unit tests were still used to start with. However, in 2017 we moved almost entirely to behavior-driven development of microservices. Unit tests are still used for lower-level libraries and utilities. As our microservices are all based on Kappa Architecture , all our behaviour driven tests are modeled as a series of events in and out of the service. An input test might look like this --- oms : O
Hi!
ReplyDeleteI found your article very interesting.
What do you mean by "Use int primitives and simple hash map", did you implemented your own Hash Map functions?
@akoskm, Yes, the simple HashMap implements just what is required for the test. Its code in in the "Directory of performance examples" link, or you can click SimpleHashMap
ReplyDelete