From 75b6417b4d8fa68d565ad942d55f5da74280ef93 Mon Sep 17 00:00:00 2001 From: hissssst Date: Sat, 14 Dec 2024 10:05:41 +0100 Subject: [PATCH 1/2] Hot path optimizations --- lib/peep/buckets/custom.ex | 94 ++++++++++++++++++++++++++++++++----- lib/peep/event_handler.ex | 32 +++++++++---- lib/peep/storage/striped.ex | 4 +- 3 files changed, 109 insertions(+), 21 deletions(-) diff --git a/lib/peep/buckets/custom.ex b/lib/peep/buckets/custom.ex index aa7a23d..ae4f9cd 100644 --- a/lib/peep/buckets/custom.ex +++ b/lib/peep/buckets/custom.ex @@ -34,22 +34,95 @@ defmodule Peep.Buckets.Custom do end end + ## Bucket binary search + defp bucket_for_ast(buckets) do - bucket_defns = - for {boundary, bucket_idx} <- Enum.with_index(buckets) do - quote do - def bucket_for(n, _) when n < unquote(boundary), do: unquote(bucket_idx) - end + int_buckets = int_buckets(buckets, nil, 0) + + float_buckets = + buckets + |> Enum.map(&(&1 * 1.0)) + |> Enum.with_index() + + variable = Macro.var(:x, nil) + + int_length = length(int_buckets) + int_tree = build_bucket_tree(int_buckets, int_length, length(buckets), variable) + + float_length = length(float_buckets) + float_tree = build_bucket_tree(float_buckets, float_length, length(buckets), variable) + + quote do + def bucket_for(unquote(variable), _) when is_integer(unquote(variable)) do + unquote(int_tree) end - final_defn = - quote do - def bucket_for(_, _), do: unquote(length(buckets)) + def bucket_for(unquote(variable), _) when is_float(unquote(variable)) do + unquote(float_tree) end + end - bucket_defns ++ [final_defn] + # |> 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 + + defp int_buckets([], _prev, _counter) do + [] + end + + defp int_buckets([curr | tail], prev, counter) do + case ceil(curr) do + ^prev -> int_buckets(tail, prev, counter + 1) + curr -> [{curr, counter} | int_buckets(tail, curr, counter + 1)] + end + end + + ## Upper bound + defp upper_bound_ast(buckets) do bucket_defns = for {boundary, bucket_idx} <- Enum.with_index(buckets) do @@ -67,7 +140,6 @@ defmodule Peep.Buckets.Custom do end defp int_to_float_string(int) do - # kind of a hack, but nothing else came to mind - to_string(:math.pow(int, 1)) + to_string(int * 1.0) end end diff --git a/lib/peep/event_handler.ex b/lib/peep/event_handler.ex index 21e614f..bc8b884 100644 --- a/lib/peep/event_handler.ex +++ b/lib/peep/event_handler.ex @@ -2,6 +2,8 @@ defmodule Peep.EventHandler do @moduledoc false require Logger + @compile :inline + alias Telemetry.Metrics.{Counter, Summary, Distribution} def attach(metrics, name, global_tags) do @@ -28,7 +30,7 @@ defmodule Peep.EventHandler do end def detach(handler_ids) do - Enum.each(handler_ids, fn id -> :telemetry.detach(id) end) + for id <- handler_ids, do: :telemetry.detach(id) end def handle_event(_event, measurements, metadata, %{ @@ -37,12 +39,19 @@ defmodule Peep.EventHandler do global_tags: global_tags }) do for metric <- metrics do - if value = keep?(metric, metadata) && fetch_measurement(metric, measurements, metadata) do + %{ + measurement: measurement, + tag_values: tag_values, + tags: tags, + keep: keep + } = metric + + if value = keep?(keep, metadata) && fetch_measurement(measurement, measurements, metadata) do tag_values = global_tags - |> Map.merge(metric.tag_values.(metadata)) + |> Map.merge(tag_values.(metadata)) - tags = Map.new(metric.tags, &{&1, Map.get(tag_values, &1, "")}) + tags = Map.new(tags, &{&1, Map.get(tag_values, &1, "")}) Peep.insert_metric(name, metric, value, tags) end @@ -53,15 +62,15 @@ defmodule Peep.EventHandler do {__MODULE__, peep_name, event_name} end - defp keep?(%{keep: nil}, _metadata), do: true - defp keep?(%{keep: keep}, metadata), do: keep.(metadata) + defp keep?(nil, _metadata), do: true + defp keep?(keep, metadata), do: keep.(metadata) defp fetch_measurement(%Counter{}, _measurements, _metadata) do 1 end - defp fetch_measurement(metric, measurements, metadata) do - case metric.measurement do + defp fetch_measurement(measurement, measurements, metadata) do + case measurement do nil -> nil @@ -72,7 +81,12 @@ defmodule Peep.EventHandler do fun.(measurements, metadata) key -> - measurements[key] || 1 + case measurements do + %{^key => nil} -> 1 + %{^key => false} -> 1 + %{^key => value} -> value + _ -> 1 + end end end diff --git a/lib/peep/storage/striped.ex b/lib/peep/storage/striped.ex index e22123b..8c7ebfb 100644 --- a/lib/peep/storage/striped.ex +++ b/lib/peep/storage/striped.ex @@ -7,6 +7,8 @@ defmodule Peep.Storage.Striped do @type tids() :: %{pos_integer() => :ets.tid()} + @compile :inline + @spec new() :: tids() @impl true def new() do @@ -47,7 +49,7 @@ defmodule Peep.Storage.Striped do def insert_metric(tids, %Metrics.LastValue{} = metric, value, %{} = tags) do tid = get_tid(tids) - now = System.monotonic_time() + now = :erlang.monotonic_time() key = {metric, tags} :ets.insert(tid, {key, {now, value}}) end From cba7aca7e4877c96549b8a37d51a595824126b8c Mon Sep 17 00:00:00 2001 From: Hissssst <37012324+hissssst@users.noreply.github.com> Date: Sat, 14 Dec 2024 12:41:58 +0000 Subject: [PATCH 2/2] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Valim --- lib/peep/event_handler.ex | 1 + lib/peep/storage/striped.ex | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/peep/event_handler.ex b/lib/peep/event_handler.ex index bc8b884..6de54ba 100644 --- a/lib/peep/event_handler.ex +++ b/lib/peep/event_handler.ex @@ -31,6 +31,7 @@ defmodule Peep.EventHandler do def detach(handler_ids) do for id <- handler_ids, do: :telemetry.detach(id) + :ok end def handle_event(_event, measurements, metadata, %{ diff --git a/lib/peep/storage/striped.ex b/lib/peep/storage/striped.ex index 8c7ebfb..df6621d 100644 --- a/lib/peep/storage/striped.ex +++ b/lib/peep/storage/striped.ex @@ -49,7 +49,7 @@ defmodule Peep.Storage.Striped do def insert_metric(tids, %Metrics.LastValue{} = metric, value, %{} = tags) do tid = get_tid(tids) - now = :erlang.monotonic_time() + now = System.monotonic_time() key = {metric, tags} :ets.insert(tid, {key, {now, value}}) end