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 15 commits
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
146 changes: 146 additions & 0 deletions doc/how-to-analyze-haskell-code-performance.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
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/profiling.html>`__
can help you understand why. The main steps are:

1. Configure the project in a way that makes GHC insert performance-measuring code into your application.
2. Run the application with the right
`runtime system (RTS) flags <https://downloads.haskell.org/ghc/latest/docs/users_guide/runtime_control.html>`__
to produce a performance report and
3. Visualize and analyze that report.

The process of inserting performance measuring code and collecting performance information
is called "profiling". The work is done by GHC while Cabal only acts
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
-------------------------

First, configure Cabal to build your application, e.g. ``my-app``, with profiling enabled,
with the following command:

.. code-block:: console

$ cabal configure --enable-profiling

This command creates a `cabal.project.local <cabal-project-file>`__ file with the following content:
jasagredo marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: cabal

profiling: True

This file stores temporary configuration settings that are passed implicitly to further Cabal commands
like ``cabal build`` and ``cabal run``.
The setting ``profiling: True`` tells GHC
to insert performance measuring code into your application in general,
malteneuss marked this conversation as resolved.
Show resolved Hide resolved
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::

While `cabal.project <cabal-project-file>`__ is intended for long-time settings
that are useful to store in Git, `cabal.project.local` is for short-lived, local experiments
(like profiling) that, in general, shouldn't be committed to Git.

Second, run your application with the right runtime system flags and let it create a profiling report:

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

$ cabal run my-app +RTS -pj -RTS
<app builds, runs and finishes>

When the application finishes, a profiling JSON report (due to option ``-pj``)
is written to a ``<app-name>.prof`` file, i.e. ``my-app.prof``, in the current directory.

.. note::

Different report formats can be generated by using different RTS flags. Some useful ones are:

- ``-p`` for a GHC's own
`standard report <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#cost-centres-and-cost-centre-stacks>`__
``<app-name>.prof``, which can be visualized with `profiteur <https://github.com/jaspervdj/profiteur>`__
or `ghcprofview <https://github.com/portnov/ghcprofview-hs>`__.
- ``-pj`` for a
`JSON report <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#json-profile-format>`__
``<app-name>.prof``, which can be visualized with `Speedscope <https://speedscope.app>`__.
- ``-l-p`` for a binary
`"eventlog" report <https://downloads.haskell.org/ghc/latest/docs/users_guide/runtime_control.html#rts-eventlog>`__
``<app-name>.eventlog``, which contains a lot more details and can show you resource usage over time, and can
be converted to JSON with `hs-speedscope <https://github.com/mpickering/hs-speedscope>`__
to be visualized with `Speedscope <https://speedscope.app>`__.
jasagredo marked this conversation as resolved.
Show resolved Hide resolved

Finally, visualize this JSON report ``my-app.prof`` and analyze it 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.
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.

So far, we've only used a single GHC compiler option to enable profiling
in general for your application.
However, you can pass a lot more compiler flags to GHC via the ``cabal.project.local`` file:

.. code-block:: cabal

profiling: True
profiling-detail: late-toplevel
program-options
ghc-options:
-fprof-auto
-fno-prof-count-entries
-fprof-auto-calls
jasagredo marked this conversation as resolved.
Show resolved Hide resolved

Add these recommended profiling options to control where and when
performance measuring code is inserted into your application
malteneuss marked this conversation as resolved.
Show resolved Hide resolved
The setting ``profiling-detail: late-toplevel`` 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.

The ``ghc-options`` setting allows you to further control which functions and other bindings
the GHC compiler should profile.
malteneuss marked this conversation as resolved.
Show resolved Hide resolved
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>`__.
and the
`GHC profiling compiler options <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#compiler-options-for-profiling>`__
section.

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.local`` file:

.. 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)
...
<app runs and finishes>


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