Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a performance measuring top-level user guide page #10539

Merged
merged 39 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
c0aacca
Add top-level performance measuring guide page
malteneuss Nov 7, 2024
3a9cfba
Add top-level performance measuring guide page
malteneuss Nov 14, 2024
f42a969
Update doc/how-to-analyze-haskell-code-performance.rst
malteneuss Nov 14, 2024
4825f85
Update doc/how-to-analyze-haskell-code-performance.rst
malteneuss Nov 14, 2024
5382563
Merge remote-tracking branch 'origin/add_profiling_guide' into add_pr…
malteneuss Nov 14, 2024
64a51c5
Add top-level performance measuring guide page
malteneuss Nov 14, 2024
fea9c37
Add top-level performance measuring guide page
malteneuss Nov 14, 2024
a9d09d5
Add top-level performance measuring guide page
malteneuss Nov 15, 2024
97748f3
Add top-level performance measuring guide page
malteneuss Nov 15, 2024
bbcda2f
Add top-level performance measuring guide page
malteneuss Nov 15, 2024
9dbe7b1
Add top-level performance measuring guide page
malteneuss Nov 15, 2024
374a812
Update doc/how-to-analyze-haskell-code-performance.rst
malteneuss Nov 18, 2024
84b56b4
Add top-level performance measuring guide page
malteneuss Nov 18, 2024
153b685
Add top-level performance measuring guide page
malteneuss Nov 18, 2024
1c7af04
Add top-level performance measuring guide page
malteneuss Nov 18, 2024
b37f180
Update doc/how-to-analyze-haskell-code-performance.rst
malteneuss Nov 19, 2024
5663434
Update doc/how-to-analyze-haskell-code-performance.rst
malteneuss Nov 19, 2024
9ba9749
Add top-level performance measuring guide page
malteneuss Nov 19, 2024
235fa96
Add top-level performance measuring guide page
malteneuss Nov 19, 2024
2d5ae91
Add top-level performance measuring guide page
malteneuss Nov 19, 2024
a4ffa5a
Add top-level performance measuring guide page
malteneuss Nov 19, 2024
ef25621
Update doc/how-to-analyze-haskell-code-performance.rst
malteneuss Nov 20, 2024
bcc5709
Add top-level performance measuring guide page
malteneuss Nov 20, 2024
f09b406
Merge branch 'add_profiling_guide' of github.com:malteneuss/cabal int…
malteneuss Nov 20, 2024
33d3465
Add top-level performance measuring guide page
malteneuss Nov 20, 2024
a105e8b
Add top-level performance measuring guide page
malteneuss Nov 20, 2024
7d938d6
Add top-level performance measuring guide page
malteneuss Nov 20, 2024
de45cee
Add top-level performance measuring guide page
malteneuss Nov 20, 2024
4d00141
Update doc/how-to-analyze-haskell-code-performance.rst
malteneuss Nov 21, 2024
e775522
Add top-level performance measuring guide page
malteneuss Nov 21, 2024
286bd62
Add top-level performance measuring guide page
malteneuss Nov 21, 2024
9e63dba
Add top-level performance measuring guide page
malteneuss Nov 21, 2024
164aeb3
Add top-level performance measuring guide page
malteneuss Nov 21, 2024
5ce6023
Add top-level performance measuring guide page
malteneuss Nov 21, 2024
7be950a
Add top-level performance measuring guide page
malteneuss Nov 21, 2024
91fd6e3
Update doc/how-to-analyze-haskell-code-performance.rst
malteneuss Nov 23, 2024
8b339a4
Update doc/how-to-analyze-haskell-code-performance.rst
malteneuss Nov 23, 2024
6a20654
Add top-level performance measuring guide page
malteneuss Nov 23, 2024
dc92198
Merge branch 'master' into add_profiling_guide
mergify[bot] Nov 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
126 changes: 126 additions & 0 deletions doc/how-to-analyze-haskell-code-performance.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
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/>`__
malteneuss marked this conversation as resolved.
Show resolved Hide resolved
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.
malteneuss marked this conversation as resolved.
Show resolved Hide resolved

The process of inserting performance measuring code and collecting performance information
is called "profiling". The main work is done by GHC while Cabal only acts
malteneuss marked this conversation as resolved.
Show resolved Hide resolved
as a build configuration interface and passes corresponding compiler flags to GHC.

malteneuss marked this conversation as resolved.
Show resolved Hide resolved
Profiling CPU performance
-------------------------

The first step to build your application, e.g. ``my-app``, with profiling enabled, and
the second step to run it to collect a report, can be done with a single ``cabal run`` command:

.. code-block:: console
malteneuss marked this conversation as resolved.
Show resolved Hide resolved

$ cabal run --enable-profiling --profiling-detail=late my-app -- +RTS -pj -RTS
<program runs and finishes>
malteneuss marked this conversation as resolved.
Show resolved Hide resolved
malteneuss marked this conversation as resolved.
Show resolved Hide resolved

Finally, a profiling JSON report is written to a ``<app-name>.prof`` file,
i.e. ``my-app.prof``, in the current directory.
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 JSON file directly.
jasagredo marked this conversation as resolved.
Show resolved Hide resolved
See the
`Haskell Optimization Handbook <https://haskell.foundation/hs-opt-handbook.github.io>`__
on how to optimize your code based on the profiling results afterwards.

The ``cabal run`` command above is essentially a shorthand for

.. code-block:: console

$ cabal build --enable-profiling --profiling-detail=late my-app
$ cabal list-bin my-app
/path/to/my-app
$ /path/to/my-app +RTS -pj -RTS
<program runs and finishes>
malteneuss marked this conversation as resolved.
Show resolved Hide resolved

In the ``cabal build`` command the first general ``--enable-profiling`` build flag tells GHC
to insert performance measuring code into your application,
while the second profiling option flag ``--profiling-detail=late`` further 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 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.
Further in-depth information on profiling with GHC and its compiler options
can be found in the
`GHC profiling guide <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html>`__

.. note::

Cabal comes with a few convenient :ref:`profiling options <profiling-options>`.
However, you can also pass a lot more
`profiling compiler options <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#compiler-options-for-profiling>`__
to GHC via the ``ghc-prof-options`` field in your ``my-app.cabal`` file.

Add the following, recommended profiling options to your ``my-app.cabal`` file
to control where performance measuring code is inserted into your application:

::

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

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

In the ``/path/to/my-app +RTS -pj -RTS`` command we run the application with the necessary
`runtime system (RTS) option <https://downloads.haskell.org/ghc/latest/docs/users_guide/runtime_control.html>`__
``-pj`` to actually produce a
`"profile JSON" (pj) file report <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#rts-flag--pj>`__.
The configuration options for many other report output formats can be found in the
`GHC format documentation. <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#time-and-allocation-profiling>`__.

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
malteneuss marked this conversation as resolved.
Show resolved Hide resolved
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,
jasagredo marked this conversation as resolved.
Show resolved Hide resolved
add the following to your project’s ``cabal.project`` file:
ulysses4ever marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: cabal

package *
profiling: true
malteneuss marked this conversation as resolved.
Show resolved Hide resolved
profiling-detail: late
jasagredo marked this conversation as resolved.
Show resolved Hide resolved

Second, rerun your application with ``cabal run``, which also automatically rebuilds your application:

.. code-block:: console

$ cabal run my-app -- +RTS -pj -RTS
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 profiling flags like ``--enable-profiling``
to the build or run commands manually this time (as seen in the build log),
because these settings are now determined via the ``cabal.project`` file.

You should now find more information in the profiling report ``my-app.prof``
to analyze. More information on how to configure Cabal options can be found in the
:ref:`Cabal options sections <package-configuration-options>`.
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
Loading