Awesome
gcprof - garbage collection profiler
gcprof is a tool to measure garbage collection in a production system. For every message a process receives, gcprof tells you how much time was spent in garbage collection and how many passes were done.
How does it work
gcprof:trace(pid(), identity_f())
triggers tracing of garbage
collection in the specified process. Every time the process receives a
message, the resulting garbage collections is associated with that
message. The identity fun is used to identify that message.
The runtime of garbage collections is aggregated and grouped on the
identity. The results can be retrieved by calling
gcprof_aggregator:get_stats/0
. This will reset the current stats, so
it is suitable for periodic polling.
The convenience method gcprof:trace_me(identity_f())
can be used
from within the process you wish to trace.
Identity
The identity fun is given the message your process received and must
produce an identity. The results will be grouped by identity, so it
makes sense to keep the number of unique ids low. The identity will be
the key
in gcprof_aggregator:get_stats/0
.
For example:
fun ({'$gen_call', {_, _}, do_some_stuff}) ->
my_identity;
({'$gen_call', {_, _}, {request, Arg1, Arg2}) ->
{request, Arg1};
(init) ->
init;
(_) ->
undefined
end
There is one special message you may also handle and that is
init
. Any garbage collection done after triggering the trace, but
before your process received any messages is associated with this
identity. Please note that as starting a trace is asynchronous, some
information might be lost.
Stats
This is an example of stats created by running the provided example_server
.
{ok,[[{key,{create_garbage,invocations}},
{observations,20},
{min,1},
{mean,9.0},
{max,17},
{sd,8.207826816681232},
{quantile_25,0.5},
{quantile_75,16.5},
{quantile_99,16.98},
{quantile_999,16.998}],
[{key,{create_garbage,runtime}},
{observations,20},
{min,690},
{mean,4220.85},
{max,8728},
{sd,2898.8413706350443},
{quantile_25,1062.0},
{quantile_75,5974.0},
{quantile_99,8727.8},
{quantile_999,8727.98}]]}
Sampling
As you may not want to trace all processes executing the code that triggers tracing, there is a very simple way of deciding which processes to sample.
Example:
IdentityF = fun ...,
Id = 1000000,
Divisor = 100,
gcprof:sample_me(IdentityF, Id rem Divisor)
sample_me/2
only samples if the second argument is 0. So in the
above case, given an even distribution of ids, only 1% of the
processes will be sampled.
Impact on your system
gcprof:trace/2
uses a gen_server:cast/2
under the hood so your
process does not have to wait for gcprof. This also means that if gcprof
is not running, nothing happens.
If gcprof would crash, the processes would be restarted. When the gcprof tracer process goes away, the VM stops whatever traces were active.
Ideas for the future
At the moment, there are some race conditions in some of the tests that makes them occasionally fail. This should be fixed.
To trace code without modifying the target, a future version of gcprof
could trace a specific function call and start tracing of the process
invoking that function. Superuseful for the init/1
gen_server
callback for example.