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 c1ddadb commit d326c39
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 0 deletions.
3 changes: 3 additions & 0 deletions doc/cabal-project-description-file.rst
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,7 @@ The following settings control the behavior of the dependency solver:
explicitly constrained. When set to `none`, the solver will
consider all packages.

.. _package-configuration-options:

Package configuration options
-----------------------------
Expand Down Expand Up @@ -1302,6 +1303,8 @@ Foreign function interface options
``--extra-framework-dirs=DIR``, which can be specified multiple
times.

.. _profiling-options:

Profiling options
^^^^^^^^^^^^^^^^^

Expand Down
122 changes: 122 additions & 0 deletions doc/how-to-analyze-haskell-code-performance.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
How to analyze Haskell performance
==================================

When a Haskell application is slow or uses too much memory,
Cabal and `GHC <https://downloads.haskell.org/ghc/latest/docs/users_guide/>`__
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.

The process of inserting performance measuring code and collecting performance information
is called "profiling". Cabal makes this easy to do.

Profiling CPU performance
-------------------------

First, build your application, e.g. ``my-app``, with profiling enabled:

.. code-block:: console
$ 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
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 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-prof-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 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.
With the RTS option ``-pj`` the app produces a
`"profile JSON" (pj) file report <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#rts-flag--pj>`__.
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>`__.

.. 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 can open this report directly.

Profiling your dependencies too
-------------------------------

The setup so far only profiles your main application, which is usually what you want.
This happens by default, because Cabal command line options only apply to local packages
and dependencies are usually not local.
However, the bottlenecks may be in your dependencies, so you would want to profile those too.

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
package *
profiling: true
profiling-detail: late
Second, rebuild your application with ``cabal build`` as before:

.. code-block:: console
$ 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).

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>`__.
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Welcome to the Cabal User Guide

how-to-package-haskell-code
how-to-source-packages
how-to-analyze-haskell-code-performance
how-to-build-like-nix
how-to-run-in-windows
how-to-use-backpack
Expand Down

0 comments on commit d326c39

Please sign in to comment.