Last active
July 25, 2024 19:07
-
-
Save bryanjos/980b77f6100d676370285941b79f5930 to your computer and use it in GitHub Desktop.
Absinthe.Subscription.get: Benchmark for proposed change
This file contains hidden or 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
Operating System: macOS | |
CPU Information: Apple M1 Pro | |
Number of Available Cores: 10 | |
Available memory: 16 GB | |
Elixir 1.17.0 | |
Erlang 27.0 | |
JIT enabled: true | |
Benchmark suite executing with the following configuration: | |
warmup: 2 s | |
time: 10 s | |
memory time: 2 s | |
reduction time: 0 ns | |
parallel: 1 | |
inputs: none specified | |
Estimated total run time: 42 s | |
Benchmarking Using MapSet and lookup ... | |
Benchmarking Using list accumulator ... | |
Benchmarking Using select ... | |
Calculating statistics... | |
Formatting results... | |
Name ips average deviation median 99th % | |
Using list accumulator 9.25 108.11 ms ±6.78% 104.94 ms 149.45 ms | |
Using MapSet and lookup 9.05 110.49 ms ±3.31% 109.03 ms 126.19 ms | |
Using select 0.0125 79835.89 ms ±0.00% 79835.89 ms 79835.89 ms | |
Comparison: | |
Using list accumulator 9.25 | |
Using MapSet and lookup 9.05 - 1.02x slower +2.38 ms | |
Using select 0.0125 - 738.49x slower +79727.79 ms | |
Memory usage statistics: | |
Name average deviation median 99th % | |
Using list accumulator 152.54 MB ±0.01% 152.53 MB 152.60 MB | |
Using MapSet and lookup 158.87 MB ±0.00% 158.87 MB 158.87 MB | |
Using select 31.18 MB ±0.00% 31.18 MB 31.18 MB | |
Comparison: | |
Using list accumulator 152.53 MB | |
Using MapSet and lookup 158.87 MB - 1.04x memory usage +6.33 MB | |
Using select 31.18 MB - 0.20x memory usage -121.36031 MB |
This file contains hidden or 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
# to run `elixir registry_bench.exs` | |
Mix.install([ | |
{:benchee, "~> 1.0"}, | |
{:elixir_uuid, "~> 1.2"} | |
]) | |
# start registry with same settings as absinthe | |
{:ok, _} = | |
Registry.start_link( | |
keys: :duplicate, | |
name: RegistryTest, | |
partitions: System.schedulers_online(), | |
compressed: true | |
) | |
random_string = fn bytes_count -> | |
bytes_count |> :crypto.strong_rand_bytes() |> Base.url_encode64(padding: false) | |
end | |
# create some field keys | |
field_keys = Enum.flat_map(1..10, fn _ -> | |
field = UUID.uuid4() | |
Enum.map(1..3, fn _ -> {field, UUID.uuid4()} end) | |
end) | |
# create doc_ids and doc_values in the shape of what absinthe would put in | |
doc_ids_and_doc_values = | |
Enum.map(1..10_000, fn _ -> | |
{UUID.uuid4(), %{initial_phases: random_string.(20), source: random_string.(20)}} | |
end) | |
# add field_keys and doc_ids to registry | |
Enum.each(doc_ids_and_doc_values, fn {doc_id, doc_value} -> | |
field_keys = for _ <- 1..5, do: Enum.random(field_keys) | |
for field_key <- field_keys do | |
{:ok, _} = Registry.register(RegistryTest, field_key, doc_id) | |
end | |
{:ok, _} = Registry.register(RegistryTest, doc_id, doc_value) | |
end) | |
# current Absinthe.Subscription.get implementation | |
select_fun = fn key -> | |
RegistryTest | |
|> Registry.lookup(key) | |
|> then(fn doc_ids -> | |
RegistryTest | |
|> Registry.select( | |
# We compose a list of match specs that basically mean "lookup all keys | |
# in the doc_ids list" | |
for {_, doc_id} <- doc_ids, | |
do: {{:"$1", :_, :"$2"}, [{:==, :"$1", doc_id}], [{{:"$1", :"$2"}}]} | |
) | |
end) | |
|> Map.new(fn {doc_id, doc} -> | |
{doc_id, doc} | |
end) | |
end | |
#proposed implementation | |
map_fun = fn key -> | |
RegistryTest | |
|> Registry.lookup(key) | |
|> MapSet.new(fn {_pid, doc_id} -> doc_id end) | |
|> Enum.reduce(%{}, fn doc_id, acc -> | |
case Registry.lookup(RegistryTest, doc_id) do | |
[] -> | |
acc | |
[{_pid, doc} | _rest] -> | |
Map.put_new(acc, doc_id, doc) | |
end | |
end) | |
end | |
#proposed with list accumulator | |
map_with_list_fun = fn key -> | |
RegistryTest | |
|> Registry.lookup(key) | |
|> MapSet.new(fn {_pid, doc_id} -> doc_id end) | |
|> Enum.reduce([], fn doc_id, acc -> | |
case Registry.lookup(RegistryTest, doc_id) do | |
[] -> | |
acc | |
[{_pid, doc} | _rest] -> | |
[{doc_id, doc} | acc] | |
end | |
end) | |
|> Map.new() | |
end | |
Benchee.run( | |
%{ | |
"Using select" => fn -> Enum.each(field_keys, select_fun) end, | |
"Using MapSet and lookup" => fn -> Enum.each(field_keys, map_fun) end, | |
"Using list accumulator" => fn -> Enum.each(field_keys, map_with_list_fun) end | |
}, | |
time: 10, | |
memory_time: 2 | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment