init commit
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
# PersistentVector vs Erlang Tuple vs List benchmarks
|
||||
# Run: mix run bench/persistent_vector_bench.exs
|
||||
|
||||
defmodule PVBench do
|
||||
def run do
|
||||
sizes = [10, 100, 1_000, 10_000]
|
||||
|
||||
IO.puts("=" |> String.duplicate(70))
|
||||
IO.puts("PersistentVector vs Tuple vs List — Benchmarks")
|
||||
IO.puts("=" |> String.duplicate(70))
|
||||
|
||||
for size <- sizes do
|
||||
IO.puts("\n--- Size: #{size} ---\n")
|
||||
list = Enum.to_list(1..size)
|
||||
tuple = List.to_tuple(list)
|
||||
pv = CljElixir.PersistentVector.from_list(list)
|
||||
|
||||
bench_construction(size, list)
|
||||
bench_indexed_access(size, list, tuple, pv)
|
||||
bench_append(size, list, tuple, pv)
|
||||
bench_update(size, list, tuple, pv)
|
||||
bench_iteration(size, list, tuple, pv)
|
||||
end
|
||||
end
|
||||
|
||||
defp bench_construction(size, list) do
|
||||
{pv_us, _} = :timer.tc(fn ->
|
||||
CljElixir.PersistentVector.from_list(list)
|
||||
end)
|
||||
|
||||
{tuple_us, _} = :timer.tc(fn ->
|
||||
List.to_tuple(list)
|
||||
end)
|
||||
|
||||
IO.puts(" Construction:")
|
||||
IO.puts(" PersistentVector.from_list: #{format_us(pv_us)}")
|
||||
IO.puts(" List.to_tuple: #{format_us(tuple_us)}")
|
||||
IO.puts(" List (identity): ~0 µs")
|
||||
end
|
||||
|
||||
defp bench_indexed_access(size, list, tuple, pv) do
|
||||
indices = for _ <- 1..1000, do: :rand.uniform(size) - 1
|
||||
|
||||
{pv_us, _} = :timer.tc(fn ->
|
||||
Enum.each(indices, fn i -> CljElixir.PersistentVector.pv_nth(pv, i) end)
|
||||
end)
|
||||
|
||||
{tuple_us, _} = :timer.tc(fn ->
|
||||
Enum.each(indices, fn i -> elem(tuple, i) end)
|
||||
end)
|
||||
|
||||
{list_us, _} = :timer.tc(fn ->
|
||||
Enum.each(indices, fn i -> Enum.at(list, i) end)
|
||||
end)
|
||||
|
||||
IO.puts(" Indexed access (1000 random):")
|
||||
IO.puts(" PersistentVector.pv_nth: #{format_us(pv_us)}")
|
||||
IO.puts(" elem(tuple, i): #{format_us(tuple_us)}")
|
||||
IO.puts(" Enum.at(list, i): #{format_us(list_us)}")
|
||||
end
|
||||
|
||||
defp bench_append(size, _list, tuple, pv) do
|
||||
iters = min(1000, size)
|
||||
|
||||
{pv_us, _} = :timer.tc(fn ->
|
||||
Enum.reduce(1..iters, pv, fn x, acc ->
|
||||
CljElixir.PersistentVector.pv_conj(acc, x)
|
||||
end)
|
||||
end)
|
||||
|
||||
{tuple_us, _} = :timer.tc(fn ->
|
||||
Enum.reduce(1..iters, tuple, fn x, acc ->
|
||||
:erlang.append_element(acc, x)
|
||||
end)
|
||||
end)
|
||||
|
||||
{list_us, _} = :timer.tc(fn ->
|
||||
# Prepend (O(1)) — append would be O(n) per op
|
||||
Enum.reduce(1..iters, [], fn x, acc -> [x | acc] end)
|
||||
end)
|
||||
|
||||
IO.puts(" Append #{iters} elements:")
|
||||
IO.puts(" PersistentVector.pv_conj: #{format_us(pv_us)}")
|
||||
IO.puts(" :erlang.append_element: #{format_us(tuple_us)}")
|
||||
IO.puts(" [x | list] (prepend): #{format_us(list_us)}")
|
||||
end
|
||||
|
||||
defp bench_update(size, _list, tuple, pv) do
|
||||
indices = for _ <- 1..1000, do: :rand.uniform(size) - 1
|
||||
|
||||
{pv_us, _} = :timer.tc(fn ->
|
||||
Enum.each(indices, fn i ->
|
||||
CljElixir.PersistentVector.pv_assoc(pv, i, :updated)
|
||||
end)
|
||||
end)
|
||||
|
||||
{tuple_us, _} = :timer.tc(fn ->
|
||||
Enum.each(indices, fn i ->
|
||||
put_elem(tuple, i, :updated)
|
||||
end)
|
||||
end)
|
||||
|
||||
IO.puts(" Update (1000 random):")
|
||||
IO.puts(" PersistentVector.pv_assoc: #{format_us(pv_us)}")
|
||||
IO.puts(" put_elem(tuple, i, v): #{format_us(tuple_us)}")
|
||||
IO.puts(" List: N/A (O(n) per update)")
|
||||
end
|
||||
|
||||
defp bench_iteration(size, list, tuple, pv) do
|
||||
{pv_us, _} = :timer.tc(fn ->
|
||||
cnt = CljElixir.PersistentVector.pv_count(pv)
|
||||
Enum.reduce(0..(cnt - 1), 0, fn i, acc ->
|
||||
acc + CljElixir.PersistentVector.pv_nth(pv, i)
|
||||
end)
|
||||
end)
|
||||
|
||||
{tuple_us, _} = :timer.tc(fn ->
|
||||
Enum.reduce(0..(size - 1), 0, fn i, acc ->
|
||||
acc + elem(tuple, i)
|
||||
end)
|
||||
end)
|
||||
|
||||
{list_us, _} = :timer.tc(fn ->
|
||||
Enum.reduce(list, 0, fn x, acc -> acc + x end)
|
||||
end)
|
||||
|
||||
IO.puts(" Iteration (sum all):")
|
||||
IO.puts(" PersistentVector by index: #{format_us(pv_us)}")
|
||||
IO.puts(" Tuple by index: #{format_us(tuple_us)}")
|
||||
IO.puts(" List reduce: #{format_us(list_us)}")
|
||||
end
|
||||
|
||||
defp format_us(us) when us < 1_000, do: "#{us} µs"
|
||||
defp format_us(us) when us < 1_000_000, do: "#{Float.round(us / 1_000, 1)} ms"
|
||||
defp format_us(us), do: "#{Float.round(us / 1_000_000, 2)} s"
|
||||
end
|
||||
|
||||
PVBench.run()
|
||||
Reference in New Issue
Block a user