xref example file

Samuel Rivas <>
Fri May 19 11:32:35 CEST 2006


Torbjorn Tornkvist wrote:
> Nice! (but I couldn't get it to work)
> 
> Has anyone written some nice icing on top of the xref cake?
> I mean a collection of function which setup and executes
> some of useful metrics there are to be gathered from xref?
> The documentation of xref is good but a little bit on the terse side...

Not really a nice profiling application full of flashy metrics, but I
have a sort of template that I use to include in my applications.

Just change my_app for your application name and make my_app_app_path 
return the path to the app file, run my_app_xref:start(), wait, wait a
little more, and run my_app_xref:all(). That <i>should</i> work :)

If you want to profile code that is not in an application you'll need to
change load_my_app to call another kind of xref:add_ function.

Hope it helps
-- 
	Samuel
-------------- next part --------------
%%%-------------------------------------------------------------------
%%% File    : my_app_xref.erl
%%% Author  : Samuel Rivas <>
%%% Description : XREF useful tests for my_app
%%%
%%% Created : 19 May 2006 by Samuel Rivas <>
%%%-------------------------------------------------------------------
-module(my_app_xref).


-module(my_app_xref).

-define(XREF_SERVER, my_app_xref_server).

-export([start/0, stop/0, restart/0, undefined/0, unresolved/0, deprecated/0,
	 unused/0, all/0, reload/0, to/2, to/3]).

start() ->
    {ok, _} = xref:start(?XREF_SERVER),
    load_otp(),

    %% Load anything that your app needs here
    
    load_my_app(),
    ok.

stop() ->
    xref:stop(?XREF_SERVER).

restart() ->
    stop(),
    ok = start().

reload() ->
    unload_my_app(),
    load_my_app().

undefined() ->
    %% Look for wrong function calls (extenal call to a function that does not
    %% exist)
    xref_query("UNDEFINED CALLS",
	       "(XC - UC) | ((Fun) my_app : App) || (XU - X - B)").
unresolved() ->
    %% Look for abstract function calls (they are not errors in compile time,
    %% but it may be useful when searching for failure points)
    xref_query("UNRESOLVED CALLS",
	       "UC | ((Fun) my_app : App) || (XU - X - B)").

deprecated() ->
    %% Look for deprecated functions called from my_app application (the
    %% compiler raises warning on that too)
    xref_query("DEPRECATED CALLS", "E | (Fun) my_app:App || DF").

unused() ->
    %% Look for exported functions that are not used nor in the white list.
    %% UWL is the unused white list and is created by the unused_white_list()
    %% function. It includes all the behaviour callbacks as well as the
    %% custom_white_list functions. You may edit custom_white_list function
    %% or add new module names to gen_events() gen_servers() and supervisors()
    %% functions to avoid very large list ouputs from this function
    %% Functions in this module are automatically whitelisted
    xref_query("UNUSED FUNCTIONS", "(UU * (Fun) my_app:App) - UWL").

to(Module, Function) ->
    to(Module, Function, "_").

to(Module, Function, Arity) when is_integer(Arity) ->
    to(Module, Function, integer_to_list(Arity));
to(Module, Function, Arity) ->
    Title = lists:flatten(io_lib:format("CALLS TO ~p:~p/~s",
					[Module, Function, Arity])),
    Query = lists:flatten(io_lib:format("E | (Fun) my_app:App || ~p:~p/~s",
					[Module, Function, Arity])),
    xref_query(Title, Query).

%% Don't put my_app_ prefix, function_regexp does that for you
gen_servers() ->
    ["conf", "facade", "worker"].

gen_events() ->
    ["logger"].

supervisors() ->
    ["supervisor"].

%% Whitelist assorted functions here
custom_white_list() ->
    "\"my_app.*\":init/1 + \"my_app.*\":debug_stop/0 "
	"+ \"my_app.*\":\"(re)?start_link\"/_ + my_app_conf:save/0 "
	"+ my_app:\"restart|terminate\"/\"0|1\" + my_app_facade:_/_".

all() ->
    undefined(),
    unresolved(),
    deprecated(),
    unused().

%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------

load_otp() ->
    io:format("Loading OTP applications (it may take a while)...~n"),
    {ok, _} = xref:add_release(?XREF_SERVER, code:lib_dir(),
			       [{verbose, false}, {warnings, false},
				{name, otp}]).

load_my_app() ->
    io:format("Loading My_App ...~n"),
    {ok, _} = xref:add_application(?XREF_SERVER, my_app_app_path(),
				   {name, my_app}),

    io:format("Creating unused function white list ...~n"),
    unused_white_list().

unload_my_app() ->
    ok = xref:remove_application(?XREF_SERVER, my_app).

my_app_app_path() ->
    my_app_util:get_home() ++ "/ebin".

xref_query(Message, Query) ->
    {ok, L} = xref:q(?XREF_SERVER, Query),
    io:format("~n~s:~n~n", [Message]),
    print_results(L).

print_results(L) ->
    F = fun({{OMod, OFun, OAr}, {IMod, IFun, IAr}}) ->
		print_call(OMod, OFun, OAr, IMod, IFun, IAr);
	   ({Mod, Fun, Ar}) ->
		print_function(Mod, Fun, Ar)
	end,
    lists:foreach(F, L).

print_call(OMod, OFun, OAr, IMod, IFun, IAr) ->
    io:format("~p:~p/~p -> ~p:~p/~p~n", [OMod, OFun, OAr, IMod, IFun, IAr]).

print_function(Mod, Fun, Ar) ->
    io:format("~p:~p/~p~n", [Mod, Fun, Ar]).

unused_white_list() ->
    xref:forget(?XREF_SERVER, 'UWL'),
    Q = lists:flatten(["UWL:=(", module_regexp(gen_servers()), $:,
		       function_regexp(gen_server_callbacks()), "/_) "
		       "+ (", module_regexp(gen_events()), $:,
		       function_regexp(gen_event_callbacks()), "/_) "
		       "+ (", module_regexp(supervisors()), $:,
		       function_regexp(supervisor_callbacks()), "/_) "
		       "+ (", application_module(), $:,
		       function_regexp(application_callbacks()), "/_) "
		       "+ ", custom_white_list(),
		       "+ (X * (Fun) my_app_xref:Mod)"]),
    {ok, _} = xref:q(?XREF_SERVER,Q),
    ok.

module_regexp([]) ->
    "\"\"";
module_regexp([H|T]) ->
    ["\"my_app_", H, [[$|, gen_server_prefix() | Name] || Name <- T], $"].

% xemacs keeps thinking i'm writing a string until these quotes:"

function_regexp([]) ->
    "\"\"";
function_regexp([H|T]) ->
    [$", H, [[$| | Name] || Name <- T], $"].

gen_server_prefix() ->
    "my_app_".

gen_server_callbacks() ->
    ["code_change", "handle_(call(2)?|cast|info)", "init", "terminate"].

application_module() ->
    "my_app".

application_callbacks() ->
    ["start", "stop"].

gen_event_callbacks() ->
    ["init", "handle_(event|call|info)", "code_change", "terminate"].

supervisor_callbacks() ->
    ["init"].


More information about the erlang-questions mailing list