Profiler - Sampling Profiler for Shell Debugging

Hi there,

this is a tool I’ve been using myself quite a bit recently for online debugging and performance analysis. It’s a simple remote shell Sampling Profiler module.

Here you can get it:


https://hexdocs.pm/profiler/Profiler.html

It’s focused on shell usage so all commands print to stdout. Usage is simple after including it in your project. E.g. here it’s used to profiler the Elixir compiler and shows use how much time is % spend in function calls:

iex(diode@leno)3> pid = spawn(fn() -> for _ <- 1..100000, do: Elixir.Code.compile_file("lib/debounce.ex") end)
#PID<0.731.0>
iex(diode@leno)4> Profiler.profile(pid)
  96% {:erl_eval, :expr, 5, [file: 'erl_eval.erl', line: 411]}
     96% {:erl_eval, :expr_list, 6, [file: 'erl_eval.erl', line: 888]}
        96% {:erl_eval, :do_apply, 6, [file: 'erl_eval.erl', line: 680]}
           96% {Enum, :reduce_range_inc, 4, [file: 'lib/enum.ex', line: 3371]}
              96% {:erl_eval, :expr, 5, [file: 'erl_eval.erl', line: 232]}
                 96% {:erl_eval, :do_apply, 6, [file: 'erl_eval.erl', line: 680]}
                    78% {Code, :compile_file, 2, [file: 'lib/code.ex', line: 1157]}
                       74% {:elixir_compiler, :quoted, 3, [file: 'src/elixir_compiler.erl', line: 18]}
                          74% {:elixir_lexical, :run, 3, [file: 'src/elixir_lexical.erl', line: 14]}
                             74% {:elixir_compiler, :eval_forms, 3, [file: 'src/elixir_compiler.erl', line: 46]}
                                73% {:elixir, :eval_forms, 3, [file: 'src/elixir.erl', line: 263]}
                                   73% {:elixir, :recur_eval, 3, [file: 'src/elixir.erl', line: 278]}
                                      73% {:erl_eval, :do_apply, 6, [file: 'erl_eval.erl', line: 680]}
                                         42% {:elixir_module, :compile, 5, [file: 'src/elixir_module.erl', line: 107]}
                                            42% {:elixir_module, :eval_form, 6, [file: 'src/elixir_module.erl', line: 333]}
                                               31% {:elixir_compiler, :compile, 3, [file: 'src/elixir_compiler.erl', line: 58]}
                                                  31% {:elixir_erl_compiler, :spawn, 2, [file: 'src/elixir_erl_compiler.erl', line: 20]}
                                               10% {:elixir_compiler, :compile, 3, [file: 'src/elixir_compiler.erl', line: 60]}
                                         21% {:elixir_module, :compile, 5, [file: 'src/elixir_module.erl', line: 140]}
                                            21% {:elixir_erl_compiler, :spawn, 2, [file: 'src/elixir_erl_compiler.erl', line: 20]}
                                          7% {:elixir_module, :compile, 5, [file: 'src/elixir_module.erl', line: 142]}
                                             7% {:code_server, :call, 1, [file: 'code_server.erl', line: 139]}
                    18% {Code, :verify_loaded, 1, [file: 'lib/code.ex', line: 1394]}
                       17% {Module.ParallelChecker, :collect_results, 2, [file: 'lib/module/parallel_checker.ex', line: 31]}
:ok

By default it takes 10000 samples, one every millisecond and then analyzes the stack traces. Since the sampling is time based it’s especially useful when reduction count based profiling leads you to a red herring.

Have fun!

2 Likes