summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJordan Bracco <href@random.sh>2020-05-08 20:10:33 +0200
committerJordan Bracco <href@random.sh>2020-05-08 20:10:33 +0200
commitb541ef96741129f5aebd2b7526bbca8717cf5c40 (patch)
tree2cad5e33c2ef3175adeac264453ac22e8b0ed126 /test
parentInitial commit (diff)
Switch to atomics, add shared ets, ..
Diffstat (limited to 'test')
-rw-r--r--test/limiter_test.exs36
-rw-r--r--test/samples/limiter.exs33
-rw-r--r--test/samples/multi_limiter.exs56
-rw-r--r--test/samples/results_multi_limiter.txt86
-rw-r--r--test/samples/update_counter.exs19
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()
+)