📄 fprof.erl
字号:
end, sort = case Sort of [] -> acc; [{sort, acc}] -> acc; [{sort, own}] -> own; _ -> erlang:fault(badarg, [Options]) end, totals = case Totals of [] -> false; [totals] -> true; [{totals, true}] -> true; [{totals, false}] -> false; _ -> erlang:fault(badarg, [Options]) end, details = case {Details, NoDetails} of {[], []} -> true; {[details], []} -> true; {[{details, true}], []} -> true; {[{details, false}], []} -> false; {[], [no_details]} -> false; _ -> erlang:fault(badarg, [Options]) end}); _ -> erlang:fault(badarg, [Options]) end;analyse(Options) -> erlang:fault(badarg, [Options]).%%----------------%% Debug functions%%----------------get_state() -> just_call(#get_state{}).save_profile() -> save_profile([]).save_profile(Option, Value) when is_atom(Option) -> save_profile([{Option, Value}]);save_profile(Option, Value) -> erlang:fault(badarg, [Option, Value]).save_profile(Option) when is_atom(Option) -> save_profile([Option]);save_profile(Options) when is_list(Options) -> case getopts(Options, [file]) of {[File], []} -> call(#save_profile{file = case File of [] -> ?PROFILE_FILE; [{file, F}] -> F; _ -> erlang:fault(badarg, [Options]) end}); _ -> erlang:fault(badarg, [Options]) end;save_profile(Options) -> erlang:fault(badarg, [Options]).load_profile() -> load_profile([]).load_profile(Option, Value) when is_atom(Option) -> load_profile([{Option, Value}]);load_profile(Option, Value) -> erlang:fault(badarg, [Option, Value]).load_profile(Option) when is_atom(Option) -> load_profile([Option]);load_profile(Options) when is_list(Options) -> case getopts(Options, [file]) of {[File], []} -> call(#load_profile{file = case File of [] -> ?PROFILE_FILE; [{file, F}] -> F; _ -> erlang:fault(badarg, [Options]) end}); _ -> erlang:fault(badarg, [Options]) end;load_profile(Options) -> erlang:fault(badarg, [Options]).code_change() -> just_call('$code_change').%%%----------------------------------------------------------------------%%% ETS table record definitions%%% The field 'id' must be first in these records;%%% it is the common ets table index field.%%%-----------------------------------------------------------------------record(clocks, { id, cnt = 0, % Number of calls own = 0, % Own time (wall clock) acc = 0}). % Accumulated time : own + subfunctions (wall clock)-record(proc, { id, parent, spawned_as, % Spawned MFArgs init_log = [], % List of first calls, head is newest init_cnt = 2}). % First calls counter, counts down to 0-record(misc, {id, data}).%% Analysis summary record-record(funcstat, { callers_sum, % #clocks{id = {Pid, Caller, Func}} called_sum, % #clocks{id = {Pid, Caller, Func}} callers = [], % [#clocks{}, ...] called = []}). % [#clocks{}, ...]%%%----------------------------------------------------------------------%%% ?FPROF_SERVER%%%----------------------------------------------------------------------%%%-------------------%%% Exported functions%%%-------------------%% Start server processstart() -> spawn_3step( fun () -> try register(?FPROF_SERVER, self()) of true -> process_flag(trap_exit, true), {{ok, self()}, loop} catch error:badarg -> {{error, {already_started, whereis(?FPROF_SERVER)}}, already_started} end end, fun (X) -> X end, fun (loop) -> put(trace_state, idle), put(profile_state, {idle, undefined}), put(pending_stop, []), server_loop([]); (already_started) -> ok end).%% Stop server processstop() -> stop(normal).stop(kill) -> case whereis(?FPROF_SERVER) of undefined -> ok; Pid -> exit(Pid, kill), ok end;stop(Reason) -> just_call(#stop{reason = Reason}), ok.%%%------------------------%%% Client helper functions%%%------------------------%% Send request to server process and return the server's reply.%% First start server if it ain't started.call(Request) -> case whereis(?FPROF_SERVER) of undefined -> start(), just_call(Request); Server -> just_call(Server, Request) end.%% Send request to server process, and return the server's reply.%% Returns {'EXIT', Pid, Reason} if the server dies during the%% call, or if it wasn't started.just_call(Request) -> just_call(whereis(?FPROF_SERVER), Request).just_call(undefined, _) -> {'EXIT', ?FPROF_SERVER, noproc};just_call(Pid, Request) -> Mref = erlang:monitor(process, Pid), receive {'DOWN', Mref, _, _, Reason} -> {'EXIT', Pid, Reason} after 0 -> Tag = {Mref, self()}, {T, Demonitor} = case Request of #stop{} -> {?FPROF_SERVER_TIMEOUT, false}; _ -> {0, true} end, %% io:format("~p request: ~p~n", [?MODULE, Request]), catch Pid ! {?FPROF_SERVER, Tag, Request}, receive {?FPROF_SERVER, Mref, Reply} -> case Demonitor of true -> erlang:demonitor(Mref); false -> ok end, receive {'DOWN', Mref, _, _, _} -> ok after T -> ok end, Reply; {'DOWN', Mref, _, _, Reason} -> receive {?FPROF_SERVER, Mref, _} -> ok after T -> ok end, {'EXIT', Pid, Reason} after ?FPROF_SERVER_TIMEOUT -> timeout end end.%%%------------------------%%% Server helper functions%%%------------------------%% Return the reply to the client's request.reply({Mref, Pid}, Reply) when is_reference(Mref), is_pid(Pid) -> catch Pid ! {?FPROF_SERVER, Mref, Reply}, ok.server_loop(State) -> receive {?FPROF_SERVER, {Mref, Pid} = Tag, '$code_change'} when is_reference(Mref), is_pid(Pid) -> reply(Tag, ok), ?MODULE:'$code_change'(State); {?FPROF_SERVER, {Mref, Pid} = Tag, Request} when is_reference(Mref), is_pid(Pid) -> server_loop(handle_req(Request, Tag, State)); Other -> server_loop(handle_other(Other, State)) end.%-export.'$code_change'(State) -> case lists:keysearch(time, 1, module_info(compile)) of {value, {time, {Y, M, D, HH, MM, SS}}} -> io:format("~n~w: code change to compile time " ++"~4..0w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w~n", [?MODULE, Y, M, D, HH, MM, SS]); false -> ok end, server_loop(State).%% Server help function that stops the server iff the%% sub state machines are in proper states. Sends the reply%% to all waiting clients.try_pending_stop(State) -> case {get(trace_state), get(profile_state), get(pending_stop)} of {idle, {idle, _}, [_|_] = PendingStop} -> Reason = get(stop_reason), Reply = result(Reason), lists:foreach( fun (Tag) -> reply(Tag, Reply) end, PendingStop), exit(Reason); _ -> State end.%%------------------%% Server handle_req %%------------------handle_req(#trace_start{procs = Procs, mode = Mode, type = file, dest = Filename}, Tag, State) -> case {get(trace_state), get(pending_stop)} of {idle, []} -> trace_off(), Port = open_dbg_trace_port(file, Filename), case trace_on(Procs, Port, Mode) of ok -> put(trace_state, running), put(trace_type, file), put(trace_pid, Port), reply(Tag, ok), State; Error -> reply(Tag, Error), State end; _ -> reply(Tag, {error, already_tracing}), State end;handle_req(#trace_start{procs = Procs, mode = Mode, type = tracer, dest = Tracer}, Tag, State) -> case {get(trace_state), get(pending_stop)} of {idle, []} -> trace_off(), case trace_on(Procs, Tracer, Mode) of ok -> put(trace_state, running), put(trace_type, tracer), put(trace_pid, Tracer), reply(Tag, ok), State; Error -> reply(Tag, Error), State end; _ -> reply(Tag, {error, already_tracing}), State end;handle_req(#trace_stop{}, Tag, State) -> case get(trace_state) of running -> TracePid = get(trace_pid), trace_off(), case erase(trace_type) of file -> catch erlang:port_close(TracePid), put(trace_state, stopping), put(trace_tag, Tag), State; tracer -> erase(trace_pid), put(trace_state, idle), case {get(profile_state), get(profile_type), get(profile_pid)} of {running, tracer, TracePid} -> exit(TracePid, normal), put(profile_tag, Tag), State; _ -> reply(Tag, ok), try_pending_stop(State) end end; _ -> reply(Tag, {error, not_tracing}), State end;handle_req(#profile{src = Filename, group_leader = GroupLeader, dump = Dump, flags = Flags}, Tag, State) -> case {get(profile_state), get(pending_stop)} of {{idle, _}, []} -> case ensure_open(Dump, [write | Flags]) of {already_open, DumpPid} -> put(profile_dump, DumpPid), put(profile_close_dump, false); {ok, DumpPid} -> put(profile_dump, DumpPid), put(profile_close_dump, true); {error, _} = Error -> reply(Tag, Error), State end, Table = ets:new(?MODULE, [set, public, {keypos, #clocks.id}]), Pid = spawn_link_dbg_trace_client(Filename, Table, GroupLeader, get(profile_dump)), put(profile_state, running), put(profile_type, file), put(profile_pid, Pid), put(profile_tag, Tag), put(profile_table, Table), State; _ -> reply(Tag, {error, already_profiling}), State end; handle_req(#profile_start{group_leader = GroupLeader, dump = Dump, flags = Flags}, Tag, State) -> case {get(profile_state), get(pending_stop)} of {{idle, _}, []} -> case ensure_open(Dump, [write | Flags]) of {already_open, DumpPid} -> put(profile_dump, DumpPid), put(profile_close_dump, false); {ok, DumpPid} -> put(profile_dump, DumpPid), put(profile_close_dump, true); {error, _} = Error -> reply(Tag, Error), State end, Table = ets:new(?MODULE, [set, public, {keypos, #clocks.id}]), Pid = spawn_link_trace_client(Table, GroupLeader, get(profile_dump)), put(profile_state, running), put(profile_type, tracer), put(profile_pid, Pid), put(profile_table, Table), reply(Tag, {ok, Pid}), State; _ -> reply(Tag, {error, already_profiling}), State end;handle_req(#profile_stop{}, Tag, State) -> case {get(profile_state), get(profile_type)} of {running, tracer} -> ProfilePid = get(profile_pid), case {get(trace_state), get(trace_type), get(trace_pid)} of {running, tracer, ProfilePid} -> trace_off(), erase(trace_type), erase(trace_pid), put(trace_state, idle); _ -> ok end, exit(ProfilePid, normal), put(profile_tag, Tag), State; {running, file} -> reply(Tag, {error, profiling_file}), State; {_, _} -> reply(Tag, {error, not_profiling}), State end;handle_req(#analyse{dest = Dest,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -