Skip to content

Instantly share code, notes, and snippets.

@hauleth
Last active July 25, 2025 16:10
Show Gist options
  • Save hauleth/fa7a29ce8437c8ba8d03d0bfe158ab4c to your computer and use it in GitHub Desktop.
Save hauleth/fa7a29ce8437c8ba8d03d0bfe158ab4c to your computer and use it in GitHub Desktop.

Untitled notebook

Mix.install([
  :kino_benchee,
  :peep
])

Section

defmodule Curr do
  @moduledoc """
  A helper module for writing modules that implement the `Peep.Buckets`
  behavior, with custom bucket boundaries.

  For an example, look at the source of `Peep.Buckets.PowersOfTen`.
  """

  defmacro __using__(opts) do
    dbg Module.attributes_in(__CALLER__.module)
    buckets =
      Keyword.fetch!(opts, :buckets)
      |> Code.eval_quoted([], __CALLER__)
      |> elem(0)
      |> :lists.usort()

    unless Enum.all?(buckets, &is_number/1) do
      raise ArgumentError, "expected buckets to be a list of numbers, got: #{buckets}"
    end

    number_of_buckets = length(buckets)

    quote do
      @behaviour Peep.Buckets

      @impl true
      def config(_), do: %{}

      @impl true
      def number_of_buckets(_), do: unquote(number_of_buckets)

      @impl true
      unquote(bucket_for_ast(buckets))

      @impl true
      unquote(upper_bound_ast(buckets))

            def all(samples) do
        Enum.each(samples, &bucket_for(&1, []))
      end
    end
  end

  ## Bucket binary search

  defp bucket_for_ast(buckets) do
    int_buckets =
      buckets
      |> Enum.map(&ceil/1)
      |> Enum.with_index()
      |> Enum.dedup_by(&elem(&1, 0))

    float_buckets =
      buckets
      |> Enum.map(&(&1 * 1.0))
      |> Enum.with_index()

    length = length(buckets)

    variable = Macro.var(:x, nil)

    int_length = length(int_buckets)
    int_tree = build_bucket_tree(int_buckets, int_length, length, variable)

    float_length = length(float_buckets)
    float_tree = build_bucket_tree(float_buckets, float_length, length, variable)

    quote do
      def bucket_for(unquote(variable), _) when is_integer(unquote(variable)) do
        unquote(int_tree)
      end

      def bucket_for(unquote(variable), _) when is_float(unquote(variable)) do
        unquote(float_tree)
      end
    end

    # |> tap(&IO.puts(Code.format_string!(Macro.to_string(&1))))
  end

  defp build_bucket_tree([{bound, lval}], 1, rval, variable) do
    quote do
      case unquote(variable) do
        x when x < unquote(bound) ->
          unquote(lval)

        _ ->
          unquote(rval)
      end
    end
  end

  defp build_bucket_tree([{lbound, lval}, {rbound, mval}], 2, rval, variable) do
    quote do
      case unquote(variable) do
        x when x < unquote(lbound) ->
          unquote(lval)

        x when x < unquote(rbound) ->
          unquote(mval)

        _ ->
          unquote(rval)
      end
    end
  end

  defp build_bucket_tree(bounds, length, rval, variable) do
    llength = div(length, 2)
    rlength = length - llength - 1

    {lbounds, rbounds} = Enum.split(bounds, llength)
    [{bound, lval} | rbounds] = rbounds

    quote do
      case unquote(variable) do
        x when x < unquote(bound) ->
          unquote(build_bucket_tree(lbounds, llength, lval, variable))

        _ ->
          unquote(build_bucket_tree(rbounds, rlength, rval, variable))
      end
    end
  end

  ## Upper bound

  defp upper_bound_ast(buckets) do
    bucket_defns =
      for {boundary, bucket_idx} <- Enum.with_index(buckets) do
        quote do
          def upper_bound(unquote(bucket_idx), _), do: unquote(int_to_float_string(boundary))
        end
      end

    final_defn =
      quote do
        def upper_bound(_, _), do: "+Inf"
      end

    bucket_defns ++ [final_defn]
  end

  defp int_to_float_string(int) do
    to_string(int * 1.0)
  end
end
{:module, Curr, <<70, 79, 82, 49, 0, 0, 32, ...>>, {:int_to_float_string, 1}}
defmodule Fin do
  @moduledoc """
  A helper module for writing modules that implement the `Peep.Buckets`
  behavior, with custom bucket boundaries.

  For an example, look at the source of `Peep.Buckets.PowersOfTen`.
  """

  defmacro __using__(opts) do
    quote bind_quoted: [buckets: Keyword.fetch!(opts, :buckets)] do
      @behaviour Peep.Buckets

      require Fin

      buckets = :lists.usort(buckets)
      len = length(buckets)

      unless Enum.all?(buckets, &is_number/1) do
        raise ArgumentError, "expected buckets to be a list of numbers, got: #{buckets}"
      end

      @impl true
      def config(_), do: %{}

      @impl true
      def number_of_buckets(_), do: unquote(len)

      @impl true

      int_buckets =
        buckets
        |> Enum.map(&ceil/1)
        |> Enum.with_index()
        |> Enum.dedup_by(&elem(&1, 0))

      float_buckets =
        buckets
        |> Enum.map(&(&1 * 1.0))
        |> Enum.with_index()

      if len < 32 do
        for {top, idx} <- int_buckets do
          def bucket_for(val, _) when is_integer(val) and val < unquote(top), do: unquote(idx)
        end

        for {top, idx} <- float_buckets do
          def bucket_for(val, _) when is_float(val) and val < unquote(top), do: unquote(idx)
        end

        def bucket_for(_, _), do: unquote(length(buckets))
      else
        def bucket_for(val, _) when is_integer(val) do
          Fin.build_tree(unquote(int_buckets), unquote(len), val)
        end

        def bucket_for(val, _) when is_float(val) do
          Fin.build_tree(unquote(float_buckets), unquote(len), val)
        end
      end

      @impl true
      def upper_bound(_, _)

      for {boundary, bucket_idx} <- Enum.with_index(buckets) do
        def upper_bound(unquote(bucket_idx), _), do: unquote(to_string(boundary * 1.0))
      end

      def upper_bound(_, _), do: "+Inf"

                  def all(samples) do
        Enum.each(samples, &bucket_for(&1, []))
      end
    end
  end

  ## Bucket binary search

  defmacro build_tree(buckets, overflow, var) do
    build_bucket_tree(buckets, length(buckets), overflow, var)
  end

  defp build_bucket_tree([{bound, lval}], 1, rval, variable) do
    quote do
      case unquote(variable) do
        x when x < unquote(bound) ->
          unquote(lval)

        _ ->
          unquote(rval)
      end
    end
  end

  defp build_bucket_tree([{lbound, lval}, {rbound, mval}], 2, rval, variable) do
    quote do
      case unquote(variable) do
        x when x < unquote(lbound) ->
          unquote(lval)

        x when x < unquote(rbound) ->
          unquote(mval)

        _ ->
          unquote(rval)
      end
    end
  end

  defp build_bucket_tree(bounds, length, rval, variable) do
    llength = div(length, 2)
    rlength = length - llength - 1

    {lbounds, rbounds} = Enum.split(bounds, llength)
    [{bound, lval} | rbounds] = rbounds

    quote do
      case unquote(variable) do
        x when x < unquote(bound) ->
          unquote(build_bucket_tree(lbounds, llength, lval, variable))

        _ ->
          unquote(build_bucket_tree(rbounds, rlength, rval, variable))
      end
    end
  end
end
{:module, Fin, <<70, 79, 82, 49, 0, 0, 21, ...>>, {:build_bucket_tree, 4}}
defmodule Lin do
  @moduledoc """
  A helper module for writing modules that implement the `Peep.Buckets`
  behavior, with custom bucket boundaries.

  For an example, look at the source of `Peep.Buckets.PowersOfTen`.
  """

  defmacro __using__(opts) do
    quote bind_quoted: [buckets: Keyword.fetch!(opts, :buckets)] do
      buckets = :lists.usort(buckets)

      unless Enum.all?(buckets, &is_number/1) do
        raise ArgumentError, "expected buckets to be a list of numbers, got: #{buckets}"
      end

      @behaviour Peep.Buckets

      @impl true
      def config(_), do: %{}

      @impl true
      def number_of_buckets(_), do: unquote(length(buckets))

      int_buckets =
        buckets
        |> Enum.map(&ceil/1)
        |> Enum.with_index()
        |> Enum.dedup_by(&elem(&1, 0))

      float_buckets =
        buckets
        |> Enum.map(&(&1 * 1.0))
        |> Enum.with_index()

      max = Enum.max(buckets)

      @impl true
      for {top, idx} <- int_buckets do
        def bucket_for(val, _) when is_integer(val) and val < unquote(top), do: unquote(idx)
      end

      for {top, idx} <- float_buckets do
        def bucket_for(val, _) when is_float(val) and val < unquote(top), do: unquote(idx)
      end

      def bucket_for(_, _), do: unquote(length(buckets))

      @impl true
      def upper_bound(_, _)

      for {boundary, bucket_idx} <- Enum.with_index(buckets) do
        def upper_bound(unquote(bucket_idx), _), do: unquote(to_string(boundary * 1.0))
      end

      def upper_bound(_, _), do: "+Inf"

      def all(samples) do
        Enum.each(samples, &bucket_for(&1, []))
      end
    end
  end

  ## Bucket binary search

  def bsearch(tuple, key) do
    bsearch(tuple, key, 0, tuple_size(tuple) - 1)
  end

  defp bsearch(tuple, _key, n, n), do: elem(elem(tuple, n), 1)

  defp bsearch(tuple, key, a, b) do
    mid = div(b - a, 2) + a

    case elem(tuple, mid) do
      {v, _} when key < v -> bsearch(tuple, key, a, mid)
      _ -> bsearch(tuple, key, mid + 1, b)
    end
  end
end
{:module, Lin, <<70, 79, 82, 49, 0, 0, 17, ...>>, {:bsearch, 4}}
range = 1..10_000

for {name, step} <- [{Small, 666}, {Mid, 100}, {Large, 10}] do 
  defmodule Module.concat(Fin, name) do
    use Fin, buckets: Enum.to_list(%{range | step: step})
  end

    defmodule Module.concat(Lin, name) do
    use Lin, buckets: Enum.to_list(%{range | step: step})
  end
end
warning: variable "step" is unused (if the variable is not meant to be used, prefix it with an underscore)
└─ peep-bench.livemd#cell:armt2gwknf3nnynu:3

[
  {:module, Lin.Small,
   <<70, 79, 82, 49, 0, 0, 17, 184, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 250, 0, 0, 0, 24, 16,
     69, 108, 105, 120, 105, 114, 46, 76, 105, 110, 46, 83, 109, 97, 108, 108, 8, 95, 95, 105, 110,
     ...>>, {:all, 1}},
  {:module, Lin.Mid,
   <<70, 79, 82, 49, 0, 0, 45, 172, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 248, 0, 0, 0, 24, 14,
     69, 108, 105, 120, 105, 114, 46, 76, 105, 110, 46, 77, 105, 100, 8, 95, 95, 105, 110, 102,
     ...>>, {:all, 1}},
  {:module, Lin.Large,
   <<70, 79, 82, 49, 0, 1, 91, 168, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 250, 0, 0, 0, 24, 16,
     69, 108, 105, 120, 105, 114, 46, 76, 105, 110, 46, 76, 97, 114, 103, 101, 8, 95, 95, ...>>,
   {:all, 1}}
]
Enum.to_list(%{range | step: div(Range.size(range), 15)})
[1, 667, 1333, 1999, 2665, 3331, 3997, 4663, 5329, 5995, 6661, 7327, 7993, 8659, 9325, 9991]
defmodule Curr.Small do
  use Curr, buckets: [1, 334, 667, 1000, 1333, 1666, 1999, 2332, 2665, 2998, 3331, 3664, 3997, 4330, 4663, 4996, 5329,
 5662, 5995, 6328, 6661, 6994, 7327, 7660, 7993, 8326, 8659, 8992, 9325, 9658, 9991]
end

defmodule Curr.Mid do
  use Curr, buckets: [1, 101, 201, 301, 401, 501, 601, 701, 801, 901, 1001, 1101, 1201, 1301, 1401,
 1501, 1601, 1701, 1801, 1901, 2001, 2101, 2201, 2301, 2401, 2501, 2601, 2701,
 2801, 2901, 3001, 3101, 3201, 3301, 3401, 3501, 3601, 3701, 3801, 3901, 4001,
 4101, 4201, 4301, 4401, 4501, 4601, 4701, 4801, 4901, 5001, 5101, 5201, 5301,
 5401, 5501, 5601, 5701, 5801, 5901, 6001, 6101, 6201, 6301, 6401, 6501, 6601,
 6701, 6801, 6901, 7001, 7101, 7201, 7301, 7401, 7501, 7601, 7701, 7801, 7901,
 8001, 8101, 8201, 8301, 8401, 8501, 8601, 8701, 8801, 8901, 9001, 9101, 9201,
 9301, 9401, 9501, 9601, 9701, 9801, 9901]
end

defmodule Curr.Large do
  use Curr, buckets: [1, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101, 111, 121, 131, 141, 151, 161, 171,
 181, 191, 201, 211, 221, 231, 241, 251, 261, 271, 281, 291, 301, 311, 321, 331,
 341, 351, 361, 371, 381, 391, 401, 411, 421, 431, 441, 451, 461, 471, 481, 491,
 501, 511, 521, 531, 541, 551, 561, 571, 581, 591, 601, 611, 621, 631, 641, 651,
 661, 671, 681, 691, 701, 711, 721, 731, 741, 751, 761, 771, 781, 791, 801, 811,
 821, 831, 841, 851, 861, 871, 881, 891, 901, 911, 921, 931, 941, 951, 961, 971,
 981, 991, 1001, 1011, 1021, 1031, 1041, 1051, 1061, 1071, 1081, 1091, 1101,
 1111, 1121, 1131, 1141, 1151, 1161, 1171, 1181, 1191, 1201, 1211, 1221, 1231,
 1241, 1251, 1261, 1271, 1281, 1291, 1301, 1311, 1321, 1331, 1341, 1351, 1361,
 1371, 1381, 1391, 1401, 1411, 1421, 1431, 1441, 1451, 1461, 1471, 1481, 1491,
 1501, 1511, 1521, 1531, 1541, 1551, 1561, 1571, 1581, 1591, 1601, 1611, 1621,
 1631, 1641, 1651, 1661, 1671, 1681, 1691, 1701, 1711, 1721, 1731, 1741, 1751,
 1761, 1771, 1781, 1791, 1801, 1811, 1821, 1831, 1841, 1851, 1861, 1871, 1881,
 1891, 1901, 1911, 1921, 1931, 1941, 1951, 1961, 1971, 1981, 1991, 2001, 2011,
 2021, 2031, 2041, 2051, 2061, 2071, 2081, 2091, 2101, 2111, 2121, 2131, 2141,
 2151, 2161, 2171, 2181, 2191, 2201, 2211, 2221, 2231, 2241, 2251, 2261, 2271,
 2281, 2291, 2301, 2311, 2321, 2331, 2341, 2351, 2361, 2371, 2381, 2391, 2401,
 2411, 2421, 2431, 2441, 2451, 2461, 2471, 2481, 2491, 2501, 2511, 2521, 2531,
 2541, 2551, 2561, 2571, 2581, 2591, 2601, 2611, 2621, 2631, 2641, 2651, 2661,
 2671, 2681, 2691, 2701, 2711, 2721, 2731, 2741, 2751, 2761, 2771, 2781, 2791,
 2801, 2811, 2821, 2831, 2841, 2851, 2861, 2871, 2881, 2891, 2901, 2911, 2921,
 2931, 2941, 2951, 2961, 2971, 2981, 2991, 3001, 3011, 3021, 3031, 3041, 3051,
 3061, 3071, 3081, 3091, 3101, 3111, 3121, 3131, 3141, 3151, 3161, 3171, 3181,
 3191, 3201, 3211, 3221, 3231, 3241, 3251, 3261, 3271, 3281, 3291, 3301, 3311,
 3321, 3331, 3341, 3351, 3361, 3371, 3381, 3391, 3401, 3411, 3421, 3431, 3441,
 3451, 3461, 3471, 3481, 3491, 3501, 3511, 3521, 3531, 3541, 3551, 3561, 3571,
 3581, 3591, 3601, 3611, 3621, 3631, 3641, 3651, 3661, 3671, 3681, 3691, 3701,
 3711, 3721, 3731, 3741, 3751, 3761, 3771, 3781, 3791, 3801, 3811, 3821, 3831,
 3841, 3851, 3861, 3871, 3881, 3891, 3901, 3911, 3921, 3931, 3941, 3951, 3961,
 3971, 3981, 3991, 4001, 4011, 4021, 4031, 4041, 4051, 4061, 4071, 4081, 4091,
 4101, 4111, 4121, 4131, 4141, 4151, 4161, 4171, 4181, 4191, 4201, 4211, 4221,
 4231, 4241, 4251, 4261, 4271, 4281, 4291, 4301, 4311, 4321, 4331, 4341, 4351,
 4361, 4371, 4381, 4391, 4401, 4411, 4421, 4431, 4441, 4451, 4461, 4471, 4481,
 4491, 4501, 4511, 4521, 4531, 4541, 4551, 4561, 4571, 4581, 4591, 4601, 4611,
 4621, 4631, 4641, 4651, 4661, 4671, 4681, 4691, 4701, 4711, 4721, 4731, 4741,
 4751, 4761, 4771, 4781, 4791, 4801, 4811, 4821, 4831, 4841, 4851, 4861, 4871,
 4881, 4891, 4901, 4911, 4921, 4931, 4941, 4951, 4961, 4971, 4981, 4991, 5001,
 5011, 5021, 5031, 5041, 5051, 5061, 5071, 5081, 5091, 5101, 5111, 5121, 5131,
 5141, 5151, 5161, 5171, 5181, 5191, 5201, 5211, 5221, 5231, 5241, 5251, 5261,
 5271, 5281, 5291, 5301, 5311, 5321, 5331, 5341, 5351, 5361, 5371, 5381, 5391,
 5401, 5411, 5421, 5431, 5441, 5451, 5461, 5471, 5481, 5491, 5501, 5511, 5521,
 5531, 5541, 5551, 5561, 5571, 5581, 5591, 5601, 5611, 5621, 5631, 5641, 5651,
 5661, 5671, 5681, 5691, 5701, 5711, 5721, 5731, 5741, 5751, 5761, 5771, 5781,
 5791, 5801, 5811, 5821, 5831, 5841, 5851, 5861, 5871, 5881, 5891, 5901, 5911,
 5921, 5931, 5941, 5951, 5961, 5971, 5981, 5991, 6001, 6011, 6021, 6031, 6041,
 6051, 6061, 6071, 6081, 6091, 6101, 6111, 6121, 6131, 6141, 6151, 6161, 6171,
 6181, 6191, 6201, 6211, 6221, 6231, 6241, 6251, 6261, 6271, 6281, 6291, 6301,
 6311, 6321, 6331, 6341, 6351, 6361, 6371, 6381, 6391, 6401, 6411, 6421, 6431,
 6441, 6451, 6461, 6471, 6481, 6491, 6501, 6511, 6521, 6531, 6541, 6551, 6561,
 6571, 6581, 6591, 6601, 6611, 6621, 6631, 6641, 6651, 6661, 6671, 6681, 6691,
 6701, 6711, 6721, 6731, 6741, 6751, 6761, 6771, 6781, 6791, 6801, 6811, 6821,
 6831, 6841, 6851, 6861, 6871, 6881, 6891, 6901, 6911, 6921, 6931, 6941, 6951,
 6961, 6971, 6981, 6991, 7001, 7011, 7021, 7031, 7041, 7051, 7061, 7071, 7081,
 7091, 7101, 7111, 7121, 7131, 7141, 7151, 7161, 7171, 7181, 7191, 7201, 7211,
 7221, 7231, 7241, 7251, 7261, 7271, 7281, 7291, 7301, 7311, 7321, 7331, 7341,
 7351, 7361, 7371, 7381, 7391, 7401, 7411, 7421, 7431, 7441, 7451, 7461, 7471,
 7481, 7491, 7501, 7511, 7521, 7531, 7541, 7551, 7561, 7571, 7581, 7591, 7601,
 7611, 7621, 7631, 7641, 7651, 7661, 7671, 7681, 7691, 7701, 7711, 7721, 7731,
 7741, 7751, 7761, 7771, 7781, 7791, 7801, 7811, 7821, 7831, 7841, 7851, 7861,
 7871, 7881, 7891, 7901, 7911, 7921, 7931, 7941, 7951, 7961, 7971, 7981, 7991,
 8001, 8011, 8021, 8031, 8041, 8051, 8061, 8071, 8081, 8091, 8101, 8111, 8121,
 8131, 8141, 8151, 8161, 8171, 8181, 8191, 8201, 8211, 8221, 8231, 8241, 8251,
 8261, 8271, 8281, 8291, 8301, 8311, 8321, 8331, 8341, 8351, 8361, 8371, 8381,
 8391, 8401, 8411, 8421, 8431, 8441, 8451, 8461, 8471, 8481, 8491, 8501, 8511,
 8521, 8531, 8541, 8551, 8561, 8571, 8581, 8591, 8601, 8611, 8621, 8631, 8641,
 8651, 8661, 8671, 8681, 8691, 8701, 8711, 8721, 8731, 8741, 8751, 8761, 8771,
 8781, 8791, 8801, 8811, 8821, 8831, 8841, 8851, 8861, 8871, 8881, 8891, 8901,
 8911, 8921, 8931, 8941, 8951, 8961, 8971, 8981, 8991, 9001, 9011, 9021, 9031,
 9041, 9051, 9061, 9071, 9081, 9091, 9101, 9111, 9121, 9131, 9141, 9151, 9161,
 9171, 9181, 9191, 9201, 9211, 9221, 9231, 9241, 9251, 9261, 9271, 9281, 9291,
 9301, 9311, 9321, 9331, 9341, 9351, 9361, 9371, 9381, 9391, 9401, 9411, 9421,
 9431, 9441, 9451, 9461, 9471, 9481, 9491, 9501, 9511, 9521, 9531, 9541, 9551,
 9561, 9571, 9581, 9591, 9601, 9611, 9621, 9631, 9641, 9651, 9661, 9671, 9681,
 9691, 9701, 9711, 9721, 9731, 9741, 9751, 9761, 9771, 9781, 9791, 9801, 9811,
 9821, 9831, 9841, 9851, 9861, 9871, 9881, 9891, 9901, 9911, 9921, 9931, 9941,
 9951, 9961, 9971, 9981, 9991]

end
[:before_compile, :on_definition, :external_resource, :derive, :typep, :opaque, :spec,
 :macrocallback, :behaviour, :type, :dialyzer, :after_verify, :compile, :after_compile, :callback,
 :optional_callbacks, :moduledoc]
{:module, Curr.Large, <<70, 79, 82, 49, 0, 1, 172, ...>>, {:all, 1}}
samples = Enum.map(1..100000, fn _ -> Enum.random(1..(range.last + 1000)) end) ++
  Enum.map(1..100000, fn _ -> Enum.random(1..(range.last + 1000)) * 0.5 end)
[10021, 7638, 868, 514, 8402, 10906, 170, 22, 2420, 2681, 10242, 1201, 10957, 10944, 2728, 5589,
 960, 1915, 1455, 6348, 3564, 7579, 8421, 10845, 7259, 2414, 10570, 8334, 26, 6483, 2364, 5478,
 2466, 4528, 2864, 843, 1340, 9531, 9246, 10795, 7054, 3003, 8729, 2019, 8889, 8285, 254, 965, 4392,
 5070, ...]
Benchee.run(%{
  "curr" => &Curr.Small.all/1,
  "fin" =>  &Fin.Small.all/1,
    "lin" =>  &Lin.Small.all/1,
}, inputs: %{"samples" => samples})
Operating System: macOS
CPU Information: Apple M3 Pro
Number of Available Cores: 12
Available memory: 36 GB
Elixir 1.18.4
Erlang 27.3.4.1
JIT enabled: true

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
reduction time: 0 ns
parallel: 1
inputs: samples
Estimated total run time: 21 s

Benchmarking curr with input samples ...
Benchmarking fin with input samples ...
Benchmarking lin with input samples ...
Calculating statistics...
Formatting results...

##### With input samples #####
Name           ips        average  deviation         median         99th %
lin         434.51        2.30 ms     ±7.52%        2.27 ms        2.74 ms
fin         419.93        2.38 ms     ±2.48%        2.38 ms        2.51 ms
curr        331.83        3.01 ms     ±2.00%        3.02 ms        3.20 ms

Comparison: 
lin         434.51
fin         419.93 - 1.03x slower +0.0799 ms
curr        331.83 - 1.31x slower +0.71 ms
Benchee.run(%{
  "curr" => &Curr.Mid.all/1,
  "fin" =>  &Fin.Mid.all/1,
    "lin" =>  &Lin.Mid.all/1,
}, inputs: %{"samples" => samples})
Operating System: macOS
CPU Information: Apple M3 Pro
Number of Available Cores: 12
Available memory: 36 GB
Elixir 1.18.4
Erlang 27.3.4.1
JIT enabled: true

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
reduction time: 0 ns
parallel: 1
inputs: samples
Estimated total run time: 21 s

Benchmarking curr with input samples ...
Benchmarking fin with input samples ...
Benchmarking lin with input samples ...
Calculating statistics...
Formatting results...

##### With input samples #####
Name           ips        average  deviation         median         99th %
fin         248.60        4.02 ms     ±2.72%        4.01 ms        4.38 ms
curr        245.84        4.07 ms     ±3.50%        4.04 ms        4.51 ms
lin         159.43        6.27 ms     ±2.03%        6.25 ms        6.81 ms

Comparison: 
fin         248.60
curr        245.84 - 1.01x slower +0.0451 ms
lin         159.43 - 1.56x slower +2.25 ms
Benchee.run(%{
  "curr" => &Curr.Large.all/1,
  "fin" =>  &Fin.Large.all/1,
    "lin" =>  &Lin.Large.all/1,
}, inputs: %{"samples" => samples})
Operating System: macOS
CPU Information: Apple M3 Pro
Number of Available Cores: 12
Available memory: 36 GB
Elixir 1.18.4
Erlang 27.3.4.1
JIT enabled: true

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
reduction time: 0 ns
parallel: 1
inputs: samples
Estimated total run time: 21 s

Benchmarking curr with input samples ...
Benchmarking fin with input samples ...
Benchmarking lin with input samples ...
Calculating statistics...
Formatting results...

##### With input samples #####
Name           ips        average  deviation         median         99th %
fin         160.73        6.22 ms     ±2.64%        6.17 ms        6.82 ms
curr        159.97        6.25 ms     ±3.97%        6.23 ms        6.96 ms
lin          20.41       48.99 ms     ±2.70%       48.74 ms       55.71 ms

Comparison: 
fin         160.73
curr        159.97 - 1.00x slower +0.0295 ms
lin          20.41 - 7.87x slower +42.77 ms
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment