Skip to content

case study: add klister case study #81

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

Merged
merged 1 commit into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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

Large diffs are not rendered by default.

Large diffs are not rendered by default.

167 changes: 167 additions & 0 deletions _static/klister/klister-eventlog-implicit-conversion-hb.html

Large diffs are not rendered by default.

167 changes: 167 additions & 0 deletions _static/klister/klister-eventlog-implicit-conversion-hm.html

Large diffs are not rendered by default.

Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
167 changes: 167 additions & 0 deletions _static/klister/klister-eventlog-implicit-conversion-hy.html

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

167 changes: 167 additions & 0 deletions _static/klister/klister-eventlog-implicit-conversion-strict-value.html

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions bib/book.bib
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,19 @@ @article{hoCardinality
numpages = {13},
keywords = {lazy evaluation, haskell, functional programming languages, compilers, static analysis, cardinality analysis, program optimisation, operational semantics, types and effects, thunks}
}

@book{okasaki,
place={Cambridge},
title={Purely Functional Data Structures},
DOI={10.1017/CBO9780511530104},
publisher={Cambridge University Press},
author={Okasaki, Chris},
year={1998}
}

@techreport{BagwellHAMT,
title={Ideal hash trees},
author={Bagwell, Phil},
institution={Ecole polytechnique fédérale de Lausanne},
year={2001}
}
1 change: 1 addition & 0 deletions conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
## global links in the book that share a prefix that we've named.
extlinks = {'userGuide': ('https://downloads.haskell.org/~ghc/9.2.4/docs/html/users_guide/%s', '%s'),
'ghcWiki': ('https://gitlab.haskell.org/ghc/ghc/wikis/%s', '#%s'),
'haskellPerf': ('https://github.com/haskell-perf/%s', '%s'),
}

# prolog for colored text and global variables
Expand Down
7 changes: 7 additions & 0 deletions custom.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,11 @@
.. role:: strike
:class: strike

..
Convienien math
.. |bottom| replace:: :math:`\bot`
..
GHC Specific
.. |ghcVersion| replace:: 9.2.x
.. |core| replace:: Core
.. |stg| replace:: Stg
5 changes: 5 additions & 0 deletions index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ by `Input Output Global <https://iohk.io/>`_.
Release History
---------------

* March/April, 2023

* :ref:`Klister Case Study <klister case study>` first draft finished.
* Add :ref:`Info-Table profiling <IPE chapter>` stub.

* February, 2023

* Lambda lifting chapter first draft finished.
Expand Down
1 change: 1 addition & 0 deletions src/Case_Studies/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ Case Studies

sbv_572
sbv_642
klister
1,514 changes: 1,514 additions & 0 deletions src/Case_Studies/klister.rst

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/Measurement_Observation/Heap_Ghc/eventlog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ understand:
#. When to use eventlog.
#. How to build your program to use eventlog.
#. How to visualize eventlog information.
#. How to tune eventlog to inspect specific subsystems.
#. How to tune eventlog to inspect specific sub-system.
#. How to tune eventlog to inspect specific pieces of code.

Requirements
Expand Down Expand Up @@ -57,7 +57,7 @@ When should I use Eventlog

Eventlog is most useful when you need to :ref:`Characterize the Problem
<characterize-the-problem>`. It yields runtime information on the specific
subsystems the program relies on. Thus, it allows you to drill down into the
sub-system the program relies on. Thus, it allows you to drill down into the
behavior of the garbage collector, the scheduler, the heap and so. For example,
using the flag ``+RTS -lg`` you can collect the ``CONC_MARK_BEGIN`` and
``CONC_MARK_END`` events which log the beginning and end of the concurrent
Expand Down
79 changes: 40 additions & 39 deletions src/Measurement_Observation/Heap_Ghc/ghc_flags.rst
Original file line number Diff line number Diff line change
@@ -1,45 +1,46 @@
.. GHC Flags
.. _Heap Profiling Chapter:

:lightgrey:`GHC Flags`
======================

`TODO <https://github.com/input-output-hk/hs-opt-handbook.github.io/issues/22>`_

The Running Example
-------------------

Our test program is an example of excessive closure allocation:

.. code-block:: haskell

-- Need to disable optimizations because GHC will recognize and perform
-- let-floating for us!
{-# OPTIONS_GHC -O0 -ddump-simpl -ddump-to-file -ddump-stg-final #-}

module Main where

import Gauge

-- | This function excessively allocates closures every time 'f' is called. The
-- closure in question being the allocation of the 10k element list.
bad :: [Int] -> Int
bad xs = sum $ fmap f xs
where f x = x + length [1..10000]

-- | This function avoids the excessive closure allocation. We still will
-- allocate thunks for every element of 'xs' but we only calculate 'length
-- [1..10000]' once because we floated it out of 'f'.
good :: [Int] -> Int
good xs = sum $ fmap f xs
where
n = length [1..10000]
f x = x + n

-- | use Gauge to run the benchmarks
main :: IO ()
main = do
let test_values = replicate 5000 1
defaultMain [ bgroup "Too Many Closures" [ bench "bad" $ whnf bad test_values
, bench "good" $ whnf good test_values
]
]
..
The Running Example
-------------------

Our test program is an example of excessive closure allocation:

.. code-block:: haskell

-- Need to disable optimizations because GHC will recognize and perform
-- let-floating for us!
{-# OPTIONS_GHC -O0 -ddump-simpl -ddump-to-file -ddump-stg-final #-}

module Main where

import Gauge

-- | This function excessively allocates closures every time 'f' is called. The
-- closure in question being the allocation of the 10k element list.
bad :: [Int] -> Int
bad xs = sum $ fmap f xs
where f x = x + length [1..10000]

-- | This function avoids the excessive closure allocation. We still will
-- allocate thunks for every element of 'xs' but we only calculate 'length
-- [1..10000]' once because we floated it out of 'f'.
good :: [Int] -> Int
good xs = sum $ fmap f xs
where
n = length [1..10000]
f x = x + n

-- | use Gauge to run the benchmarks
main :: IO ()
main = do
let test_values = replicate 5000 1
defaultMain [ bgroup "Too Many Closures" [ bench "bad" $ whnf bad test_values
, bench "good" $ whnf good test_values
]
]
1 change: 1 addition & 0 deletions src/Measurement_Observation/Heap_Ghc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ Heap Profiling and Inspection : GHC Based Methods

ghc_flags
eventlog
info_table
ghc_debug
scopes
6 changes: 6 additions & 0 deletions src/Measurement_Observation/Heap_Ghc/info_table.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.. _IPE Chapter:

:lightgrey:`Info-Table Profiling`
=================================

`TODO <https://github.com/input-output-hk/hs-opt-handbook.github.io/issues/80>`_
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.. TickyTicky
.. _Ticky Chapter:

:lightgrey:`TickyTicky`
=======================
Expand Down
2 changes: 1 addition & 1 deletion src/Measurement_Observation/Measurement_Libs/criterion.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.. _Criterion:
.. _Tasty Chapter:

:lightgrey:`Criterion, Gauge, and Tasty-Bench`
==============================================
Expand Down
12 changes: 6 additions & 6 deletions src/Measurement_Observation/Measurement_Libs/weigh.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

`Weigh <https://hackage.haskell.org/package/weigh>`_ is a tiny Haskell package
to measure allocations of data constructors and functions. It provides a similar
interface to :ref:`Criterion, Gauge, and Tasty-Bench <Criterion>` and is useful to confirm
that a data structure or function has the memory performance you anticipate it
to have at *runtime*. ``Weigh`` is easy to setup and non-invasive; requiring no
changes to source code. Thus, it is a good *initial* tool to use before trying
more advanced methods with higher setup costs, such as :ref:`Cachegrind
<Cachegrind>`.
interface to :ref:`Criterion, Gauge, and Tasty-Bench <Tasty Chapter>` and is
useful to confirm that a data structure or function has the memory performance
you anticipate it to have at *runtime*. ``Weigh`` is easy to setup and
non-invasive; requiring no changes to source code. Thus, it is a good *initial*
tool to use before trying more advanced methods with higher setup costs, such as
:ref:`Cachegrind <Cachegrind>`.


Requirements
Expand Down
12 changes: 9 additions & 3 deletions src/Measurement_Observation/the_recipe.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@
The Recipe
==========

.. _Understand the System:

.. _Don't think, look:

.. warning::

This chapter is still under heavy revision. Please feel free to still read
through it, just know that it needs more love and care, and I (Jeff) had to
walk away in order to continue to make progress on it at some later date.
This chapter is going to be rewritten with reference to David Agan's
`Debugging book <https://debuggingrules.com/>`_. Until that time I have left
it intact in case it may be helpful. If you came here chasing a link to
``understand the system`` or ``don't think, look`` then I refer you to his
book for the time being.


This chapter presents a recipe for debugging performance regressions in Haskell.
Expand Down
2 changes: 1 addition & 1 deletion src/Optimizations/Code_Changes/oneshot.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.. _OneShot Monad Trick:
.. _OneShot Monad Chapter:

:lightgrey:`The OneShot Monad Trick`
====================================
Expand Down
36 changes: 36 additions & 0 deletions src/glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ Glossary
:ghcWiki:`wiki <commentary/rts/storage/heap-objects#info-tables>` for more
details.

Info Table Address : Runtime

The memory address for heap object descriptors :term:`info table`.

Join Point : Optimization

A join point is a place where different execution paths come together or
Expand Down Expand Up @@ -209,6 +213,38 @@ Glossary
type is a set with three values: ``True``, ``False``, and :math:`\bot`.
Therefore ``Bool`` is a Lifted type.

Loop Fusion

Loop fusion is a classic optimization technique that reduces the number of
loops in a program, thereby reducing the number of memory accesses and the
number of looping constructs. In Haskell, loop fusion transforms many
traversals over the same data structure to a single traversal. A classic
example of this is map fusion.

.. code-block:: haskell

-- two traversals, one for f, one for g on the result of f
map g . map f $ [1..100]

-- after map fusion:
-- only one traversal
map (g . f) [1..100]

This can also appear in list comprehensions, for example:

.. code-block:: haskell

...
-- three traversals: two to project elements, 1 to fold
let foo = foldl + 0 [ i | (i,_) <- args ]
let res = bar foo [ j | (_,j) <- args ]

-- after loop fusion on the list comprehensions
-- 2 traversals: one for the arguments, one to fold
let (is, js) = unzip args
let foo = foldl + 0 is
let bar = bar foo js

Multi-Shot Lambda

A multi-shot lambda is a lambda that is called *more* than once. In
Expand Down