diff --git a/src/recon.erl b/src/recon.erl index 1a16c74..9ee79ae 100644 --- a/src/recon.erl +++ b/src/recon.erl @@ -316,16 +316,21 @@ proc_window(AttrName, Num, Time) -> %% for more details on refc binaries -spec bin_leak(pos_integer()) -> [proc_attrs()]. bin_leak(N) -> - Procs = recon_lib:sublist_top_n_attrs([ - try - {ok, {_,Pre,Id}} = recon_lib:proc_attrs(binary, Pid), - erlang:garbage_collect(Pid), - {ok, {_,Post,_}} = recon_lib:proc_attrs(binary, Pid), - {Pid, length(Pre) - length(Post), Id} - catch - _:_ -> {Pid, 0, []} - end || Pid <- processes() - ], N), + Procs = recon_lib:sublist_top_n_attrs( + recon_lib:fold_processes( + fun(Pid, Acc) -> + Result = try + {ok, {_,Pre,Id}} = recon_lib:proc_attrs(binary, Pid), + erlang:garbage_collect(Pid), + {ok, {_,Post,_}} = recon_lib:proc_attrs(binary, Pid), + {Pid, length(Pre) - length(Post), Id} + catch + _:_ -> {Pid, 0, []} + end, + [Result | Acc] + end, + [] + ), N), [{Pid, -Val, Id} ||{Pid, Val, Id} <-Procs]. %% @doc Shorthand for `node_stats(N, Interval, fun(X,_) -> io:format("~p~n",[X]) end, nostate)'. diff --git a/src/recon_lib.erl b/src/recon_lib.erl index 76140c5..8af2bfa 100644 --- a/src/recon_lib.erl +++ b/src/recon_lib.erl @@ -13,7 +13,8 @@ term_to_port/1, time_map/5, time_fold/6, scheduler_usage_diff/2, - sublist_top_n_attrs/2]). + sublist_top_n_attrs/2, + fold_processes/2]). %% private exports -export([binary_memory/1]). @@ -73,15 +74,45 @@ port_list(Attr, Val) -> [Port || Port <- erlang:ports(), {Attr, Val} =:= erlang:port_info(Port, Attr)]. +%% @doc Fold over all processes, using efficient iterator when available (OTP 28+). +-spec fold_processes(Fun, Acc0) -> Acc when + Fun :: fun((pid(), Acc) -> Acc), + Acc0 :: Acc, + Acc :: term(). +fold_processes(Fun, Acc0) -> + try + Iter = erlang:processes_iterator(), + fold_processes_iter(Fun, Acc0, Iter) + catch + error:undef -> + lists:foldl(Fun, Acc0, processes()) + end. + +fold_processes_iter(Fun, Acc, Iter) -> + case erlang:processes_next(Iter) of + {Pid, NewIter} -> + NewAcc = Fun(Pid, Acc), + fold_processes_iter(Fun, NewAcc, NewIter); + none -> + Acc + end. + %% @doc Returns the attributes ({@link recon:proc_attrs()}) of %% all processes of the node, except the caller. -spec proc_attrs(term()) -> [recon:proc_attrs()]. proc_attrs(AttrName) -> Self = self(), - [Attrs || Pid <- processes(), - Pid =/= Self, - {ok, Attrs} <- [proc_attrs(AttrName, Pid)] - ]. + fold_processes( + fun(Pid, Acc) when Pid =/= Self -> + case proc_attrs(AttrName, Pid) of + {ok, Attrs} -> [Attrs | Acc]; + {error, _} -> Acc + end; + (_, Acc) -> + Acc + end, + [] + ). %% @doc Returns the attributes of a given process. This form of attributes %% is standard for most comparison functions for processes in recon. @@ -288,5 +319,3 @@ merge(H1, [E2|H2]) -> [E2, H1|H2]. merge_pairs([]) -> []; merge_pairs([H]) -> H; merge_pairs([A, B|T]) -> merge(merge(A, B), merge_pairs(T)). - -