Created
May 21, 2023 19:22
-
-
Save jchristgit/a002d1a4c724e62c72386692396417b3 to your computer and use it in GitHub Desktop.
Benchmarking of Erlang's QLC module in various ways
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tab = :ets.new(:test, [:set, :public]) | |
:ets.insert(tab, Enum.map(1..10_000, &{&1, %{id: &1, name: "#{&1}"}})) | |
qh = :ets.table(tab) | |
ms = [{{:"$1", :"$2"}, [], [{{:"$1", :"$1", :"$2"}}]}] | |
qhtraverse = :ets.table(tab, traverse: {:select, ms}) | |
# Elixir queries | |
qh0 = :qlc.string_to_handle('[{Id, Id, Value} || {Id, Value} <- Handle, Id =:= RequestedId].', [], Handle: qh, RequestedId: 500_000) | |
qh1a = :qlc.string_to_handle('[{Id, Id, Value} || {Id, Value} <- Handle].', [], Handle: qh, RequestedId: 500_000) | |
qh1b = :qlc.string_to_handle('[Value || {Id, _, Value} <- Handle, Id =:= RequestedId].', [], Handle: qh1a, RequestedId: 500_000) | |
qh2a = :qlc.string_to_handle('[{Id, Id, Value} || {Id, Value} <- Handle, Id =:= RequestedId].', [], Handle: qhtraverse, RequestedId: 500_000) | |
# Erlang queries | |
nqh0 = :qlctest.qh0(qh, 500_000) | |
nqh1b = :qlctest.qh1b(qh, 500_000) | |
nqh2a = :qlctest.qh2a(qhtraverse, 500_000) | |
# Print query information. | |
# These _should_ be the same between Elixir and Erlang. | |
# IO.puts("===== NAIVE (Elixir) =====") | |
# IO.puts(:qlc.info(qh0)) | |
# IO.puts("===== NAIVE (Erlang) =====") | |
# IO.puts(:qlc.info(nqh0)) | |
# IO.puts("===== NESTED (Elixir) =====") | |
# IO.puts(:qlc.info(qh1b)) | |
# IO.puts("===== NESTED (Erlang) =====") | |
# IO.puts(:qlc.info(nqh1b)) | |
# IO.puts("===== NAIVE, TRAVERSED (Elixir) =====") | |
# IO.puts(:qlc.info(qh2a)) | |
# IO.puts("===== NAIVE, TRAVERSED (Erlang) =====") | |
# IO.puts(:qlc.info(nqh2a)) | |
counter = fn _item, acc -> acc + 1 end | |
Benchee.run( | |
%{ | |
# Queries coming from `string_to_handle` in Elixir. | |
"naive" => fn -> :qlc.e(qh0) end, | |
"nested" => fn -> :qlc.e(qh1b) end, | |
"naive, traversed" => fn -> :qlc.e(qh2a) end, | |
"naive, fold" => fn -> :qlc.fold(counter, 0, qh0) end, | |
"nested, fold" => fn -> :qlc.fold(counter, 0, qh1b) end, | |
"naive, traversed, fold" => fn -> :qlc.fold(counter, 0, qh2a) end, | |
# No effect. | |
# "naive, fold, uncached" => fn -> :qlc.fold(counter, 0, qh0, cache_all: false) end, | |
# "nested, fold, uncached" => fn -> :qlc.fold(counter, 0, qh1b, cache_all: false) end, | |
# "naive, traversed, fold, uncached" => fn -> :qlc.fold(counter, 0, qh2a, cache_all: false) end, | |
# A lot slower. | |
# "naive, cursor" => fn -> cursor_counter.(qh0) |> Enum.sum() end, | |
# "nested, cursor" => fn -> cursor_counter.(qh1b) |> Enum.sum() end, | |
# "naive, traversed, cursor" => fn -> cursor_counter.(qh2a) |> Enum.sum() end, | |
# Queries coming from the parse transform in Erlang. | |
"native, naive" => fn -> :qlc.e(nqh0) end, | |
"native, nested" => fn -> :qlc.e(nqh1b) end, | |
"native, naive, traversed" => fn -> :qlc.e(nqh2a) end, | |
"native, naive, fold" => fn -> :qlc.fold(counter, 0, nqh0) end, | |
"native, nested, fold" => fn -> :qlc.fold(counter, 0, nqh1b) end, | |
"native, naive, traversed, fold" => fn -> :qlc.fold(counter, 0, nqh2a) end, | |
# No effect. | |
# "native, naive, fold, uncached" => fn -> :qlc.fold(counter, 0, nqh0, cache_all: false) end, | |
# "native, nested, fold, uncached" => fn -> :qlc.fold(counter, 0, nqh1b, cache_all: false) end, | |
# "native, naive, traversed, fold, uncached" => fn -> :qlc.fold(counter, 0, nqh2a, cache_all: false) end, | |
# A lot slower. | |
# "native, naive, cursor" => fn -> cursor_counter.(nqh0) |> Enum.sum() end, | |
# "native, nested, cursor" => fn -> cursor_counter.(nqh1b) |> Enum.sum() end, | |
# "native, naive, traversed, cursor" => fn -> cursor_counter.(nqh2a) |> Enum.sum() end | |
}, | |
memory_time: 2, | |
time: 2 | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(qlctest). | |
-export([qh0/2, qh1b/2, qh2a/2]). | |
-include_lib("stdlib/include/qlc.hrl"). | |
% Direct lookup on the handle, with a slight rewrite | |
qh0(Tab, RequestedId) -> | |
qlc:q([{Id, Id, Value} || {Id, Value} <- Tab, Id =:= RequestedId]). | |
% Nested lookup via a second QLC that rewrites results | |
qh1b(Tab, RequestedId) -> | |
V1 = qlc:q([{Id, Id, Value} || {Id, Value} <- Tab]), | |
qlc:q([Value || {Id, _, Value} <- V1, Id =:= RequestedId]). | |
% Lookup on table rewritten via traverse function | |
qh2a(Tab, RequestedId) -> | |
qlc:q([{Id, Id, Value} || {Id, _, Value} <- Tab, Id =:= RequestedId]). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Name ips average deviation median 99th % | |
native, naive 388190.23 0.00258 ms ±679.57% 0.00188 ms 0.00939 ms | |
native, naive, fold 378867.15 0.00264 ms ±595.45% 0.00193 ms 0.00732 ms | |
naive 25145.54 0.0398 ms ±20.92% 0.0373 ms 0.0626 ms | |
naive, fold 25084.02 0.0399 ms ±24.82% 0.0373 ms 0.0629 ms | |
native, nested 23.21 43.09 ms ±10.36% 41.71 ms 65.80 ms | |
native, naive, traversed 23.06 43.36 ms ±9.46% 42.61 ms 59.01 ms | |
native, naive, traversed, fold 22.97 43.53 ms ±7.96% 42.83 ms 53.73 ms | |
native, nested, fold 21.53 46.45 ms ±15.48% 43.10 ms 68.19 ms | |
naive, traversed 1.55 644.14 ms ±2.32% 639.93 ms 665.63 ms | |
naive, traversed, fold 1.46 684.60 ms ±3.41% 676.03 ms 711.02 ms | |
nested, fold 0.37 2693.06 ms ±0.00% 2693.06 ms 2693.06 ms | |
nested 0.36 2776.43 ms ±0.00% 2776.43 ms 2776.43 ms | |
Comparison: | |
native, naive 388190.23 | |
native, naive, fold 378867.15 - 1.02x slower +0.00006 ms | |
naive 25145.54 - 15.44x slower +0.0372 ms | |
naive, fold 25084.02 - 15.48x slower +0.0373 ms | |
native, nested 23.21 - 16728.42x slower +43.09 ms | |
native, naive, traversed 23.06 - 16833.76x slower +43.36 ms | |
native, naive, traversed, fold 22.97 - 16896.88x slower +43.52 ms | |
native, nested, fold 21.53 - 18033.17x slower +46.45 ms | |
naive, traversed 1.55 - 250048.14x slower +644.14 ms | |
naive, traversed, fold 1.46 - 265755.27x slower +684.60 ms | |
nested, fold 0.37 - 1045420.38x slower +2693.06 ms | |
nested 0.36 - 1077784.35x slower +2776.43 ms | |
Memory usage statistics: | |
Name Memory usage | |
native, naive 0.00218 MB | |
native, naive, fold 0.00218 MB - 1.00x memory usage +0 MB | |
naive 0.0116 MB - 5.31x memory usage +0.00941 MB | |
naive, fold 0.0116 MB - 5.31x memory usage +0.00941 MB | |
native, nested 12.75 MB - 5844.20x memory usage +12.75 MB | |
native, naive, traversed 12.75 MB - 5845.10x memory usage +12.75 MB | |
native, naive, traversed, fold 12.75 MB - 5842.74x memory usage +12.75 MB | |
native, nested, fold 12.75 MB - 5841.85x memory usage +12.74 MB | |
naive, traversed 346.34 MB - 158723.67x memory usage +346.33 MB | |
naive, traversed, fold 346.44 MB - 158771.85x memory usage +346.44 MB | |
nested, fold 1064.72 MB - 487952.83x memory usage +1064.71 MB | |
nested 1064.87 MB - 488021.91x memory usage +1064.86 MB |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Name ips average deviation median 99th % | |
native, naive 384015.58 0.00260 ms ±1298.11% 0.00194 ms 0.00847 ms | |
native, naive, fold 372373.43 0.00269 ms ±601.45% 0.00196 ms 0.0110 ms | |
naive 22170.37 0.0451 ms ±210.01% 0.0386 ms 0.116 ms | |
naive, fold 20456.88 0.0489 ms ±144.07% 0.0389 ms 0.164 ms | |
native, nested 388.13 2.58 ms ±26.49% 2.31 ms 5.51 ms | |
native, nested, fold 351.89 2.84 ms ±34.88% 2.32 ms 6.20 ms | |
native, naive, traversed, fold 328.18 3.05 ms ±37.97% 2.56 ms 6.19 ms | |
native, naive, traversed 316.37 3.16 ms ±39.75% 2.61 ms 7.23 ms | |
naive, traversed, fold 14.49 69.02 ms ±8.71% 66.76 ms 84.71 ms | |
naive, traversed 13.93 71.80 ms ±27.60% 64.84 ms 165.24 ms | |
nested, fold 3.77 265.53 ms ±5.41% 265.96 ms 284.93 ms | |
nested 3.66 273.20 ms ±10.90% 264.14 ms 344.07 ms | |
Comparison: | |
native, naive 384015.58 | |
native, naive, fold 372373.43 - 1.03x slower +0.00008 ms | |
naive 22170.37 - 17.32x slower +0.0425 ms | |
naive, fold 20456.88 - 18.77x slower +0.0463 ms | |
native, nested 388.13 - 989.39x slower +2.57 ms | |
native, nested, fold 351.89 - 1091.31x slower +2.84 ms | |
native, naive, traversed, fold 328.18 - 1170.14x slower +3.04 ms | |
native, naive, traversed 316.37 - 1213.82x slower +3.16 ms | |
naive, traversed, fold 14.49 - 26505.46x slower +69.02 ms | |
naive, traversed 13.93 - 27574.19x slower +71.80 ms | |
nested, fold 3.77 - 101969.35x slower +265.53 ms | |
nested 3.66 - 104914.55x slower +273.20 ms | |
Memory usage statistics: | |
Name Memory usage | |
native, naive 0.00218 MB | |
native, naive, fold 0.00218 MB - 1.00x memory usage +0 MB | |
naive 0.0116 MB - 5.31x memory usage +0.00941 MB | |
naive, fold 0.0116 MB - 5.31x memory usage +0.00941 MB | |
native, nested 1.26 MB - 575.84x memory usage +1.25 MB | |
native, nested, fold 1.26 MB - 575.58x memory usage +1.25 MB | |
native, naive, traversed, fold 1.26 MB - 576.47x memory usage +1.26 MB | |
native, naive, traversed 1.26 MB - 576.73x memory usage +1.26 MB | |
naive, traversed, fold 34.62 MB - 15867.99x memory usage +34.62 MB | |
naive, traversed 34.63 MB - 15870.92x memory usage +34.63 MB | |
nested, fold 106.96 MB - 49018.93x memory usage +106.96 MB | |
nested 106.97 MB - 49021.67x memory usage +106.96 MB |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment