Application profiling

In case the application performs poorly when serving a request, profiling can help to spot the areas in the code that need improving. This guide explains how to start the application in a way that profiling tools are run. It currently focuses on the backend especially on usingflamegraph.

Adding thin to the gemfile

The default web server OpenProject runs on ispuma, which is threaded. The profiling tool used israck-mini-profiler which makes use of i.e.stackprof. Those tools cannot work in a threaded environment which is whythin needs to be employed. This is achieved by adding

gem'thin'

to theGemfile orGemfile.local in case the later already exists.

If profiling is a recurring task, it might also make sense to add another gemfile, e.g.Gemfile.profiling and use the environment variableCUSTOM_PLUGIN_GEMFILE to have OpenProject load it.

Then runbundle install orCUSTOM_PLUGIN_GEMFILE=Gemfile.profiling bundle install to installthin.

Starting the application

Since thin is to be used, and the profiling gems are to be loaded, the application needs to be started like this:

OPENPROJECT_RACK_PROFILER_ENABLED=truethin start

or, if a custom gemfile includes the reference to thin, use the following:

CUSTOM_PLUGIN_GEMFILE=gemfile.profilingOPENPROJECT_RACK_PROFILER_ENABLED=truethin start

This will start the application in development mode, which oftentimes is sufficient, but will lead to slightly distorted results since reloading and reloading checks, especially the ones for I18n, will take place.

To avoid this, the application can be started in production mode but before this can happen, the code needs to be adapted slightly:

  • Search for the places whereOPENPROJECT_RACK_PROFILER_ENABLED is referenced within the code and remove the references toRails.env.development? from the conditions. At the time of writing, this needs to be done at:
    • config/initializers/rack_profiler.rb
    • config/initializers/secure_headers.rb
  • Read the profiling gems to yourGemfile/Gemfile.local/Gemfile.profiling since they would otherwise only be available in the development environment:
gem'flamegraph'gem'rack-mini-profiler'gem'ruby-prof'gem'stackprof'

Start thin via:

SECRET_KEY_BASE='abcd'RAILS_ENV=productionCUSTOM_PLUGIN_GEMFILE=gemfile.profilingOPENPROJECT_RACK_PROFILER_ENABLED=truethin start

Using the profiling tools

Profiling now takes place on every request and every request will be slowed down by it which is why you should not profile on an actual production setup.

Having a flamegraph displayed is triggered by issuing the request withpp=flamegraph as a query prop. E.g. requesting

http://localhost:3000/api/v3/work_packages?pp=flamegraph

will show the flamegraph for that api request.

The options available can be displayed by addingpp=help to a query.

API patch/post requests

For bodied requests (e.g. patch/post) which typically are triggered not from a browser when profiling, a flamegraph can still be created, e.g.:

PATCH http://localhost:3000/api/v3/work_packages/1547?pp=async-flamegraph

will result in a flamegraph being created. Instead of appendingpp=flamegraph, the appended parameter needs to bepp=async-flamegraph.

But that flamegraph will not show up directly in the tools typically used.

The flamegraph needs to be accessed by calling an arbitrary page of the application via the browser after having issued the bodied request (e.g.http://localhost:3000). In the lower right corner, sometimes after some waiting, the profiling tools will show a small menu from which the generated flamegraph can be accessed.

Flamegraph retrieval

In case this fails, the flamegraphs are stored intmp/miniprofiler in a file calledmp_timers_[some hash]. Knowing which file belongs to the previously created flamegraph, the file can be opened by requesting:

http://localhost:3000/mini-profiler-resources/flamegraph?id=[some hash]