%% -*- erlang -*-
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
-mode(compile).
main(_) ->
DisDir = "./dis",
ok = filelib:ensure_dir(filename:join(DisDir, "dummy")),
io:format("Dissambling to ~s\n", [DisDir]),
ok = file:set_cwd(DisDir),
Path = code:get_path() -- ["."],
Beams0 = [filelib:wildcard(filename:join(Dir, "*.beam")) ||
Dir <- Path],
Beams = lists:append(Beams0),
Mods0 = [list_to_atom(filename:rootname(filename:basename(F))) ||
F <- Beams],
Mods = lists:usort(Mods0),
start_sem(),
Ps = [begin
{_,Ref} = spawn_monitor(fun() -> count(M) end),
Ref
end || M <- Mods],
[put(list_to_atom(I), 0) || I <- erts_debug:instructions()],
Res = wait_for_all(Ps, 1),
OutFile = "count",
{ok,Out} = file:open(OutFile, [write]),
[io:format(Out, "~s ~p\n", [I,C]) || {I,C} <- Res],
ok = file:close(Out),
io:format("\nResult written to ~s\n",
[filename:join(DisDir, OutFile)]),
ok.
wait_for_all([], _) ->
lists:reverse(lists:keysort(2, get()));
wait_for_all([_|_]=Ps, I) ->
receive
{'DOWN',Ref,process,_,Result} ->
io:format("\r~p", [I]),
[increment(Key, Count) || {Key,Count} <- Result],
wait_for_all(Ps -- [Ref], I+1)
end.
count(M) ->
down(),
erts_debug:df(M),
{ok,Fd} = file:open(atom_to_list(M) ++ ".dis", [read,raw]),
count_is(Fd),
ok = file:close(Fd),
exit(get()).
count_is(Fd) ->
case file:read_line(Fd) of
{ok,Line} ->
count_instr(Line),
count_is(Fd);
eof ->
ok
end.
count_instr([$\s|T]) ->
count_instr_1(T, []);
count_instr([_|T]) ->
count_instr(T);
count_instr([]) ->
%% Empty line.
ok.
count_instr_1([$\s|_], Acc) ->
Instr = list_to_atom(lists:reverse(Acc)),
increment(Instr, 1);
count_instr_1([H|T], Acc) ->
count_instr_1(T, [H|Acc]).
increment(Key, Inc) ->
case get(Key) of
undefined ->
put(Key, Inc);
Count ->
put(Key, Count+Inc)
end.
%%%
%%% Counting sempahore to limit the number of processes that
%%% can run concurrently.
%%%
down() ->
sem ! {down,self()},
receive
sem_taken -> ok
end.
start_sem() ->
spawn(fun() ->
register(sem, self()),
process_flag(trap_exit, true),
do_sem(erlang:system_info(schedulers)+1) end).
do_sem(0) ->
receive
{'EXIT',_,_} ->
do_sem(1)
end;
do_sem(C) ->
receive
{down,Pid} ->
link(Pid),
Pid ! sem_taken,
do_sem(C-1)
end.