View Source Profiler (Profiler v0.4.1)
This package contains a couple of profiling shell scripts to aid live-system investigation. Among them:
- Easy performance visualization using kcachegrind
- Shell information using a sampling provider
- Memory information
This sampling profiler is intendend for shell and remote shell usage. Most commands here print their results to the screen for human inspection.
Example usage:
iex(2)> Profiler.profile("<0.187.0>")
100% {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 249]}
100% {IEx.Evaluator, :init, 4, [file: 'lib/iex/evaluator.ex', line: 27]}
100% {IEx.Evaluator, :loop, 1, [file: 'lib/iex/evaluator.ex', line: 103]}
100% {IEx.Evaluator, :eval, 3, [file: 'lib/iex/evaluator.ex', line: 217]}
100% {IEx.Evaluator, :do_eval, 3, [file: 'lib/iex/evaluator.ex', line: 239]}
100% {IEx.Evaluator, :handle_eval, 5, [file: 'lib/iex/evaluator.ex', line: 258]}
100% {:elixir, :eval_forms, 3, [file: 'src/elixir.erl', line: 263]}
100% {:elixir, :recur_eval, 3, [file: 'src/elixir.erl', line: 278]}
100% {:erl_eval, :do_apply, 6, [file: 'erl_eval.erl', line: 680]}
100% {Profiler, :profile, 2, [file: 'lib/profiler.ex', line: 120]}
100% {Enum, :reduce_range_inc, 4, [file: 'lib/enum.ex', line: 3371]}
100% {Profiler, :"-profile/2-fun-0-", 3, [file: 'lib/profiler.ex', line: 121]}
Summary
Functions
Demo function for the documentation. Never implement fibonacci like this. Never
This runs fprof the given amount of milliseconds or 5 seconds by default.
hotspots returns process names / stacktraces by the amount they are seen in the given the timeout.
Converts a term to a pid. Accepts
print_hotspots lists process names / stacktraces by the amount they are seen in the given the timeout.
Identify the best human readable name for a process. Supports as
arguments all types supported by pid/1
Processes lists all processes ordered by reductions withing the given timeout. For that it takes an initial snapshot, sleeps the given timeout and takes a second snapshot.
Processes lists all processes ordered by heap usage.
Lists the processes by message queue length.
This runs the sampling profiler for the given amount of milliseconds or 10 seconds by default. The sampling profiler will collect stack traces of the given process pid or process name and print the collected samples based on frequency.
Arguments are the same as for profile() but this sampling profiler does not analyze stacktrace but instead just samples the current function and prints the result.
Returns current stacktrace for the given pid and allows setting the erlang internal stacktrace depth.
Times the given function and prints the result. Example usage
In order to identify processes that are supposed to be short-lived but actually take too mich time this function produces Logger.warning() with a stacktrace if the provided process is still alive after the given timeout.
Types
Functions
@spec demo_fib(integer()) :: pos_integer()
Demo function for the documentation. Never implement fibonacci like this. Never
@spec fprof(task(), non_neg_integer()) :: binary()
This runs fprof the given amount of milliseconds or 5 seconds by default.
When the run completes the code tries to open kcachegrind to show the resultung kcachegrind file. Ensure to have kcachegrind installed. If kcachgrind is not found the function will just return the name of the generated report file. It can then be copied to another lcoation for analysis
For pid there are five different input formats allowed:
- fun() which will then be spwaned called in a loop and killed after the test
- Native pid()
- An atom that is resolved using whereis(name)
- A string of the format "<a.b.c>" or "0.b.c" or just "b" in which case the pid is interpreted as "<0.b.0>"
- An integer, in which case the pid is interpreted as "<0.#{int}.0>"
In this example the profiler is used to profile itself. The first percentage number shows how many samples were found in the given function call. Indention indicates the call stack:
iex(1)> Profiler.fprof(fn -> Profiler.demo_fib(30) end)
hotspots returns process names / stacktraces by the amount they are seen in the given the timeout.
Converts a term to a pid. Accepts
- pid()
- integer()
- tuple()
- atom()
- binary()
- string()
Examples:
iex(1)> Profiler.pid(1)
<0.1.0>
iex(2)> Profiler.pid("1")
<0.1.0>
iex(3)> Profiler.pid("Elixir.IEx.Evaluator")
<0.187.0>
iex(4)> Profiler.pid({:IEx.Evaluator, :init, 4})
print_hotspots lists process names / stacktraces by the amount they are seen in the given the timeout.
Identify the best human readable name for a process. Supports as
arguments all types supported by pid/1
Examples:
iex(1)> Profiler.process_name(1)
:erst_code_purger
iex(2)> Profiler.process_name(self())
{IEx.Evaluator, :init, 5}
@spec processes(non_neg_integer() | Keyword.t()) :: :ok
Processes lists all processes ordered by reductions withing the given timeout. For that it takes an initial snapshot, sleeps the given timeout and takes a second snapshot.
The following options are supported:
- :timeout - the timeout in milliseconds
- :limit - the limit of processes to list
- :stacktrace - the number of processes to print the stack trace for
- :profile - the number of processes to profile
iex(1)> Profiler.processes [<0.187.0>,{'Elixir.IEx.Evaluator',init,4},1339] [<0.132.0>,tls_client_ticket_store,32] [<0.182.0>,{'Elixir.Logger.Watcher',init,1},1] [<0.181.0>,'Elixir.Logger.BackendSupervisor',1] [<0.180.0>,{'Elixir.Logger.Watcher',init,1},1] [<0.179.0>,'Elixir.Logger',1] [<0.178.0>,'Elixir.Logger.Supervisor',1] [<0.177.0>,{application_master,start_it,4},1] [<0.176.0>,{application_master,init,4},1] [<0.161.0>,'Elixir.Hex.UpdateChecker',1] :ok
@spec processes_memory() :: :ok
Processes lists all processes ordered by heap usage.
@spec processes_message_queue_len() :: :ok
Lists the processes by message queue length.
@spec profile(task(), non_neg_integer()) :: :ok
This runs the sampling profiler for the given amount of milliseconds or 10 seconds by default. The sampling profiler will collect stack traces of the given process pid or process name and print the collected samples based on frequency.
For pid there are five different input formats allowed:
- fun() which will then be spwaned called in a loop and killed after the test
- Native pid()
- An atom that is resolved using whereis(name)
- A string of the format "<a.b.c>" or "0.b.c" or just "b" in which case the pid is interpreted as "<0.b.0>"
- An integer, in which case the pid is interpreted as "<0.#{int}.0>"
In this example the profiler is used to profile itself. The first percentage number shows how many samples were found in the given function call. Indention indicates the call stack:
iex(2)> Profiler.profile(187)
100% {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 249]}
100% {IEx.Evaluator, :init, 4, [file: 'lib/iex/evaluator.ex', line: 27]}
100% {IEx.Evaluator, :loop, 1, [file: 'lib/iex/evaluator.ex', line: 103]}
100% {IEx.Evaluator, :eval, 3, [file: 'lib/iex/evaluator.ex', line: 217]}
100% {IEx.Evaluator, :do_eval, 3, [file: 'lib/iex/evaluator.ex', line: 239]}
100% {IEx.Evaluator, :handle_eval, 5, [file: 'lib/iex/evaluator.ex', line: 258]}
100% {:elixir, :eval_forms, 3, [file: 'src/elixir.erl', line: 263]}
100% {:elixir, :recur_eval, 3, [file: 'src/elixir.erl', line: 278]}
100% {:erl_eval, :do_apply, 6, [file: 'erl_eval.erl', line: 680]}
100% {Profiler, :profile, 2, [file: 'lib/profiler.ex', line: 120]}
100% {Enum, :reduce_range_inc, 4, [file: 'lib/enum.ex', line: 3371]}
100% {Profiler, :"-profile/2-fun-0-", 3, [file: 'lib/profiler.ex', line: 121]}
@spec profile_simple(task(), non_neg_integer()) :: :ok
Arguments are the same as for profile() but this sampling profiler does not analyze stacktrace but instead just samples the current function and prints the result.
The first number shows the total number of samples that have been recorded per function call.
For pid there are five different input formats allowed:
- fun() which will then be spwaned called in a loop and killed after the test
- Native pid()
- An atom that is resolved using whereis(name)
- A string of the format "<a.b.c>" or "0.b.c" or just "b" in which case the pid is interpreted as "<0.b.0>"
- An integer, in which case the pid is interpreted as "<0.#{int}.0>"
iex(2)> Profiler.profile_simple 197
{10000, {Profiler, :"-profile_simple/2-fun-0-", 3}}
Returns current stacktrace for the given pid and allows setting the erlang internal stacktrace depth.
Times the given function and prints the result. Example usage:
iex(1)> Profiler.time(fn() -> Process.sleep 1000 end)
timer: 1004
:ok
@spec trace_all_calls(task(), non_neg_integer()) :: binary()
@spec trace_poll_stacktrace(task(), non_neg_integer()) :: binary()
In order to identify processes that are supposed to be short-lived but actually take too mich time this function produces Logger.warning() with a stacktrace if the provided process is still alive after the given timeout.
If the process is just running a certain critical section that should be monitored
the warning can be supressed using cancel_warn_if_stuck()
@pid Pid of the process to be monitored, or a function after which the warning will be autocancelled @opts can be
timeout
-> Timeout in ms after which the warning will be produced. defaults to 5_000label
-> Process label to be used in the report or just thepid
will be usedfun
-> When provided this function replaces the default report viaLogger.warning