Skip to content

Commit 02da008

Browse files
malteneussjasagredoulysses4everAndreasPKmergify[bot]
authored
Add a performance measuring top-level user guide page (#10539)
* Add top-level performance measuring guide page * Add top-level performance measuring guide page * Update doc/how-to-analyze-haskell-code-performance.rst Co-authored-by: Javier Sagredo <[email protected]> * Update doc/how-to-analyze-haskell-code-performance.rst Co-authored-by: Javier Sagredo <[email protected]> * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Update doc/how-to-analyze-haskell-code-performance.rst Co-authored-by: Artem Pelenitsyn <[email protected]> * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Update doc/how-to-analyze-haskell-code-performance.rst Co-authored-by: Javier Sagredo <[email protected]> * Update doc/how-to-analyze-haskell-code-performance.rst Co-authored-by: Javier Sagredo <[email protected]> * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Update doc/how-to-analyze-haskell-code-performance.rst Co-authored-by: Artem Pelenitsyn <[email protected]> * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Update doc/how-to-analyze-haskell-code-performance.rst Co-authored-by: Javier Sagredo <[email protected]> * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Add top-level performance measuring guide page * Update doc/how-to-analyze-haskell-code-performance.rst Co-authored-by: AndreasPK <[email protected]> * Update doc/how-to-analyze-haskell-code-performance.rst Co-authored-by: AndreasPK <[email protected]> * Add top-level performance measuring guide page --------- Co-authored-by: Javier Sagredo <[email protected]> Co-authored-by: Artem Pelenitsyn <[email protected]> Co-authored-by: AndreasPK <[email protected]> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent 1103d01 commit 02da008

File tree

4 files changed

+171
-2
lines changed

4 files changed

+171
-2
lines changed

doc/cabal-project-description-file.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.. _cabal-project-file:
2+
13
Project Description — cabal.project File
24
========================================
35

@@ -767,6 +769,7 @@ The following settings control the behavior of the dependency solver:
767769
explicitly constrained. When set to `none`, the solver will
768770
consider all packages.
769771

772+
.. _package-configuration-options:
770773

771774
Package configuration options
772775
-----------------------------
@@ -1302,6 +1305,8 @@ Foreign function interface options
13021305
``--extra-framework-dirs=DIR``, which can be specified multiple
13031306
times.
13041307

1308+
.. _profiling-options:
1309+
13051310
Profiling options
13061311
^^^^^^^^^^^^^^^^^
13071312

@@ -1328,6 +1333,8 @@ Profiling options
13281333
The command line variant of this flag is ``--enable-profiling`` and
13291334
``--disable-profiling``.
13301335

1336+
.. _profiling-detail:
1337+
13311338
.. cfg-field:: profiling-detail: level
13321339
--profiling-detail=level
13331340
:synopsis: Profiling detail level.
@@ -1367,7 +1374,7 @@ Profiling options
13671374
late-toplevel
13681375
Like top-level but costs will be assigned to top level definitions after
13691376
optimization. This lowers profiling overhead massively while giving similar
1370-
levels of detail as toplevle-functions. However it means functions introduced
1377+
levels of detail as toplevel-functions. However it means functions introduced
13711378
by GHC during optimization will show up in profiles as well.
13721379
Corresponds to ``-fprof-late`` if supported and ``-fprof-auto-top`` otherwise.
13731380
late
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
How to analyze Haskell performance
2+
==================================
3+
4+
When a Haskell application is slow or uses too much memory,
5+
Cabal and `GHC <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html>`__
6+
can help you understand why. The main steps are:
7+
8+
1. Configure the project in a way that makes GHC insert performance-measuring code into your application.
9+
2. Run the application with the right
10+
`runtime system (RTS) flags <https://downloads.haskell.org/ghc/latest/docs/users_guide/runtime_control.html>`__
11+
to produce a performance report.
12+
3. Visualize and analyze that report.
13+
14+
The process of inserting performance measuring code and collecting performance information
15+
is called "profiling".
16+
This guide describes how to instruct Cabal to pass desired profiling flags to the GHC compiler;
17+
Cabal acts as a convenient build configuration interface while the work is done by GHC.
18+
To get a deeper understanding of the overall profiling process itself in GHC,
19+
it is highly recommended to read in depth the
20+
`Profiling section in GHC's User Guide <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html>`__.
21+
22+
Profiling CPU performance
23+
-------------------------
24+
25+
First, configure Cabal to build your application, e.g. ``my-app``, with profiling enabled,
26+
with the following command:
27+
28+
.. code-block:: console
29+
30+
$ cabal configure --enable-profiling
31+
32+
This command creates a ``cabal.project.local`` file with the following content:
33+
34+
.. code-block:: cabal
35+
36+
profiling: True
37+
38+
This file stores temporary configuration settings that are passed implicitly to further Cabal commands
39+
like ``cabal build`` and ``cabal run``.
40+
The setting ``profiling: True`` tells GHC to build your application (and its dependencies) with profiling enabled,
41+
and to insert performance measuring code into your application.
42+
Where exactly such code is inserted can be controlled with settings like ``profiling-detail``
43+
that are presented later.
44+
Further in-depth information on profiling with GHC and its compiler options can be found in the
45+
`GHC profiling guide <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html>`__
46+
47+
.. note::
48+
49+
While a :ref:`cabal.project <cabal-project-file>` file is intended for long-time settings
50+
that are useful to store in Git, ``cabal.project.local`` is for short-lived, local experiments
51+
(like profiling) that, in general, shouldn't be committed to Git.
52+
53+
Second, run your application with the right runtime system flags and let it create a profiling report:
54+
55+
.. code-block:: console
56+
57+
$ cabal run my-app +RTS -pj -RTS
58+
<app builds, runs and finishes>
59+
60+
When the application finishes, a profiling JSON report (due to option ``-pj``)
61+
is written to a ``<app-name>.prof`` file, i.e. ``my-app.prof``, in the current directory.
62+
63+
.. note::
64+
65+
Different report formats can be generated by using different RTS flags. Some useful ones are:
66+
67+
- ``-p`` for a GHC's own
68+
`standard report <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#cost-centres-and-cost-centre-stacks>`__
69+
``<app-name>.prof``, which can be visualized with `profiteur <https://github.com/jaspervdj/profiteur>`__
70+
or `ghcprofview <https://github.com/portnov/ghcprofview-hs>`__.
71+
- ``-pj`` for a
72+
`JSON report <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#json-profile-format>`__
73+
``<app-name>.prof``, which can be visualized with `Speedscope <https://speedscope.app>`__.
74+
- ``-l -p`` for a binary
75+
`"eventlog" report <https://downloads.haskell.org/ghc/latest/docs/users_guide/runtime_control.html#rts-eventlog>`__
76+
``<app-name>.eventlog``, which contains a lot more details and can show you resource usage over time, and can
77+
be converted to JSON with `hs-speedscope <https://github.com/mpickering/hs-speedscope>`__
78+
to be visualized with `Speedscope <https://speedscope.app>`__.
79+
This will also generate a ``.prof`` file (due to ``-p``), which you can ignore.
80+
We just need the ``-p`` flag for the ``.eventlog`` file to include profiling information.
81+
82+
Finally, visualize this JSON report ``my-app.prof`` and analyze it for performance bottlenecks.
83+
One popular open-source
84+
`flame graph <https://www.brendangregg.com/flamegraphs.html>`__
85+
visualizer is
86+
`Speedscope <https://speedscope.app>`__,
87+
which runs in the browser and can open this JSON file directly.
88+
See the
89+
`Haskell Optimization Handbook <https://haskell.foundation/hs-opt-handbook.github.io>`__
90+
on how to optimize your code based on the profiling results afterwards.
91+
92+
So far, we’ve only used a single Cabal option to enable profiling in general for your application.
93+
Where and when GHC should insert performance measuring code can be controlled with the ``profiling-detail`` setting
94+
and ``ghc-options``.
95+
Leaving ``profiling-detail`` unspecified as before results in sensible defaults that differ between libraries and executable.
96+
See the docs for :ref:`profiling-detail<profiling-detail>` to see which options are available.
97+
You can provide ``profiling-detail`` settings and more compiler flags to GHC
98+
(such as ``-fno-prof-count-entries``) via the ``cabal.project.local`` file:
99+
100+
.. code-block:: cabal
101+
102+
profiling: True
103+
profiling-detail: late-toplevel
104+
program-options
105+
ghc-options:
106+
<further options>
107+
108+
The setting ``profiling-detail: late-toplevel`` instructs GHC to use so-called
109+
`late-cost-center profiling <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#ghc-flag--fprof-late>`__
110+
and insert measuring code only after important optimisations have been applied to your application code.
111+
This reduces the performance slow-down of profiling itself and gives you more realistic measurements.
112+
113+
The ``program-options`` section allows you to add more settings like GHC options to the local
114+
packages of your project (See :ref:`Program options<program_options>`).
115+
The ``ghc-options`` setting allows you to further control which functions and other bindings
116+
the GHC compiler should profile, as well as other aspects of profiling.
117+
You can find more information and further options in the
118+
`GHC "cost-center" guide <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#automatically-placing-cost-centres>`__.
119+
and the
120+
`GHC profiling compiler options <https://downloads.haskell.org/ghc/latest/docs/users_guide/profiling.html#compiler-options-for-profiling>`__
121+
section.
122+
123+
Profiling your dependencies too
124+
-------------------------------
125+
126+
The profiling setup so far with the ``cabal.project.local`` file only applied to your local packages,
127+
which is usually what you want.
128+
However, bottlenecks may also exist in your dependencies, so you may want to profile those too.
129+
130+
First, to enable ``late``-cost-center profiling for all packages (including dependencies) concerning your project,
131+
not just the local ones, add the following to your project’s ``cabal.project.local`` file:
132+
133+
.. code-block:: cabal
134+
135+
package *
136+
profiling-detail: late-toplevel
137+
138+
.. note::
139+
140+
There are several keywords to specify to which parts of your project some settings should be applied:
141+
142+
- ``program-options`` to apply to :ref:`all local packages<program_options>`.
143+
- ``package <package-name>`` to apply to a :ref:`single package<package-configuration-options>`, be it local or remote.
144+
- ``package *`` to apply to :ref:`all local and remote packages (dependencies)<package-configuration-options>`.
145+
146+
Second, rerun your application with ``cabal run``, which also automatically rebuilds your application:
147+
148+
.. code-block:: console
149+
150+
$ cabal run my-app -- +RTS -pj -RTS
151+
Resolving dependencies...
152+
Build profile: -w ghc-9.10.1 -O1
153+
In order, the following will be built (use -v for more details):
154+
- base64-bytestring-1.2.1.0 (lib) --enable-profiling (requires build)
155+
- cryptohash-sha256-0.11.102.1 (lib) --enable-profiling (requires build)
156+
...
157+
<app runs and finishes>
158+
159+
You can now find profiling data of dependencies in the report ``my-app.prof``
160+
to analyze. More information on how to configure Cabal options can be found in the
161+
:ref:`Cabal options sections <package-configuration-options>`.

doc/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Welcome to the Cabal User Guide
1515

1616
how-to-package-haskell-code
1717
how-to-source-packages
18+
how-to-analyze-haskell-code-performance
1819
how-to-build-like-nix
1920
how-to-run-in-windows
2021
how-to-use-backpack

doc/setup-commands.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ Miscellaneous options
713713
late-toplevel
714714
Like top-level but costs will be assigned to top level definitions after
715715
optimization. This lowers profiling overhead massively while giving similar
716-
levels of detail as toplevle-functions. However it means functions introduced
716+
levels of detail as toplevel-functions. However it means functions introduced
717717
by GHC during optimization will show up in profiles as well.
718718
Corresponds to ``-fprof-late`` if supported and ``-fprof-auto-top`` otherwise.
719719
late

0 commit comments

Comments
 (0)