Current section

Files

Jump to
xprof src xprof_vm_info.erl
Raw

src/xprof_vm_info.erl

-module(xprof_vm_info).
-export([get_available_funs/1]).
%% @doc Return list of existing module/funcion/arity that match query.
%%
%% If query does not contain colon only the global functions
%% (excluding module_info) of all the matching modules are listed.
%% If query contains colon both the global and local functions
%% (excluding generated local functions) are listed of that particular module
%% matching the query.
-spec get_available_funs(binary()) -> [MFA]
when MFA :: list(). %% [module(), atom(), arity()]
get_available_funs(Query) ->
case binary:split(Query, <<":">>) of
[ModBin, Rest] ->
case is_module(ModBin) of
{true, Mod} ->
Funs = get_all_functions(Mod),
[[Mod, Fun, Arity]
|| {Fun, Arity} <- filter_funs(binary_to_list(Rest), Funs)];
false ->
[]
end;
[ModPrefix] ->
[[Mod, Fun, Arity]
|| Mod <- filter_mods(binary_to_list(ModPrefix), get_modules()),
{Fun, Arity} <- get_global_functions(Mod)]
end.
filter_funs(Prefix, Funs) ->
lists:filter(fun({Fun, Arity}) ->
Str = lists:flatten(
[atom_to_list(Fun), $/, integer_to_list(Arity)]),
lists:prefix(Prefix, Str)
end, Funs).
filter_mods(Prefix, Mods) ->
lists:filter(fun(Mod) ->
Str = atom_to_list(Mod),
lists:prefix(Prefix, Str)
end, Mods).
-spec get_global_functions(module()) -> [{atom(), arity()}].
get_global_functions(Mod) ->
[FA || FA = {F, _} <- Mod:module_info(exports), F =/= module_info].
-spec get_all_functions(module()) -> [{atom(), arity()}].
get_all_functions(Mod) ->
%% filter out functions generated for fun objects
%% and list comprehensions like '-filter_funs/2-fun-0-'
[FA || FA = {F, _} <- Mod:module_info(functions), not lists:prefix("-", atom_to_list(F))].
is_module(ModBin) ->
try list_to_existing_atom(binary_to_list(ModBin)) of
Mod ->
case code:is_loaded(Mod) of
{file, _} -> {true, Mod};
false -> false
end
catch error:badarg ->
false
end.
get_modules() ->
ModsFiles = code:all_loaded(),
[ Mod || {Mod, _File} <- ModsFiles].