Skip to content

Instantly share code, notes, and snippets.

@maxlapshin
Last active September 19, 2019 13:08
Show Gist options
  • Save maxlapshin/bab46e137d81460672d133bf0cb46a16 to your computer and use it in GitHub Desktop.
Save maxlapshin/bab46e137d81460672d133bf0cb46a16 to your computer and use it in GitHub Desktop.
-module(ems_debug_reductions).
-record(red_state, {
pids,
messages = [],
total_reductions = 0
}).
reductions() ->
reductions(#{time => 2000}).
reductions(Opts) ->
#{time := Time} = maps:merge(#{time => 2000}, Opts),
spawn_link(fun() ->
erlang:send_after(Time, self(), stop),
{R1,_} = erlang:statistics(reductions),
{_,My1} = process_info(self(),reductions),
T1 = erlang:system_time(milli_seconds),
erlang:trace(all, true, [running]),
#red_state{} = RS = reduction_loop(#red_state{pids = dict:new()}),
{R2,_} = erlang:statistics(reductions),
{_,My2} = process_info(self(),reductions),
T2 = erlang:system_time(milli_seconds),
io:format("total reductions: ~p(~p), time: ~p", [R2-R1 - (My2-My1), RS#red_state.total_reductions , T2-T1]),
ok
end).
reduction_loop(#red_state{pids = Pids, messages = Acc} = RS) ->
Msg = receive M -> M end,
case Msg of
stop ->
[io:format("~p\n",[A]) || A <- lists:sublist(lists:reverse(Acc), 1, 1000)],
io:format("total ~p messages\n\n", [length(Acc)]),
Pids1 = lists:map(fun({Pid,#{start_reductions := R1, name := Name} = Info}) ->
R2 = maps:get(end_reductions, Info, R1),
{R2-R1,Pid,Name}
end, dict:to_list(Pids)),
Pids2 = lists:reverse(lists:sort(Pids1)),
Reds = lists:foldl(fun({R,Pid,Name}, Num) ->
io:format("~p ~p ~p\n", [Pid, Name, R]),
R + Num
end, 0, Pids2),
RS#red_state{total_reductions = Reds};
{trace,Pid,IO,_} when IO == in orelse IO == out ->
RS1 = case erlang:process_info(Pid,[reductions,dictionary,registered_name]) of
undefined ->
RS;
[{reductions, Reds},{dictionary,Dict},{registered_name,RName}] ->
DictName = proplists:get_value(name,Dict),
DictMFA = proplists:get_value(mfa,Dict),
Name = if
DictName =/= undefined -> DictName;
RName =/= "" -> RName;
DictMFA =/= undefined -> DictMFA;
true -> undefined
end,
Pids1 = case dict:find(Pid,Pids) of
{ok, Info} ->
Name1 = case Name of
undefined -> maps:get(name,Info,undefined);
_ -> Name
end,
dict:store(Pid, Info#{end_reductions => Reds, name => Name1}, Pids);
error ->
Name1 = case Name of
undefined -> process_info(Pid,[current_stacktrace,dictionary]);
_ -> Name
end,
dict:store(Pid, #{start_reductions => Reds, name => Name1}, Pids)
end,
RS#red_state{pids = Pids1}
end,
reduction_loop(RS1);
_ ->
reduction_loop(RS#red_state{messages = [Msg|Acc]})
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment