Skip to content

Instantly share code, notes, and snippets.

@shanesveller
Last active June 25, 2021 20:51
Show Gist options
  • Save shanesveller/9546b6b2e68d4433cac8bcf31f465cf5 to your computer and use it in GitHub Desktop.
Save shanesveller/9546b6b2e68d4433cac8bcf31f465cf5 to your computer and use it in GitHub Desktop.
# Inspired by https://engineering.tripping.com/blazing-fast-elixir-configuration-475aca10011d
# Updated with more options, including persistent_term and process locals
Mix.install([{:benchee, "~> 1.0"}])
Application.put_env(:fast_config, :adapter, TargetModule)
:persistent_term.put({:fast_config, :adapter}, TargetModule)
defmodule TargetModule do
def run, do: :ok
end
defmodule DispatchedModule do
@callback adapter :: module
@callback run :: term
end
defmodule ApplicationAdapter do
@behaviour DispatchedModule
@impl true
def adapter, do: Application.get_env(:fast_config, :adapter)
@impl true
def run, do: adapter().run()
end
defmodule PersistentAdapter do
@behaviour DispatchedModule
@impl true
def adapter, do: :persistent_term.get({:fast_config, :adapter})
@impl true
def run, do: adapter().run()
end
defmodule MemoizedAdapter do
@behaviour DispatchedModule
@impl true
def adapter, do: memoized_get(:fast_config, :adapter)
@impl true
def run, do: adapter().run()
defp memoized_get(namespace, key) do
case :persistent_term.get({namespace, key}) do
nil ->
val = Application.get_env(namespace, key)
:persistent_term.put({namespace, key}, val)
val
val ->
val
end
end
end
defmodule ProcessAdapter do
@behaviour DispatchedModule
@impl true
def adapter, do: memoized_get(:fast_config, :adapter)
@impl true
def run, do: adapter().run()
defp memoized_get(namespace, key) do
case Process.get({namespace, key}) do
nil ->
val = Application.get_env(namespace, key)
Process.put({namespace, key}, val)
val
val ->
val
end
end
end
defmodule ModuleAttrAdapter do
@behaviour DispatchedModule
@adapter Application.compile_env(:fast_config, :adapter)
@impl true
def adapter, do: @adapter
@impl true
def run, do: adapter().run()
end
Benchee.run(%{
"application.get_env" => fn -> ApplicationAdapter.run() end,
"persistent_term.get" => fn -> PersistentAdapter.run() end,
"memoized" => fn -> MemoizedAdapter.run() end,
"process_memoized" => fn -> ProcessAdapter.run() end,
"module_attr" => fn -> ModuleAttrAdapter.run() end,
"baseline" => fn -> TargetModule.run() end
})
@shanesveller
Copy link
Author

Wrapped each with for _n <- 1..1000, do: ...:

Name                          ips        average  deviation         median         99th %
baseline                  39.81 K       25.12 μs    ±22.03%          24 μs          47 μs
module_attr               29.99 K       33.35 μs    ±20.00%          33 μs          64 μs
process_memoized          12.83 K       77.95 μs    ±16.34%          75 μs         141 μs
persistent_term.get       11.24 K       88.97 μs    ±10.66%          87 μs         130 μs
memoized                  10.58 K       94.48 μs    ±13.80%          92 μs         165 μs
application.get_env        3.86 K      259.22 μs    ±11.20%         253 μs         403 μs

Comparison:
baseline                  39.81 K
module_attr               29.99 K - 1.33x slower +8.23 μs
process_memoized          12.83 K - 3.10x slower +52.83 μs
persistent_term.get       11.24 K - 3.54x slower +63.85 μs
memoized                  10.58 K - 3.76x slower +69.36 μs
application.get_env        3.86 K - 10.32x slower +234.10 μs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment