Skip to content

Commit

Permalink
Benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
ne-sachirou committed Apr 29, 2020
1 parent a879e92 commit a141c4b
Show file tree
Hide file tree
Showing 11 changed files with 241 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .credo.exs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@
{Credo.Check.Refactor.VariableRebinding, false},
{Credo.Check.Warning.LeakyEnvironment, false},
{Credo.Check.Warning.MapGetUnsafePass, false},
{Credo.Check.Warning.UnsafeToAtom, false}
{Credo.Check.Warning.UnsafeToAtom, false},
{Credo.Check.Warning.LeakyEnvironment, false}

#
# Custom checks can be created using `mix credo.gen.check`.
Expand Down
4 changes: 4 additions & 0 deletions benchmark/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
24 changes: 24 additions & 0 deletions benchmark/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where third-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Ignore package tarball (built via "mix hex.build").
benchmark-*.tar

6 changes: 6 additions & 0 deletions benchmark/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Benchmark

```sh
mix do deps.get, format
mix do compile, benchmark
```
13 changes: 13 additions & 0 deletions benchmark/lib/benchmark.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule Benchmark do
@moduledoc """
"""

@doc """
"""
def run do
for test_case <- [Benchmark.Cases.DataStoreKind] do
IO.inspect(test_case)
test_case.run
end
end
end
143 changes: 143 additions & 0 deletions benchmark/lib/cases/data_store_kind.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
defmodule Benchmark.Cases.DataStoreKind do
@moduledoc """
Compare the speed of data stores.
"""

@doc """
"""
def run do
scenarios =
for name <- ~w(empty ets fast_global gen_server heap persistent_term), into: %{} do
{name,
{
parallel(fn {param, size} ->
apply(__MODULE__, String.to_existing_atom("run_#{name}"), [param, size])
end),
before_scenario: fn data ->
{apply(__MODULE__, String.to_existing_atom("prepare_#{name}"), [data]),
map_size(data)}
end,
after_scenario: fn {param, _} ->
apply(__MODULE__, String.to_existing_atom("cleanup_#{name}"), [param])
end
}}
end

Benchee.run(
scenarios,
inputs: %{
"100" => generate_data(100),
"1_000" => generate_data(1_000),
"10_000" => generate_data(10_000),
"100_000" => generate_data(100_000)
},
memory_time: 2,
time: 10
)
end

def prepare_empty(_data), do: nil

def run_empty(_, size) do
for _ <- 1..100_000, do: :rand.uniform(size)
end

def cleanup_empty(_), do: nil

def prepare_ets(data) do
tid = :ets.new(:test, [:set, :protected, read_concurrency: true])
:ets.insert_new(tid, Map.to_list(data))
tid
end

def run_ets(tid, size) do
for _ <- 1..100_000 do
item = :ets.lookup_element(tid, :rand.uniform(size), 2)
item.name
item.callback
end
end

def cleanup_ets(tid), do: :ets.delete(tid)

def prepare_fast_global(data) do
data =
for {id, item} <- data, into: %{} do
item = update_in(item.callback, &:erlang.term_to_binary(&1))
{id, item}
end

FastGlobal.put(__MODULE__, data)
end

def run_fast_global(_, size) do
for _ <- 1..100_000 do
item = FastGlobal.get(__MODULE__)[:rand.uniform(size)]
item.name
:erlang.binary_to_term(item.callback)
end
end

def cleanup_fast_global(_), do: FastGlobal.put(__MODULE__, nil)

def prepare_gen_server(data), do: elem(GenServer.start_link(__MODULE__.GenServer, data), 1)

def run_gen_server(pid, size) do
for _ <- 1..100_000 do
item = GenServer.call(pid, {:lookup, :rand.uniform(size)})
item.name
item.callback
end
end

def cleanup_gen_server(pid), do: GenServer.stop(pid)

def prepare_heap(data), do: data

def run_heap(data, size) do
for _ <- 1..100_000 do
item = data[:rand.uniform(size)]
item.name
item.callback
end
end

def cleanup_heap(_), do: nil

def prepare_persistent_term(data), do: :persistent_term.put(__MODULE__, data)

def run_persistent_term(_, size) do
for _ <- 1..100_000 do
item = :persistent_term.get(__MODULE__)[:rand.uniform(size)]
item.name
item.callback
end
end

def cleanup_persistent_term(_), do: :persistent_term.erase(__MODULE__)

defp generate_data(size) do
for i <- 1..size, into: %{} do
item = %{id: i, name: "item #{i}", callback: fn n -> n + 1 end}
{i, item}
end
end

def parallel(fun) do
fn arg ->
1..System.schedulers_online()
|> Task.async_stream(fn _ -> fun.(arg) end, ordered: false, timeout: 10 * 1000)
|> Stream.run()
end
end
end

defmodule Benchmark.Cases.DataStoreKind.GenServer do
use GenServer

@impl GenServer
def init(data), do: {:ok, data}

@impl GenServer
def handle_call({:lookup, id}, _from, data), do: {:reply, data[id], data}
end
12 changes: 12 additions & 0 deletions benchmark/lib/mix/tasks/benchmark.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule Mix.Tasks.Benchmark do
@moduledoc """
Run bemchmarks.
"""

use Mix.Task

@shortdoc "Run bemchmarks."

@impl Mix.Task
def run(_), do: Benchmark.run()
end
23 changes: 23 additions & 0 deletions benchmark/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
defmodule Benchmark.MixProject do
use Mix.Project

def project do
[
app: :benchmark,
deps: deps(),
elixir: "~> 1.10",
start_permanent: Mix.env() == :prod,
version: "0.1.0"
]
end

def application, do: [extra_applications: [:logger]]

defp deps do
[
{:benchee, "~> 1.0"},
{:fastglobal, "~> 1.0"},
{:mnemonics, path: ".."}
]
end
end
5 changes: 5 additions & 0 deletions benchmark/mix.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
%{
"benchee": {:hex, :benchee, "1.0.1", "66b211f9bfd84bd97e6d1beaddf8fc2312aaabe192f776e8931cb0c16f53a521", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}], "hexpm", "3ad58ae787e9c7c94dd7ceda3b587ec2c64604563e049b2a0e8baafae832addb"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"fastglobal": {:hex, :fastglobal, "1.0.0", "f3133a0cda8e9408aac7281ec579c4b4a8386ce0e99ca55f746b9f58192f455b", [:mix], [], "hexpm", "cfdb7ed63910bc75f579cd09e2517618fa9418b56731d51d03f7ba4b400798d0"},
}
8 changes: 8 additions & 0 deletions benchmark/test/benchmark_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
defmodule BenchmarkTest do
use ExUnit.Case
doctest Benchmark

test "greets the world" do
assert Benchmark.hello() == :world
end
end
1 change: 1 addition & 0 deletions benchmark/test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExUnit.start()

0 comments on commit a141c4b

Please sign in to comment.