From de386424d637dcf117a25121ab003e55e05c6d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Niemier?= <~@hauleth.dev> Date: Tue, 17 Feb 2026 00:01:18 +0100 Subject: [PATCH] Optimise generated module to avoid calling external functions This reduces need for (relatively) expensive `Map.take/2` and `Map.merge/2` calls if these aren't needed. It also traverses metric list with internally defined function to avoid lambda and external function call. --- lib/peep/codegen.ex | 77 +++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/lib/peep/codegen.ex b/lib/peep/codegen.ex index 9151a20..3871614 100644 --- a/lib/peep/codegen.ex +++ b/lib/peep/codegen.ex @@ -12,7 +12,7 @@ defmodule Peep.Codegen do module_name = module(name) handle_event_ast = build_handle_event_ast(name) - other_funs_ast = other_funs_ast() + other_funs_ast = other_funs_ast(global_tags) module_ast = quote do @@ -40,43 +40,48 @@ defmodule Peep.Codegen do defp build_handle_event_ast(peep_name) do quote do def handle_event(event, measurements, metadata, _) do - global_tags = global_tags() - persistent( events_to_metrics: %{^event => metrics}, storage: {storage_mod, storage} ) = fast_fetch(unquote(peep_name)) - :lists.foreach( - fn {metric, id} -> - %{ - measurement: measurement, - tag_values: tag_values, - tags: tags, - keep: keep - } = metric - - if keep?(keep, metadata, measurement) do - # credo:disable-for-next-line Credo.Check.Refactor.Nesting - case fetch_measurement(measurement, measurements, metadata) do - value when is_number(value) -> - tag_values = tag_values.(metadata) - tags = Map.merge(global_tags, Map.take(tag_values, tags)) - storage_mod.insert_metric(storage, id, metric, value, tags) - - _ -> - nil - end - end - end, - metrics - ) + store_metrics(metrics, measurements, metadata, storage_mod, storage) + end + + defp store_metrics([], _measurements, _metadata, _mod, _data), do: :ok + + defp store_metrics([{metric, id} | rest], measurements, metadata, mod, data) do + %{ + measurement: measurement, + tag_values: tag_values, + tags: tags, + keep: keep + } = metric + + if keep?(keep, metadata, measurement) do + # credo:disable-for-next-line Credo.Check.Refactor.Nesting + case fetch_measurement(measurement, measurements, metadata) do + value when is_number(value) -> + mod.insert_metric( + data, + id, + metric, + value, + meta(metadata, tag_values, tags) + ) + + _ -> + nil + end + end + + store_metrics(rest, measurements, metadata, mod, data) end end end # credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity - defp other_funs_ast() do + defp other_funs_ast(global_tags) do quote do defp keep?(keep, metadata, measurement) when is_function(keep, 2), do: keep.(metadata, measurement) @@ -84,6 +89,20 @@ defmodule Peep.Codegen do defp keep?(keep, metadata, _measurement) when is_function(keep, 1), do: keep.(metadata) defp keep?(_keep, _metadata, _measurement), do: true + # When tags are empty, just return global tags + defp meta(tags, _map, _keys) when tags == %{}, do: global_tags() + # When selected list is empty, just return global tags + defp meta(_tags, _map, []), do: global_tags() + + # Try to avoid calling `Map.merge/2` if not needed + if unquote(global_tags == %{}) do + defp meta(meta, _map, tags) when is_function(tags, 1), do: tags.(meta) + defp meta(tags, map, keys), do: Map.take(map.(tags), keys) + else + defp meta(meta, _map, tags) when is_function(tags, 1), do: Map.merge(global_tags(), tags.(meta)) + defp meta(tags, map, keys), do: Map.merge(global_tags(), Map.take(map.(tags), keys)) + end + defp fetch_measurement(%Telemetry.Metrics.Counter{}, _measurements, _metadata) do 1 end @@ -101,8 +120,6 @@ defmodule Peep.Codegen do key -> case measurements do - %{^key => nil} -> 1 - %{^key => false} -> 1 %{^key => value} -> value _ -> 1 end