Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Benchmarking Request Cache Plug

benchmarking.livemd

Benchmarking Request Cache Plug

Mix.install([
  :jason,
  :finch,
  {:benchee, github: "bencheeorg/benchee", ref: "main", override: true},
  :benchee_html,
  {:kino_vega_lite, "~> 0.1.7"}
])

{:ok, _} = Finch.start_link(name: BenchMarkFinch)

Setup

Benchmarking

inputs =
  Enum.reduce(
    %{
      "100 Bytes" => "100-bytes",
      "10 KB" => "10-kb",
      "100 KB" => "100-kb",
      "10 MB" => "10-mb",
      "100 MB" => "100-mb",
      "Large Item" => "large-item",
      "Large Items (Multiple)" => "large-items"
    },
    %{},
    fn {name, url}, acc ->
      acc
      |> Map.put("Cached #{name}", url)
      |> Map.put("Uncached #{name}", "uncached/#{url}")
    end
  )

defmodule RequestModule do
  for {_name, url} <- inputs do
    fn_name = :"get_#{String.replace(url, "-", "_")}"

    def unquote(fn_name)() do
      :get
      |> Finch.build(Path.join("http://localhost:4000", unquote(url)))
      |> Finch.request(BenchMarkFinch)
    end
  end
end
bench =
  Benchee.run(
    Enum.map(inputs, fn {name, url} ->
      fn_name = :"get_#{String.replace(url, "-", "_")}"

      {name, fn -> apply(RequestModule, fn_name, []) end}
    end),
    warmup: 10,
    time: 30,
    formatters: [
      Benchee.Formatters.HTML,
      Benchee.Formatters.Console
    ]
  )
minimum_data =
  Enum.map(
    bench.scenarios,
    &amp;%{name: &amp;1.name, milliseconds: &amp;1.run_time_data.statistics.minimum / 1_000_000}
  )

maximum_data =
  Enum.map(
    bench.scenarios,
    &amp;%{name: &amp;1.name, milliseconds: &amp;1.run_time_data.statistics.maximum / 1_000_000}
  )

median_data =
  Enum.map(
    bench.scenarios,
    &amp;%{name: &amp;1.name, milliseconds: &amp;1.run_time_data.statistics.median / 1_000_000}
  )

min_data = Enum.reject(minimum_data, &amp;(&amp;1.name =~ ~r/Uncached 100? MB|Uncached Large Item/))
max_data = Enum.reject(maximum_data, &amp;(&amp;1.name =~ ~r/Uncached 100? MB|Uncached Large Item/))
median_2_data = Enum.reject(median_data, &amp;(&amp;1.name =~ ~r/Uncached 100? MB|Uncached Large Item/))

ips_data =
  bench.scenarios
  |> Enum.map(&amp;%{name: &amp;1.name, ips: &amp;1.run_time_data.statistics.ips})
  |> Enum.sort_by(&amp; &amp;1.ips, :desc)
VegaLite.new(title: "Times")
|> VegaLite.layers([
  VegaLite.new()
  |> VegaLite.data_from_values(maximum_data, only: ["milliseconds", "name"])
  |> VegaLite.mark(:bar)
  |> VegaLite.encode_field(:x, "milliseconds", type: :quantitative)
  |> VegaLite.encode_field(:y, "name", type: :nominal),
  VegaLite.new()
  |> VegaLite.data_from_values(minimum_data, only: ["milliseconds", "name"])
  |> VegaLite.mark(:bar)
  |> VegaLite.encode_field(:x, "milliseconds", type: :quantitative)
  |> VegaLite.encode_field(:y, "name", type: :nominal)
  |> VegaLite.encode_field(:color, "name", type: :nominal),
  VegaLite.new()
  |> VegaLite.data_from_values(median_data, only: ["milliseconds", "name"])
  |> VegaLite.mark(:rule)
  |> VegaLite.encode_field(:x, "milliseconds", type: :quantitative)
  |> VegaLite.encode_field(:y, "name", type: :nominal)
])
VegaLite.new(title: "Times Smaller than 500ms")
|> VegaLite.layers([
  VegaLite.new()
  |> VegaLite.data_from_values(max_data, only: ["milliseconds", "name"])
  |> VegaLite.mark(:bar)
  |> VegaLite.encode_field(:x, "milliseconds", type: :quantitative)
  |> VegaLite.encode_field(:y, "name", type: :nominal),
  VegaLite.new()
  |> VegaLite.data_from_values(min_data, only: ["milliseconds", "name"])
  |> VegaLite.mark(:bar)
  |> VegaLite.encode_field(:x, "milliseconds", type: :quantitative)
  |> VegaLite.encode_field(:y, "name", type: :nominal)
  |> VegaLite.encode_field(:color, "name", type: :nominal),
  VegaLite.new()
  |> VegaLite.data_from_values(median_2_data, only: ["milliseconds", "name"])
  |> VegaLite.mark(:rule)
  |> VegaLite.encode_field(:x, "milliseconds", type: :quantitative)
  |> VegaLite.encode_field(:y, "name", type: :nominal)
])
VegaLite.new(title: "Iterations Per Second")
|> VegaLite.data_from_values(ips_data, only: ["ips", "name"])
|> VegaLite.mark(:rule)
|> VegaLite.encode_field(:x, "ips", type: :quantitative)
|> VegaLite.encode_field(:y, "name", type: :nominal)