diff options
author | Jordan Bracco <href@random.sh> | 2020-05-08 20:10:33 +0200 |
---|---|---|
committer | Jordan Bracco <href@random.sh> | 2020-05-08 20:10:33 +0200 |
commit | b541ef96741129f5aebd2b7526bbca8717cf5c40 (patch) | |
tree | 2cad5e33c2ef3175adeac264453ac22e8b0ed126 /test | |
parent | Initial commit (diff) |
Switch to atomics, add shared ets, ..
Diffstat (limited to 'test')
-rw-r--r-- | test/limiter_test.exs | 36 | ||||
-rw-r--r-- | test/samples/limiter.exs | 33 | ||||
-rw-r--r-- | test/samples/multi_limiter.exs | 56 | ||||
-rw-r--r-- | test/samples/results_multi_limiter.txt | 86 | ||||
-rw-r--r-- | test/samples/update_counter.exs | 19 |
5 files changed, 195 insertions, 35 deletions
diff --git a/test/limiter_test.exs b/test/limiter_test.exs index c60db9e..1b81ead 100644 --- a/test/limiter_test.exs +++ b/test/limiter_test.exs @@ -2,38 +2,20 @@ defmodule LimiterTest do use ExUnit.Case doctest Limiter - defp test_ets(name, max, sleep, fun) do - count = :ets.update_counter(:limiter_test, name, {2, 1}, {name, 0}) - - if count <= max do - fun.({:ok, count}) - Process.sleep(sleep) - else - fun.(:fail) - end - after - :ets.update_counter(:limiter_test, name, {2, -1}, {name, 1}) + test "limiter ets is atomic" do + name = "test1" + Limiter.new(name, 2, 2) + atomic_test(name) end - test "limits with ets" do - :ets.new(:limiter_test, [:public, :named_table]) - ets = "test" - test = self() - spawn_link(fn -> test_ets(ets, 2, 500, fn result -> send(test, result) end) end) - spawn_link(fn -> test_ets(ets, 2, 750, fn result -> send(test, result) end) end) - spawn_link(fn -> test_ets(ets, 2, 500, fn result -> send(test, result) end) end) - assert_receive {:ok, 1} - assert_receive {:ok, 2} - assert_receive :fail - Process.sleep(500) - spawn_link(fn -> test_ets(ets, 2, 500, fn result -> send(test, result) end) end) - assert_receive {:ok, 2} + test "limiter atomics is atomic" do + name = "test2" + Limiter.new(name, 2, 2, backend: :atomics) + atomic_test(name) end - test "limiter" do - name = "test1" + defp atomic_test(name) do self = self() - Limiter.set(name, 2, 2) sleepy = fn sleep -> case Limiter.limit(name, fn -> diff --git a/test/samples/limiter.exs b/test/samples/limiter.exs index 896056d..785c85f 100644 --- a/test/samples/limiter.exs +++ b/test/samples/limiter.exs @@ -1,11 +1,28 @@ -:ets.new(:limiter_bench, [:public, :named_table]) -Limiter.new(:bench, 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000, 0) +infinite = 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000 +Limiter.new(:bench, infinite, 0) +Limiter.new(:bench_s, infinite, 0, ets: LimiterTest) -Benchee.run(%{ - "update_counter" => fn -> - :ets.update_counter(:limiter_bench, "bench", {2, 1}, {"bench", 0}) - end, - "limit" => fn -> +concurrent = [{:read_concurrency, true}, {:write_concurrency, true}] + +Limiter.new(:bench_rw, infinite, 0) +Limiter.new(:bench_s_rw, infinite, 0, ets: LimiterTest, ets_opts: concurrent) + +single = %{ + "Limiter.limit/2" => fn -> Limiter.limit(:bench, fn -> :ok end) + end, + "Limiter.limit/2 with concurrency" => fn -> + Limiter.limit(:bench_rw, fn -> :ok end) + end, + "Limiter:limit/2 with shared ets" => fn -> + Limiter.limit(:bench_s, fn -> :ok end) + end, + "Limiter:limit/2 with shared ets and concurrency" => fn -> + Limiter.limit(:bench_s_rw, fn -> :ok end) end -}) +} + +IO.puts("\n\n\n\nsingle, sequential\n\n\n\n") +Benchee.run(single, parallel: 1) +IO.puts("\n\n\n\nsingle, parallel\n\n\n\n") +Benchee.run(single, parallel: System.schedulers_online()) diff --git a/test/samples/multi_limiter.exs b/test/samples/multi_limiter.exs new file mode 100644 index 0000000..abec65d --- /dev/null +++ b/test/samples/multi_limiter.exs @@ -0,0 +1,56 @@ +infinite = 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000 + +Limiter.new(:bench_u_0, infinite, 0, backend: {:ets, LimiterTest0, []}) +Limiter.new(:bench_u_1, infinite, 0, backend: {:ets, LimiterTest1, []}) +Limiter.new(:bench_u_2, infinite, 0, backend: {:ets, LimiterTest2, []}) +Limiter.new(:bench_u_3, infinite, 0, backend: {:ets, LimiterTest3, []}) + +Limiter.new(:bench_a_0, infinite, 0, backend: :atomics) +Limiter.new(:bench_a_1, infinite, 0, backend: :atomics) +Limiter.new(:bench_a_2, infinite, 0, backend: :atomics) +Limiter.new(:bench_a_3, infinite, 0, backend: :atomics) + +Limiter.new(:bench_s_0, infinite, 0, backend: {:ets, LimiterTest, []}) +Limiter.new(:bench_s_1, infinite, 0, backend: {:ets, LimiterTest, []}) +Limiter.new(:bench_s_2, infinite, 0, backend: {:ets, LimiterTest, []}) +Limiter.new(:bench_s_3, infinite, 0, backend: {:ets, LimiterTest, []}) + +rw = [{:read_concurrency, true}, {:write_concurrency, true}] + +Limiter.new(:bench_u_rw0, infinite, 0, backend: {:ets, LimiterTestRW0, rw}) +Limiter.new(:bench_u_rw1, infinite, 0, backend: {:ets, LimiterTestRW1, rw}) +Limiter.new(:bench_u_rw2, infinite, 0, backend: {:ets, LimiterTestRW2, rw}) +Limiter.new(:bench_u_rw3, infinite, 0, backend: {:ets, LimiterTestRW3, rw}) + +Limiter.new(:bench_s_rw0, infinite, 0, backend: {:ets, LimiterTestRW, rw}) +Limiter.new(:bench_s_rw1, infinite, 0, backend: {:ets, LimiterTestRW, rw}) +Limiter.new(:bench_s_rw2, infinite, 0, backend: {:ets, LimiterTestRW, rw}) +Limiter.new(:bench_s_rw3, infinite, 0, backend: {:ets, LimiterTestRW, rw}) + +multiple = %{ + "Limiter.limit/2 unique ets" => fn -> + limiter = Enum.random([:bench_u_0, :bench_u_1, :bench_u_2, :bench_u_3]) + Limiter.limit(limiter, fn -> :ok end) + end, + "Limiter:limit/2 shared ets" => fn -> + limiter = Enum.random([:bench_s_0, :bench_s_1, :bench_s_2, :bench_s_3]) + Limiter.limit(limiter, fn -> :ok end) + end, + "Limiter.limit/2 unique ets, concurrency" => fn -> + limiter = Enum.random([:bench_u_rw0, :bench_u_rw1, :bench_u_rw2, :bench_u_rw3]) + Limiter.limit(limiter, fn -> :ok end) + end, + "Limiter:limit/2 shared ets, concurrency" => fn -> + limiter = Enum.random([:bench_s_rw0, :bench_s_rw1, :bench_s_rw2, :bench_s_rw3]) + Limiter.limit(limiter, fn -> :ok end) + end, + "Limiter:limit/2 atomics" => fn -> + limiter = Enum.random([:bench_a_0, :bench_a_1, :bench_a_2, :bench_a_3]) + Limiter.limit(limiter, fn -> :ok end) + end +} + +IO.puts("\n\n\n\nmulti, sequential\n\n\n\n") +Benchee.run(multiple) +IO.puts("\n\n\n\nmulti, parallel\n\n\n\n") +Benchee.run(multiple, parallel: System.schedulers_online()) diff --git a/test/samples/results_multi_limiter.txt b/test/samples/results_multi_limiter.txt new file mode 100644 index 0000000..112c325 --- /dev/null +++ b/test/samples/results_multi_limiter.txt @@ -0,0 +1,86 @@ + + + + +multi, sequential + + + + +Operating System: Linux +CPU Information: AMD EPYC 7401P 24-Core Processor +Number of Available Cores: 8 +Available memory: 31.41 GB +Elixir 1.10.3 +Erlang 22.3.2 + +Benchmark suite executing with the following configuration: +warmup: 2 s +time: 5 s +memory time: 0 ns +parallel: 1 +inputs: none specified +Estimated total run time: 35 s + +Benchmarking Limiter.limit/2 unique ets... +Benchmarking Limiter.limit/2 unique ets, concurrency... +Benchmarking Limiter:limit/2 atomics... +Benchmarking Limiter:limit/2 shared ets... +Benchmarking Limiter:limit/2 shared ets, concurrency... + +Name ips average deviation median 99th % +Limiter:limit/2 atomics 491.88 K 2.03 μs ±1506.30% 1.55 μs 3.48 μs +Limiter.limit/2 unique ets 414.63 K 2.41 μs ±1169.34% 1.97 μs 4.53 μs +Limiter:limit/2 shared ets 411.43 K 2.43 μs ±1286.95% 1.96 μs 3.66 μs +Limiter.limit/2 unique ets, concurrency 406.50 K 2.46 μs ±1006.31% 2.06 μs 4.34 μs +Limiter:limit/2 shared ets, concurrency 384.04 K 2.60 μs ±1293.25% 2.12 μs 4.37 μs + +Comparison: +Limiter:limit/2 atomics 491.88 K +Limiter.limit/2 unique ets 414.63 K - 1.19x slower +0.38 μs +Limiter:limit/2 shared ets 411.43 K - 1.20x slower +0.40 μs +Limiter.limit/2 unique ets, concurrency 406.50 K - 1.21x slower +0.43 μs +Limiter:limit/2 shared ets, concurrency 384.04 K - 1.28x slower +0.57 μs + + + + +multi, parallel + + + + +Operating System: Linux +CPU Information: AMD EPYC 7401P 24-Core Processor +Number of Available Cores: 8 +Available memory: 31.41 GB +Elixir 1.10.3 +Erlang 22.3.2 + +Benchmark suite executing with the following configuration: +warmup: 2 s +time: 5 s +memory time: 0 ns +parallel: 8 +inputs: none specified +Estimated total run time: 35 s + +Benchmarking Limiter.limit/2 unique ets... +Benchmarking Limiter.limit/2 unique ets, concurrency... +Benchmarking Limiter:limit/2 atomics... +Benchmarking Limiter:limit/2 shared ets... +Benchmarking Limiter:limit/2 shared ets, concurrency... + +Name ips average deviation median 99th % +Limiter:limit/2 atomics 307.84 K 3.25 μs ±1113.62% 2.09 μs 10.24 μs +Limiter.limit/2 unique ets, concurrency 95.56 K 10.46 μs ±391.37% 2.93 μs 163.02 μs +Limiter:limit/2 shared ets, concurrency 92.39 K 10.82 μs ±374.36% 2.92 μs 158.97 μs +Limiter.limit/2 unique ets 80.68 K 12.39 μs ±362.74% 2.85 μs 160.66 μs +Limiter:limit/2 shared ets 6.04 K 165.66 μs ±17.23% 167.48 μs 237.96 μs + +Comparison: +Limiter:limit/2 atomics 307.84 K +Limiter.limit/2 unique ets, concurrency 95.56 K - 3.22x slower +7.22 μs +Limiter:limit/2 shared ets, concurrency 92.39 K - 3.33x slower +7.57 μs +Limiter.limit/2 unique ets 80.68 K - 3.82x slower +9.15 μs +Limiter:limit/2 shared ets 6.04 K - 51.00x slower +162.41 μs diff --git a/test/samples/update_counter.exs b/test/samples/update_counter.exs new file mode 100644 index 0000000..1768735 --- /dev/null +++ b/test/samples/update_counter.exs @@ -0,0 +1,19 @@ +:ets.new(:limiter_bench, [:public, :named_table]) + +Benchee.run( + %{ + "ets:update_counter" => fn -> + :ets.update_counter(:limiter_bench, "bench", {2, 1}, {"bench", 0}) + end + }, + parallel: 1 +) + +Benchee.run( + %{ + "ets:update_counter" => fn -> + :ets.update_counter(:limiter_bench, "bench", {2, 1}, {"bench", 0}) + end + }, + parallel: System.schedulers_online() +) |