diff --git a/.gitignore b/.gitignore index 1b522f7..d1f2a59 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ ebin/* *.svg *.out erl_crash.dump +.rebar diff --git a/README.md b/README.md index 22d7d97..71632e9 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ Make sure to check out his talk, [Actively Measuring And Profiling Erlang Code]( Usage example: https://github.com/proger/active/commit/81e7e40c9dc5a4666742636ea4c5dfafc41508a5 ```erlang -> eflame:apply(normal_with_children, "stacks.out", my_module, awesome_calculation, []). +> eflame:apply(my_module, awesome_calculation, [], #{mode => normal_with_children, output_file => "stacks.out"}). > eflame:apply(my_module, awesome_calculation, []). % same as above > eflame:apply(fun my_module:awesome_calculation/0, []). % same as above > eflame:apply(fun awesome_calculation/0, []). % same as above, when called in my_module.erl -> eflame:apply(normal, "stacks.out", my_module, awesome_calculation, []). % won't trace children +> eflame:apply(my_module, awesome_calculation, [], #{mode => normal, output_file => "stacks.out"}). % won't trace children ``` ```sh diff --git a/src/eflame.erl b/src/eflame.erl index c19c730..939e584 100644 --- a/src/eflame.erl +++ b/src/eflame.erl @@ -1,33 +1,34 @@ -module(eflame). -export([apply/2, apply/3, - apply/4, - apply/5]). + apply/4]). -define(RESOLUTION, 1000). %% us -record(dump, {stack=[], us=0, acc=[]}). % per-process state -define(DEFAULT_MODE, normal_with_children). -define(DEFAULT_OUTPUT_FILE, "stacks.out"). +-define(DEFAULT_OPTIONS, #{timeout => 5000, mode => ?DEFAULT_MODE, output_file => ?DEFAULT_OUTPUT_FILE}). apply(F, A) -> - apply1(?DEFAULT_MODE, ?DEFAULT_OUTPUT_FILE, {F, A}). + apply1({F, A}, ?DEFAULT_OPTIONS). -apply(M, F, A) -> - apply1(?DEFAULT_MODE, ?DEFAULT_OUTPUT_FILE, {{M, F}, A}). +apply(F, A, O) when is_map(O) -> + apply1({F, A}, O); -apply(Mode, OutputFile, Fun, Args) -> - apply1(Mode, OutputFile, {Fun, Args}). +apply(M, F, A) -> + apply1({{M, F}, A}, ?DEFAULT_OPTIONS). -apply(Mode, OutputFile, M, F, A) -> - apply1(Mode, OutputFile, {{M, F}, A}). +apply(M, F, A, O) when is_map(O) -> + apply1({{M, F}, A}, O). -apply1(Mode, OutputFile, {Fun, Args}) -> +apply1({Fun, Args}, Options) -> Tracer = spawn_tracer(), + #{timeout := Timeout, mode := Mode, output_file := OutputFile} = maps:merge(?DEFAULT_OPTIONS, Options), start_trace(Tracer, self(), Mode), Return = (catch apply_fun(Fun, Args)), - {ok, Bytes} = stop_trace(Tracer, self()), + {ok, Bytes} = stop_trace(Tracer, self(), Timeout), ok = file:write_file(OutputFile, Bytes), Return. @@ -44,12 +45,12 @@ start_trace(Tracer, Target, Mode) -> erlang:trace(Target, true, [{tracer, Tracer} | trace_flags(Mode)]), ok. -stop_trace(Tracer, Target) -> +stop_trace(Tracer, Target, Timeout) -> erlang:trace(Target, false, [all]), Tracer ! {dump_bytes, self()}, Ret = receive {bytes, B} -> {ok, B} - after 5000 -> {error, timeout} + after Timeout -> {error, timeout} end, exit(Tracer, normal),