akoutmos
I tweeted this morning about some BEAM internals (Alex Koutmos on X: "🔥 Quick Erlang/Elixir tip 🔥 Under the hood, a map in the BEAM is an HAMT (Hash array mapped trie). If the size of your map is greater than 32 entries, it is O(log n) search time erl_map.h-https://t.co/LTulCHACFK erl_map.c-https://t.co/Lx8ok2DJit #myelixirstatus #elixirlang" / X). Specifically about how maps are represented internally as hash array mapped tries (or HAMT for short) when the size of the map is greater than 32 entries.
@StanBright had a good idea to run some benchmarks against small maps (32 entries) and large maps (greater than 32 keys). I threw together a quick benchee script (found here Elixir Benchmark of big versus small maps (inspired by https://twitter.com/akoutmos/status/1266034402422853633) · GitHub) to give it a go.
Here are the results:
Name ips average deviation median 99th %
Small Map - first item 41.25 M 24.24 ns ±2890.98% 22 ns 66 ns
Large Map - invalid item 31.10 M 32.15 ns ±841.48% 30 ns 83 ns
Large Map - first item 23.43 M 42.67 ns ±217.74% 40 ns 113 ns
Large Map - middle item 23.06 M 43.36 ns ±218.75% 40 ns 118 ns
Large Map - last item 19.82 M 50.45 ns ±355.66% 48 ns 121 ns
Small Map - middle item 12.21 M 81.93 ns ±376.39% 78 ns 198 ns
Small Map - invalid item 5.96 M 167.82 ns ±203.11% 162 ns 342 ns
Small Map - last item 4.50 M 222.17 ns ±355.61% 214 ns 459 ns
Comparison:
Small Map - first item 41.25 M
Large Map - invalid item 31.10 M - 1.33x slower +7.91 ns
Large Map - first item 23.43 M - 1.76x slower +18.43 ns
Large Map - middle item 23.06 M - 1.79x slower +19.12 ns
Large Map - last item 19.82 M - 2.08x slower +26.21 ns
Small Map - middle item 12.21 M - 3.38x slower +57.69 ns
Small Map - invalid item 5.96 M - 6.92x slower +143.58 ns
Small Map - last item 4.50 M - 9.17x slower +197.93 ns
Memory usage statistics:
Name Memory usage
Small Map - first item 0 B
Large Map - invalid item 0 B - 1.00x memory usage +0 B
Large Map - first item 0 B - 1.00x memory usage +0 B
Large Map - middle item 0 B - 1.00x memory usage +0 B
Large Map - last item 0 B - 1.00x memory usage +0 B
Small Map - middle item 0 B - 1.00x memory usage +0 B
Small Map - invalid item 0 B - 1.00x memory usage +0 B
Small Map - last item 0 B - 1.00x memory usage +0 B
Just something I figured I would share for those who are interested ![]()
Trending in Discussions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










First 6 of 6 Posts
StanBright
Hey @akoutmos, thanks for taking the time to do this. So it is actually true - it is faster to work with bigger maps compared to small ones… who would expect that
Nicd
You should also try with a “typical” map (which varies based on application), but something like 5–10 keys. Most of my maps would fall somewhere in that range.
garazdawi
The performance of small maps changes a lot depending on how complex the key term is, while large maps depend less on the complexity of the key.
For instance I would imagine you get different results if the keys were small integers.
akoutmos
Thanks for the input, that’s a great test to run! I’ll create an additional set of synthetic benchmarks using atoms and integers (for completeness although I would suspect atoms and integers to perform roughly the same since atoms are represented internally as integers ?).
Like most synthetic benchmarks this was more of a mental exercise to show the cut over between the two representations of maps otp/erts/emulator/beam/erl_map.h at master · erlang/otp · GitHub. For real world accuracy, smaller maps (5-10 keys) would have been more realistic…but without recompiling Erlang locally with those C macros changed I don’t see a way of doing it. There aren’t any run-time flags to control that right? Perhaps that will be my next mental exercise test haha.
Ninigi
What I would be interested in is the writing speed, everything I know about Elixir by now says writing/reading from maps is really fast, but does map size have an impact on writing, and stuff like update_in\3?
Thanks for doing this.
akoutmos
I was able to sneak in a little bit of benchmarking time during my lunch break and have updated the gist Elixir Benchmark of big versus small maps (inspired by https://twitter.com/akoutmos/status/1266034402422853633) · GitHub to have maps with integers and atoms as keys. Super interesting to see how the results kinda flipped when using atoms/integers as keys Below are the results: