Introducing eFlambé

Trevor Brown
Code for RentPath
Published in
4 min readOct 20, 2021

--

SpawnFest is an annual 48 hour online contest where teams try to build the best BEAM-based application, as determined by the judges based on certain criteria. In this blog post I am going to introduce the new tool I created during SpawnFest.

eFlambé is a tool for rapidly profiling Erlang and Elixir code. It is intended to be one of the first tools you reach for when debugging a performance issue in your Elixir or Erlang application. With a single command you can visualize your code’s performance as an interactive flame graph in your flame graph viewer of choice. It’s written in Erlang and published to hex.pm.

eFlambé flame graph viewed in speedscope

Design

There are no new ideas behind eFlambé. Brendan Gregg introduced flame graphs nearly a decade ago and there have been several Erlang projects that have made it possible to generate flame graphs of Elixir and Erlang call stacks. By far the most popular has been Vlad Ki’s eflame. While eflame works well it has two disadvantages:

  • Generating a SVG flame graph is a multi-step process.
  • Code that needs to be profiled must be invoked by the eflame:apply/3 directly. Sometimes you want to profile a function call as it is made by code inside of your running application. With eflame you must wrap the function call in an eflame:apply/3 call and re-compile and restart your application.

eFlambé improves upon eflame by making flame graph generation a single step process, and making it possible to profile any function inside a running application without having to recompile code or run more than one command.

Usage

Using eFlambé is easy. Simply add it as a dependency to your project.

For Elixir projects, add the following line to your mix.exs file’s dependency section and then run mix deps.get:

{:eflambe, "~> 0.2.1"}

For Erlang rebar3 projects add the following line to the dependency section of your rebar.config file and then run rebar3 get-deps:

{eflambe, "0.2.1"}

Then start up your application with a remote shell attached. For Elixir projects this will typically be iex -S <script>, and for Erlang rebar3 projects this will be rebar3 shell.

There are two different ways to generate flame graphs with eFlambé.

Profiling a single call

Generating a flame graph of a single function call can be done with the eflambe:apply/2 function. For example, suppose I want to generate a flame graph of my Fibonacci algorithm:

iex(1)> :eflambe.apply({MyFibonacci, generate, [10]}, [output_format: :brendan_gregg, open: :speedscope])

The first argument is a tuple containing the module name, function name, and the list of arguments to invoke the function with. The second argument is a list of options for eFlambé. In this example we are specifying the output format as brendan_gregg (one of the formats that speedscope can read) and instructing eFlambé to open the generated flame graph in speedscope (you’ll need to have speedscope already installed for this to work). See the readme for the complete list of options. This will execute MyFibonacci.generate/1 with an argument of 10. Because I specified open: :speedscope eFlambé will immediately open the flame graph data in speedscope when the function returns.

Flame graph of my Fibonacci function viewed in speedscope

Profiling a call invoked by application code

Sometimes the code you want to profile cannot be invoked directly, or you need to profile it with real arguments to generate a more accurate flame graph. For example, you want to profile a Phoenix controller action as it is invoked in your real Plug pipeline. eFlambé provides a convenient way to do this as well with the :eflambe.capture/3 function.

For example, to profile three invocations of MyController.index/2 action:

iex(1)> :eflambe.capture({MyController, index, 2}, 3, [output_format: :brendan_gregg, open: :speedscope])

The moment a request is sent and MyController.index/2 is invoked eFlambé will “capture” the call stack during the execution of the function. Because the :open option was specified eFlambé will open the flame graph for viewing after the function has returned. This will happen for the first three invocations of the function. After three calls eFlambé will off capturing and stop tracing calls.

Flame graph of my Phoenix controller action, viewed in speedscope

Conclusion

Seeing a flame graph of the code you’ve written can help you better understand how your code is executed. You don’t need to wait until you’ve run into performance issues to see where the execution time is spent. With eFlambé generating a flame graph is quick and easy so it only takes moment to gain some insight into your code’s performance characteristics. Hopefully the examples in this blog post have given you an idea of what is possible with eFlambé and inspired you to give it a try.

--

--