Skip to content

Commit

Permalink
Add top-level performance measuring guide page
Browse files Browse the repository at this point in the history
  • Loading branch information
malteneuss committed Nov 9, 2024
1 parent 46c6200 commit 9839ef1
Showing 1 changed file with 44 additions and 17 deletions.
61 changes: 44 additions & 17 deletions doc/how-to-analyze-haskell-code-performance.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Cabal and the
can help you understand why.

The main steps are to

1. let GHC insert performance measuring code into your application,
2. run the application to collect a performance report and
3. visualize that report.
Expand All @@ -21,25 +22,42 @@ First, build your application, e.g. ``my-app``, with profiling enabled:

.. code-block:: console
$ cabal build --enable-profiling --profiling-detail=late exe:my-app
$ cabal build --enable-profiling --profiling-detail=late my-app
Under the hood, this will pass the corresponding
`profiling compiler options <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#compiler-options-for-profiling>`__
to GHC. The additional Cabal flag ``--profiling-detail=late`` instructs GHC to use
`"late-cost-center" profiling <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#ghc-flag--fprof-late>`__
so-called
`late-cost-center profiling <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#ghc-flag--fprof-late>`__
and insert performance measuring code only after important optimisations
have been applied, to minimize the impact of profiling on performance.
have been applied to your application code.
This reduces the performance slow-down of profiling itself and gives you more realistic measurements.
See the Cabal section on :ref:`profiling options <profiling-options>` for more details.

.. note::
You can add further three recommended profiling options to your ``my-app.cabal`` file
to control where measuring code is inserted into your application as follows:

::

executable my-app
...
ghc-options:
-fprof-auto
-fno-prof-count-entries
-fprof-auto-calls
...

You can find more information on these options in the
`GHC "cost-center" guide <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#automatically-placing-cost-centres>`__.

Second, run the application with the necessary
`runtime system (RTS) options <https://downloads.haskell.org/ghc/latest/docs/users_guide/runtime_control.html>`__
to produce a profile report.

.. code-block:: console
$ cabal list-bin exe:my-app
/path/to/my-app
$ /path/to/my-app +RTS -pj -RTS
$ $(cabal list-bin my-app) +RTS -pj -RTS
<program runs and finishes>
The report is written to a ``<app-name>.prof`` file, i.e. ``my-app.prof``, in the current directory.
Expand All @@ -48,11 +66,22 @@ With the RTS option ``-pj`` the app produces a
Other report format options can be found in the
`GHC format documentation. <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#time-and-allocation-profiling>`__.

Finally, load the profiling report file into a visualizer to look for performance bottlenecks.
One popular open-source
.. note::

You can combine both steps above into a single ``cabal run`` command:

.. code-block:: console
$ cabal run --enable-profiling --profiling-detail=late my-app -- +RTS -pj -RTS
<program runs and finishes>
Finally, load the profiling report file ``my-app.prof`` into a visualizer
and look for performance bottlenecks. One popular open-source
`flame graph <https://www.brendangregg.com/flamegraphs.html>`__
visualizer is `Speedscope <https://speedscope.app>`, which runs in the browser and comes with
an example.
visualizer is
`Speedscope <https://speedscope.app>`__,
which runs in the browser and can open this report directly.

Profiling your dependencies too
-------------------------------
Expand All @@ -62,7 +91,7 @@ This happens by default, because Cabal command line options only apply to local
and dependencies are usually not local.
However, the bottlenecks may be in your dependencies, so you would want to profile those too.

To enable ``late``-cost-center profiling`` of all packages/dependencies in your project,
First, to enable ``late``-cost-center profiling`` of all packages/dependencies in your project,
add the following to your project’s ``cabal.project``` file:

.. code-block:: console
Expand All @@ -71,27 +100,25 @@ add the following to your project’s ``cabal.project``` file:
profiling: true
profiling-detail: late
Then rebuild your application with ``cabal build``:
Second, rebuild your application with ``cabal build`` as before:

.. code-block:: console
$ cabal build exe:my-app
$ cabal build my-app
Resolving dependencies...
Build profile: -w ghc-9.10.1 -O1
In order, the following will be built (use -v for more details):
- base64-bytestring-1.2.1.0 (lib) --enable-profiling (requires build)
- cryptohash-sha256-0.11.102.1 (lib) --enable-profiling (requires build)
<...>
...
There's no need to pass ``--enable-profiling`` to the build command manually,
because it's already enabled in the project file (and seen in the build log).

Then run the application with the ``-pj`` RTS option as before.

Finally, run the application with the ``-pj`` RTS option as before.
You should now find more information in the profiling report ``my-app.prof``.

Further information on how to apply Cabal options can be in the
:ref:`Cabal options sections <package-configuration-options>`.

Further in-depth information on profiling with GHC can be found in the
`GHC profiling guide <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html>`__.

0 comments on commit 9839ef1

Please sign in to comment.