From d0f34ee2ba069e6fa36a4b438f0761f326327a2e Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Wed, 26 Nov 2025 17:26:07 +0100 Subject: [PATCH 1/2] Optimise seshat:counters/3 If someone uses this function, the list of counters to return is likely very short, quite possibly it has 1 element. Rather than building a map of all counters and then dropping the irrelevant ones, only add the relevant counters in the first place. Testing with RabbitMQ an rabbit_quorum_queue:open_files function, which only asks for 1 metric, the avery execution went down form 7ms to 1ms with this change. --- src/seshat.erl | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/seshat.erl b/src/seshat.erl index 4c8fab5..ee3e46f 100644 --- a/src/seshat.erl +++ b/src/seshat.erl @@ -112,9 +112,28 @@ delete(Group, Id) -> -spec build_counters_map(counters:counters_ref(), fields_spec()) -> #{atom() => integer()}. build_counters_map(CRef, FieldsSpec) -> + build_counters_map(CRef, FieldsSpec, all). + +%% Helper function to build the map of counters for a given CRef and FieldSpec +%% with optional filtering by Names +-spec build_counters_map(counters:counters_ref(), fields_spec(), all | [atom()]) -> + #{atom() => integer()}. +build_counters_map(CRef, FieldsSpec, all) -> + Fields = resolve_fields_spec(FieldsSpec), + lists:foldl(fun ({Name, Index, _Type, _Help}, Acc0) -> + Acc0#{Name => counters:get(CRef, Index)} + end, #{}, Fields); +build_counters_map(CRef, FieldsSpec, Names) when is_list(Names) -> Fields = resolve_fields_spec(FieldsSpec), lists:foldl(fun ({Name, Index, _Type, _Help}, Acc0) -> - Acc0#{Name => counters:get(CRef, Index)} + % the assumption here is that Names is a very + % short list likely of just 1 element + case lists:member(Name, Names) of + true -> + Acc0#{Name => counters:get(CRef, Index)}; + false -> + Acc0 + end end, #{}, Fields). %% @doc Return a map with all metrics of all objects in the group @@ -159,8 +178,7 @@ counters(Group, Id) -> counters(Group, Id, Names) -> case ets:lookup(seshat_counters_server:get_table(Group), Id) of [#entry{cref = CRef, field_spec = FieldsSpec}] -> - AllCountersMap = build_counters_map(CRef, FieldsSpec), - maps:with(Names, AllCountersMap); + build_counters_map(CRef, FieldsSpec, Names); _ -> undefined end. From eb2aec3a57a410298e3cbb679266df1f33f75100 Mon Sep 17 00:00:00 2001 From: Michal Kuratczyk Date: Wed, 26 Nov 2025 18:01:38 +0100 Subject: [PATCH 2/2] Optimise seshat:counters/3 for single-item name list Previous commit sped up single-item invocation from 7ms to 1ms. With this change, it goes down to 0.1ms. --- src/seshat.erl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/seshat.erl b/src/seshat.erl index ee3e46f..f388261 100644 --- a/src/seshat.erl +++ b/src/seshat.erl @@ -123,11 +123,18 @@ build_counters_map(CRef, FieldsSpec, all) -> lists:foldl(fun ({Name, Index, _Type, _Help}, Acc0) -> Acc0#{Name => counters:get(CRef, Index)} end, #{}, Fields); +build_counters_map(CRef, FieldsSpec, [Name]) -> + %% Optimized path for single name lookup + Fields = resolve_fields_spec(FieldsSpec), + case lists:keyfind(Name, 1, Fields) of + {Name, Index, _Type, _Help} -> + #{Name => counters:get(CRef, Index)}; + false -> + #{} + end; build_counters_map(CRef, FieldsSpec, Names) when is_list(Names) -> Fields = resolve_fields_spec(FieldsSpec), lists:foldl(fun ({Name, Index, _Type, _Help}, Acc0) -> - % the assumption here is that Names is a very - % short list likely of just 1 element case lists:member(Name, Names) of true -> Acc0#{Name => counters:get(CRef, Index)};