%% -*- 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.