packages feed

perf 0.14.0.0 → 0.14.0.1

raw patch · 3 files changed

+462/−1153 lines, 3 files

Files

app/bench.hs view
@@ -9,4 +9,4 @@ main = do   let l = 1000   let a = ExampleSum-  reportMain a defaultReportOptions (List.intercalate "-" [show a, show @Int l])  (testExample . examplePattern a)+  reportMain a defaultReportOptions (List.intercalate "-" [show a, show @Int l]) (testExample . examplePattern a)
perf.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: perf-version: 0.14.0.0+version: 0.14.0.1 license: BSD-3-Clause license-file: LICENSE copyright: Tony Day (c) 2018
readme.md view
@@ -1,1154 +1,463 @@--# perf--[![img](https://img.shields.io/hackage/v/perf.svg)](https://hackage.haskell.org/package/perf) [![img](https://github.com/tonyday567/perf/workflows/haskell-ci.yml/badge.svg)](https://github.com/tonyday567/perf/actions)--<a id="orga196864"></a>--# Introduction--`perf` provides some ideas, code and a library for low-level performance measurement for Haskell hacking. The library:---   provides a monad transformer, `PerfT`, as a light-weight wrapper for use on existing code. `PerfT` modifications can be included in code bases, as opposed to performance being separated code and process, with any effects able to be erased at compile time with `evalPerfT`.---   focuses on fast and accurate measurement.---   is polymorphic to what, exactly, is being measured, so that concepts such as counters, debug checks, time and space performance can share treatment.---   can measure big O for algorithms that can be defined in terms of input size growth.---<a id="orgfd30244"></a>--# Setup--Note that running perf.org is very slow compared with an external process which accesses the compiled version of the library.--    :r-    :set -Wno-type-defaults-    :set -Wno-unused-do-bind-    :set -Wno-name-shadowing-    :set -XOverloadedStrings-    :set -XOverloadedLabels-    import Perf-    import Data.FormatN-    import qualified Data.Text as Text-    import qualified Data.Text.IO as Text-    import qualified Data.Map.Strict as Map-    import Control.Monad-    import Data.Bifunctor-    import System.Clock-    putStrLn "ok"--    [ 1 of 10] Compiling Perf.Stats       ( src/Perf/Stats.hs, interpreted ) [Source file changed]-    [ 3 of 10] Compiling Perf.Time        ( src/Perf/Time.hs, interpreted ) [Source file changed]-    [ 6 of 10] Compiling Perf.Measure     ( src/Perf/Measure.hs, interpreted ) [Source file changed]-    [ 7 of 10] Compiling Perf.Report      ( src/Perf/Report.hs, interpreted ) [Source file changed]-    [ 8 of 10] Compiling Perf.BigO        ( src/Perf/BigO.hs, interpreted ) [Perf.Stats changed]-    [10 of 10] Compiling Perf             ( src/Perf.hs, interpreted ) [Perf.BigO changed]-    Ok, 10 modules reloaded.-    ok---<a id="orgb51effe"></a>--# System.Clock--The default clock is MonoticRaw for linux & macOS, and ThreadCPUTime for Windows.---<a id="org7dcd69d"></a>--## resolution--    getRes Monotonic-    getRes Realtime-    getRes ProcessCPUTime-    getRes ThreadCPUTime-    getRes MonotonicRaw--    TimeSpec {sec = 0, nsec = 1000}-    TimeSpec {sec = 0, nsec = 1000}-    TimeSpec {sec = 0, nsec = 1000}-    TimeSpec {sec = 0, nsec = 42}-    TimeSpec {sec = 0, nsec = 42}---<a id="org6c19f0f"></a>--# Time---<a id="org49fb855"></a>--## What is a tick?--A fundamental operation of Perf.Time is tick, which sandwiches a (strict) function application between two readings of a clock, and returns time in nanoseconds, and the computation result. In this way, the \`Perf\` monad can be inserted into the midst of a computation in an attempt to measure performance in-situ as opposed to sitting off in a separate and decontextualized process.--    :t tick--    tick :: (a -> b) -> a -> IO (Nanos, b)--`tick` returns in the IO monad, because reading a cycle counter is an IO effect. A trivial but fundamental point is that performance measurement effects the computation being measured.---<a id="org1de7ebb"></a>--## tick\_--tick\_ measures the nanoseconds between two immediate clock reads.--    :t tick_--    tick_ :: IO Nanos--    replicateM 10 tick_--    [1833,500,416,416,416,375,375,416,416,416]---<a id="org27958a7"></a>--## multiple ticks--    fmap (fmap (fst)) . replicateM 10 $ tick (const ()) ()--    [7000,2333,2000,2208,1958,1959,1959,2000,2000,1959]--Here, `const () ()` was evaluated and took 7 micro-seconds for the first effect, reducing down to 2 msecs after 10 effects.---<a id="orga206cb6"></a>--## tickIO--`tickIO` measures the evaluation of an IO value.--    :t tickIO--    tickIO :: IO a -> IO (Cycles, a)--    fmap (fmap fst) . replicateM 10 $ tickIO (pure ())--    [5541,1625,1458,1833,1375,1416,1375,1375,1375,1375]---<a id="orgd6c8625"></a>--## sum example--    fmap (expt (Just 2) . fromIntegral) . fst <$> ticks 10 sum ([1..10000] :: [Double])--    ["5.0e5","2.4e5","2.4e5","2.4e5","2.4e5","2.4e5","2.4e5","2.4e5","2.5e5","2.4e5"]--    ts <- ticks 10000 sum ([1..1000] :: [Double])-    print $ average (fmap fromIntegral $ fst ts)--    10747.1975---<a id="org0974e4d"></a>--# PerfT--`PerfT` allows for multiple measurement points and is polymorphic in what is being measured. It returns a Map of results held in State.--Compare a lower-level usage of ticks, measuring the average of summing to one thousand over one thousand trials:--    first (average . fmap fromIntegral) <$> ticks 1000 sum [1..1000]--    (25947.635,500500)--&#x2026; with PerfT usage--    second (fmap (average . fmap fromIntegral)) <$> runPerfT (times 1000) (sum |$| [1..1000])--    (500500,fromList [("",26217.098)])--Comparing performance of sum versus a list fusion approach:--    fmap (average . fmap fromIntegral) <$> (execPerfT (times 1000) $ do; (fap "sum" sum [1..1000]); (fap "fusion" (\x -> sum [1..x]) 1000))--    fromList [("fusion",32871.248),("sum",26924.128)]--An IO example--    exampleIO' :: IO ()-    exampleIO' = do-      txt <- Text.readFile "src/Perf.hs"-      let n = Text.length txt-      Text.putStrLn $ "length of file is: " <> Text.pack (show n)--    exampleIO = execPerfT time (do-      txt <- fam "file_read" (Text.readFile "src/Perf.hs")-      n <- fap "length" Text.length txt-      fam "print_result" (Text.putStrLn $ "length of file is: " <> Text.pack (show n)))--    perf-explore --exampleIO--    length of file is: 1794-    length of file is: 1794-    -    label1          label2          label3          old result      new result      change-    -    normal          file-read       time            2.31e5          1.28e5          improvement-    normal          length          time            2.71e3          2.00e3          improvement-    normal          print-result    time            3.75e4          1.32e4          improvement-    outer           file-read       time            6.05e4          3.64e4          improvement-    outer           length          time            9.59e2          6.25e2          improvement-    outer           outer-total     time            7.39e4          4.02e4          improvement-    outer           print-result    time            9.79e3          1.71e3          improvement---<a id="org216f105"></a>--# perf-explore--`perf-explore` contains some exploratory routines used to develop `perf`--    perf-explore --help--    examples of perf usage-    -    Usage: perf-explore [-n|--runs ARG]-                        [--Monotonic | --Realtime | --ProcessCPUTime |-                          --ThreadCPUTime | --MonotonicRaw]-                        [--best | --median | --average]-                        [--time | --space | --spacetime | --allocation | --count]-                        [-g|--golden ARG] [--nocheck] [-r|--record]-                        [--header | --noheader] [--error ARG] [--warning ARG]-                        [--improved ARG]-                        [--sums | --lengths | --nub | --clocks | --examples |-                          --example | --exampleIO | --noops | --ticks]-                        [-l|--length ARG]-                        [--sumFuse | --sum | --lengthF | --constFuse | --mapInc |-                          --noOp]-    -      perf exploration-    -    Available options:-      -n,--runs ARG            number of runs to perform-      --best                   report upper decile-      --median                 report median-      --average                report average-      --time                   measure time performance-      --space                  measure space performance-      --spacetime              measure both space and time performance-      --allocation             measure bytes allocated-      --count                  measure count-      -g,--golden ARG          golden file name-      --nocheck                do not check versus the golden file-      -r,--record              record the result to the golden file-      --header                 include headers-      --noheader               dont include headers-      --error ARG              error level-      --warning ARG            warning level-      --improved ARG           improved level-      --sums                   run on sum algorithms-      --lengths                run on length algorithms-      --nub                    nub test-      --clocks                 clock test-      --examples               run on example algorithms-      --example                run on the example algorithm-      --exampleIO              exampleIO test-      --noops                  noops test-      --ticks                  tick test-      -l,--length ARG          length of list-      --sumFuse                fused sum pipeline-      --sum                    sum-      --lengthF                foldr id length-      --constFuse              fused const pipeline-      --mapInc                 fmap (+1)-      --noOp                   const ()-      -h,--help                Show this help text--    fmap averageI <$> execPerfT (times 10000) (sum |$| [1..1000])--    fromList [("",136055.5594)]--The equivalent to the above code is:--    perf-explore -n 10000 -l 1000 --sum --nocheck--    label1          label2          results-    -    sum             time            6.32e3---<a id="org2d42223"></a>--## noops--This no-op experiment is useful to understand the pure time performance of the machinery around measurement. It can be (re)run with:--    perf-explore --noops--    label1          label2          label3          old result      new result      change-    -    const           1st             time            1.72e4          8.79e3          improvement-    const           2nd             time            2.09e2          1.25e2          improvement-    const           3rd             time            1.66e2          1.25e2          improvement-    const           4th             time            2.08e2          8.30e1          improvement-    const           average         time            2.08e2          1.10e2          improvement-    const           best            time            1.31e2          6.31e1          improvement-    const           median          time            1.60e2          7.76e1          improvement-    pure            1st             time            1.00e3          1.25e2          improvement-    pure            2nd             time            1.67e2          8.30e1          improvement-    pure            3rd             time            1.66e2          8.30e1          improvement-    pure            4th             time            1.25e2          4.20e1          improvement-    pure            average         time            1.85e2          8.29e1          improvement-    pure            best            time            1.31e2          6.37e1          improvement-    pure            median          time            1.63e2          7.79e1          improvement---<a id="org95a9062"></a>--## measurement context--Exploration of how the code surrounding measurement effects performance.--    perf-explore -n 1000 -l 1000 --ticks --nocheck--<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">---<colgroup>-<col  class="org-left" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />-</colgroup>-<tbody>-<tr>-<td class="org-left">&#xa0;</td>-<td class="org-right">stepTime</td>-<td class="org-right">tick</td>-<td class="org-right">tickForce</td>-<td class="org-right">tickForceArgs</td>-<td class="org-right">tickLazy</td>-<td class="org-right">tickWHNF</td>-<td class="org-right">times</td>-</tr>--<tr>-<td class="org-left">sumAux</td>-<td class="org-right">3.29e3</td>-<td class="org-right">4.83e3</td>-<td class="org-right">3.29e3</td>-<td class="org-right">3.29e3</td>-<td class="org-right">1.85e2</td>-<td class="org-right">3.92e3</td>-<td class="org-right">3.29e3</td>-</tr>--<tr>-<td class="org-left">sumCata</td>-<td class="org-right">5.86e3</td>-<td class="org-right">5.61e3</td>-<td class="org-right">6.00e3</td>-<td class="org-right">6.12e3</td>-<td class="org-right">1.85e2</td>-<td class="org-right">5.78e3</td>-<td class="org-right">5.86e3</td>-</tr>--<tr>-<td class="org-left">sumCo</td>-<td class="org-right">3.73e3</td>-<td class="org-right">4.63e3</td>-<td class="org-right">3.66e3</td>-<td class="org-right">3.66e3</td>-<td class="org-right">1.90e2</td>-<td class="org-right">4.36e3</td>-<td class="org-right">3.72e3</td>-</tr>--<tr>-<td class="org-left">sumCoCase</td>-<td class="org-right">5.08e3</td>-<td class="org-right">5.10e3</td>-<td class="org-right">4.96e3</td>-<td class="org-right">4.95e3</td>-<td class="org-right">1.85e2</td>-<td class="org-right">5.12e3</td>-<td class="org-right">5.11e3</td>-</tr>--<tr>-<td class="org-left">sumCoGo</td>-<td class="org-right">3.47e3</td>-<td class="org-right">4.74e3</td>-<td class="org-right">4.66e3</td>-<td class="org-right">4.64e3</td>-<td class="org-right">1.85e2</td>-<td class="org-right">4.72e3</td>-<td class="org-right">3.29e3</td>-</tr>--<tr>-<td class="org-left">sumF</td>-<td class="org-right">5.92e3</td>-<td class="org-right">4.85e3</td>-<td class="org-right">4.84e3</td>-<td class="org-right">6.41e3</td>-<td class="org-right">1.85e2</td>-<td class="org-right">4.85e3</td>-<td class="org-right">5.91e3</td>-</tr>--<tr>-<td class="org-left">sumFlip</td>-<td class="org-right">4.54e3</td>-<td class="org-right">4.45e3</td>-<td class="org-right">4.44e3</td>-<td class="org-right">4.44e3</td>-<td class="org-right">1.85e2</td>-<td class="org-right">4.44e3</td>-<td class="org-right">4.26e3</td>-</tr>--<tr>-<td class="org-left">sumFlipLazy</td>-<td class="org-right">4.52e3</td>-<td class="org-right">4.51e3</td>-<td class="org-right">4.47e3</td>-<td class="org-right">4.47e3</td>-<td class="org-right">1.85e2</td>-<td class="org-right">4.49e3</td>-<td class="org-right">4.50e3</td>-</tr>--<tr>-<td class="org-left">sumFoldr</td>-<td class="org-right">5.55e3</td>-<td class="org-right">4.78e3</td>-<td class="org-right">4.71e3</td>-<td class="org-right">4.72e3</td>-<td class="org-right">1.85e2</td>-<td class="org-right">4.77e3</td>-<td class="org-right">5.56e3</td>-</tr>--<tr>-<td class="org-left">sumFuse</td>-<td class="org-right">8.28e2</td>-<td class="org-right">8.33e2</td>-<td class="org-right">8.29e2</td>-<td class="org-right">8.29e2</td>-<td class="org-right">1.86e2</td>-<td class="org-right">8.28e2</td>-<td class="org-right">8.29e2</td>-</tr>--<tr>-<td class="org-left">sumFuseFoldl&rsquo;</td>-<td class="org-right">2.03e3</td>-<td class="org-right">8.29e2</td>-<td class="org-right">8.32e2</td>-<td class="org-right">8.29e2</td>-<td class="org-right">1.84e2</td>-<td class="org-right">8.29e2</td>-<td class="org-right">8.29e2</td>-</tr>--<tr>-<td class="org-left">sumFuseFoldr</td>-<td class="org-right">1.17e3</td>-<td class="org-right">1.17e3</td>-<td class="org-right">1.18e3</td>-<td class="org-right">1.17e3</td>-<td class="org-right">1.84e2</td>-<td class="org-right">1.19e3</td>-<td class="org-right">1.17e3</td>-</tr>--<tr>-<td class="org-left">sumFusePoly</td>-<td class="org-right">8.40e2</td>-<td class="org-right">8.37e2</td>-<td class="org-right">8.35e2</td>-<td class="org-right">8.36e2</td>-<td class="org-right">1.84e2</td>-<td class="org-right">8.40e2</td>-<td class="org-right">8.37e2</td>-</tr>--<tr>-<td class="org-left">sumLambda</td>-<td class="org-right">3.67e3</td>-<td class="org-right">5.03e3</td>-<td class="org-right">3.67e3</td>-<td class="org-right">3.67e3</td>-<td class="org-right">1.85e2</td>-<td class="org-right">3.78e3</td>-<td class="org-right">3.67e3</td>-</tr>--<tr>-<td class="org-left">sumMono</td>-<td class="org-right">3.66e3</td>-<td class="org-right">5.13e3</td>-<td class="org-right">5.12e3</td>-<td class="org-right">7.20e3</td>-<td class="org-right">1.84e2</td>-<td class="org-right">5.13e3</td>-<td class="org-right">3.66e3</td>-</tr>--<tr>-<td class="org-left">sumPoly</td>-<td class="org-right">4.83e3</td>-<td class="org-right">4.85e3</td>-<td class="org-right">4.83e3</td>-<td class="org-right">4.84e3</td>-<td class="org-right">1.86e2</td>-<td class="org-right">4.84e3</td>-<td class="org-right">4.84e3</td>-</tr>--<tr>-<td class="org-left">sumSum</td>-<td class="org-right">4.55e3</td>-<td class="org-right">4.83e3</td>-<td class="org-right">4.53e3</td>-<td class="org-right">4.53e3</td>-<td class="org-right">1.85e2</td>-<td class="org-right">6.02e3</td>-<td class="org-right">4.55e3</td>-</tr>--<tr>-<td class="org-left">sumTail</td>-<td class="org-right">4.54e3</td>-<td class="org-right">7.07e3</td>-<td class="org-right">5.81e3</td>-<td class="org-right">4.96e3</td>-<td class="org-right">3.27e2</td>-<td class="org-right">6.49e3</td>-<td class="org-right">4.43e3</td>-</tr>--<tr>-<td class="org-left">sumTailLazy</td>-<td class="org-right">6.24e3</td>-<td class="org-right">4.41e3</td>-<td class="org-right">6.47e3</td>-<td class="org-right">6.23e3</td>-<td class="org-right">2.03e2</td>-<td class="org-right">5.49e3</td>-<td class="org-right">6.24e3</td>-</tr>-</tbody>-</table>---<a id="orgdb37d7c"></a>--### short list--    perf-explore -n 10000 -l 10 --median --ticks--<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">---<colgroup>-<col  class="org-left" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />-</colgroup>-<tbody>-<tr>-<td class="org-left">&#xa0;</td>-<td class="org-right">stepTime</td>-<td class="org-right">tick</td>-<td class="org-right">tickForce</td>-<td class="org-right">tickForceArgs</td>-<td class="org-right">tickLazy</td>-<td class="org-right">tickWHNF</td>-<td class="org-right">times</td>-</tr>--<tr>-<td class="org-left">sumAux</td>-<td class="org-right">2.17e2</td>-<td class="org-right">2.21e2</td>-<td class="org-right">2.18e2</td>-<td class="org-right">2.19e2</td>-<td class="org-right">1.85e2</td>-<td class="org-right">2.17e2</td>-<td class="org-right">2.18e2</td>-</tr>--<tr>-<td class="org-left">sumCata</td>-<td class="org-right">2.16e2</td>-<td class="org-right">2.19e2</td>-<td class="org-right">2.20e2</td>-<td class="org-right">2.21e2</td>-<td class="org-right">1.85e2</td>-<td class="org-right">2.17e2</td>-<td class="org-right">2.18e2</td>-</tr>--<tr>-<td class="org-left">sumCo</td>-<td class="org-right">2.22e2</td>-<td class="org-right">2.34e2</td>-<td class="org-right">2.17e2</td>-<td class="org-right">2.18e2</td>-<td class="org-right">1.85e2</td>-<td class="org-right">2.17e2</td>-<td class="org-right">2.21e2</td>-</tr>--<tr>-<td class="org-left">sumCoCase</td>-<td class="org-right">2.15e2</td>-<td class="org-right">2.32e2</td>-<td class="org-right">2.18e2</td>-<td class="org-right">2.36e2</td>-<td class="org-right">1.91e2</td>-<td class="org-right">2.18e2</td>-<td class="org-right">2.18e2</td>-</tr>--<tr>-<td class="org-left">sumCoGo</td>-<td class="org-right">2.16e2</td>-<td class="org-right">2.23e2</td>-<td class="org-right">2.18e2</td>-<td class="org-right">2.31e2</td>-<td class="org-right">1.87e2</td>-<td class="org-right">2.16e2</td>-<td class="org-right">2.18e2</td>-</tr>--<tr>-<td class="org-left">sumF</td>-<td class="org-right">2.19e2</td>-<td class="org-right">2.30e2</td>-<td class="org-right">2.19e2</td>-<td class="org-right">2.20e2</td>-<td class="org-right">1.86e2</td>-<td class="org-right">2.19e2</td>-<td class="org-right">2.20e2</td>-</tr>--<tr>-<td class="org-left">sumFlip</td>-<td class="org-right">2.16e2</td>-<td class="org-right">2.34e2</td>-<td class="org-right">2.17e2</td>-<td class="org-right">2.16e2</td>-<td class="org-right">1.85e2</td>-<td class="org-right">2.17e2</td>-<td class="org-right">2.17e2</td>-</tr>--<tr>-<td class="org-left">sumFlipLazy</td>-<td class="org-right">2.16e2</td>-<td class="org-right">2.23e2</td>-<td class="org-right">2.16e2</td>-<td class="org-right">2.17e2</td>-<td class="org-right">1.85e2</td>-<td class="org-right">2.17e2</td>-<td class="org-right">2.18e2</td>-</tr>--<tr>-<td class="org-left">sumFoldr</td>-<td class="org-right">2.14e2</td>-<td class="org-right">2.31e2</td>-<td class="org-right">2.17e2</td>-<td class="org-right">2.17e2</td>-<td class="org-right">1.85e2</td>-<td class="org-right">2.17e2</td>-<td class="org-right">2.18e2</td>-</tr>--<tr>-<td class="org-left">sumFuse</td>-<td class="org-right">2.02e2</td>-<td class="org-right">2.03e2</td>-<td class="org-right">2.03e2</td>-<td class="org-right">2.03e2</td>-<td class="org-right">1.85e2</td>-<td class="org-right">2.03e2</td>-<td class="org-right">2.03e2</td>-</tr>--<tr>-<td class="org-left">sumFuseFoldl&rsquo;</td>-<td class="org-right">2.02e2</td>-<td class="org-right">2.03e2</td>-<td class="org-right">2.03e2</td>-<td class="org-right">2.03e2</td>-<td class="org-right">1.85e2</td>-<td class="org-right">2.03e2</td>-<td class="org-right">2.03e2</td>-</tr>--<tr>-<td class="org-left">sumFuseFoldr</td>-<td class="org-right">2.04e2</td>-<td class="org-right">2.04e2</td>-<td class="org-right">2.07e2</td>-<td class="org-right">2.04e2</td>-<td class="org-right">1.94e2</td>-<td class="org-right">2.05e2</td>-<td class="org-right">2.04e2</td>-</tr>--<tr>-<td class="org-left">sumFusePoly</td>-<td class="org-right">2.05e2</td>-<td class="org-right">2.05e2</td>-<td class="org-right">2.05e2</td>-<td class="org-right">2.05e2</td>-<td class="org-right">1.85e2</td>-<td class="org-right">2.05e2</td>-<td class="org-right">2.05e2</td>-</tr>--<tr>-<td class="org-left">sumLambda</td>-<td class="org-right">2.18e2</td>-<td class="org-right">2.39e2</td>-<td class="org-right">2.18e2</td>-<td class="org-right">2.19e2</td>-<td class="org-right">1.84e2</td>-<td class="org-right">2.20e2</td>-<td class="org-right">2.19e2</td>-</tr>--<tr>-<td class="org-left">sumMono</td>-<td class="org-right">2.08e2</td>-<td class="org-right">2.31e2</td>-<td class="org-right">2.08e2</td>-<td class="org-right">2.11e2</td>-<td class="org-right">1.92e2</td>-<td class="org-right">2.09e2</td>-<td class="org-right">2.09e2</td>-</tr>--<tr>-<td class="org-left">sumPoly</td>-<td class="org-right">2.18e2</td>-<td class="org-right">2.32e2</td>-<td class="org-right">2.19e2</td>-<td class="org-right">2.19e2</td>-<td class="org-right">1.85e2</td>-<td class="org-right">2.20e2</td>-<td class="org-right">2.20e2</td>-</tr>--<tr>-<td class="org-left">sumSum</td>-<td class="org-right">2.18e2</td>-<td class="org-right">2.33e2</td>-<td class="org-right">2.19e2</td>-<td class="org-right">2.19e2</td>-<td class="org-right">1.85e2</td>-<td class="org-right">2.20e2</td>-<td class="org-right">2.19e2</td>-</tr>--<tr>-<td class="org-left">sumTail</td>-<td class="org-right">2.52e2</td>-<td class="org-right">4.19e2</td>-<td class="org-right">2.95e2</td>-<td class="org-right">2.60e2</td>-<td class="org-right">2.69e2</td>-<td class="org-right">3.64e2</td>-<td class="org-right">2.42e2</td>-</tr>--<tr>-<td class="org-left">sumTailLazy</td>-<td class="org-right">2.09e2</td>-<td class="org-right">2.42e2</td>-<td class="org-right">2.13e2</td>-<td class="org-right">2.10e2</td>-<td class="org-right">1.90e2</td>-<td class="org-right">2.28e2</td>-<td class="org-right">2.11e2</td>-</tr>-</tbody>-</table>---<a id="org56b0098"></a>--### long list--    perf-explore -n 100 -l 100000 --best --ticks--<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">---<colgroup>-<col  class="org-left" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />--<col  class="org-right" />-</colgroup>-<tbody>-<tr>-<td class="org-left">&#xa0;</td>-<td class="org-right">stepTime</td>-<td class="org-right">tick</td>-<td class="org-right">tickForce</td>-<td class="org-right">tickForceArgs</td>-<td class="org-right">tickLazy</td>-<td class="org-right">tickWHNF</td>-<td class="org-right">times</td>-</tr>--<tr>-<td class="org-left">sumAux</td>-<td class="org-right">7.38e5</td>-<td class="org-right">7.38e5</td>-<td class="org-right">7.36e5</td>-<td class="org-right">7.36e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">7.38e5</td>-<td class="org-right">7.38e5</td>-</tr>--<tr>-<td class="org-left">sumCata</td>-<td class="org-right">7.40e5</td>-<td class="org-right">7.40e5</td>-<td class="org-right">7.38e5</td>-<td class="org-right">7.39e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">7.40e5</td>-<td class="org-right">7.40e5</td>-</tr>--<tr>-<td class="org-left">sumCo</td>-<td class="org-right">7.40e5</td>-<td class="org-right">7.41e5</td>-<td class="org-right">7.38e5</td>-<td class="org-right">7.38e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">7.41e5</td>-<td class="org-right">7.39e5</td>-</tr>--<tr>-<td class="org-left">sumCoCase</td>-<td class="org-right">7.39e5</td>-<td class="org-right">7.39e5</td>-<td class="org-right">7.36e5</td>-<td class="org-right">7.36e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">7.40e5</td>-<td class="org-right">7.38e5</td>-</tr>--<tr>-<td class="org-left">sumCoGo</td>-<td class="org-right">7.39e5</td>-<td class="org-right">7.39e5</td>-<td class="org-right">7.36e5</td>-<td class="org-right">7.36e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">7.39e5</td>-<td class="org-right">7.39e5</td>-</tr>--<tr>-<td class="org-left">sumF</td>-<td class="org-right">3.52e5</td>-<td class="org-right">3.52e5</td>-<td class="org-right">3.52e5</td>-<td class="org-right">3.52e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">3.52e5</td>-<td class="org-right">3.52e5</td>-</tr>--<tr>-<td class="org-left">sumFlip</td>-<td class="org-right">3.75e5</td>-<td class="org-right">3.75e5</td>-<td class="org-right">3.75e5</td>-<td class="org-right">3.75e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">3.75e5</td>-<td class="org-right">3.75e5</td>-</tr>--<tr>-<td class="org-left">sumFlipLazy</td>-<td class="org-right">3.65e5</td>-<td class="org-right">3.65e5</td>-<td class="org-right">3.65e5</td>-<td class="org-right">3.65e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">3.65e5</td>-<td class="org-right">3.65e5</td>-</tr>--<tr>-<td class="org-left">sumFoldr</td>-<td class="org-right">7.51e5</td>-<td class="org-right">7.52e5</td>-<td class="org-right">7.47e5</td>-<td class="org-right">7.48e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">7.51e5</td>-<td class="org-right">7.51e5</td>-</tr>--<tr>-<td class="org-left">sumFuse</td>-<td class="org-right">6.26e4</td>-<td class="org-right">6.26e4</td>-<td class="org-right">6.26e4</td>-<td class="org-right">6.26e4</td>-<td class="org-right">1.66e2</td>-<td class="org-right">6.26e4</td>-<td class="org-right">6.26e4</td>-</tr>--<tr>-<td class="org-left">sumFuseFoldl&rsquo;</td>-<td class="org-right">6.26e4</td>-<td class="org-right">6.26e4</td>-<td class="org-right">6.26e4</td>-<td class="org-right">6.26e4</td>-<td class="org-right">1.66e2</td>-<td class="org-right">6.26e4</td>-<td class="org-right">6.26e4</td>-</tr>--<tr>-<td class="org-left">sumFuseFoldr</td>-<td class="org-right">4.97e5</td>-<td class="org-right">4.95e5</td>-<td class="org-right">4.96e5</td>-<td class="org-right">4.97e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">4.96e5</td>-<td class="org-right">4.97e5</td>-</tr>--<tr>-<td class="org-left">sumFusePoly</td>-<td class="org-right">6.26e4</td>-<td class="org-right">6.26e4</td>-<td class="org-right">6.26e4</td>-<td class="org-right">6.26e4</td>-<td class="org-right">1.66e2</td>-<td class="org-right">6.26e4</td>-<td class="org-right">6.26e4</td>-</tr>--<tr>-<td class="org-left">sumLambda</td>-<td class="org-right">3.73e5</td>-<td class="org-right">3.71e5</td>-<td class="org-right">3.71e5</td>-<td class="org-right">3.71e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">3.71e5</td>-<td class="org-right">3.73e5</td>-</tr>--<tr>-<td class="org-left">sumMono</td>-<td class="org-right">3.95e5</td>-<td class="org-right">3.95e5</td>-<td class="org-right">3.95e5</td>-<td class="org-right">3.95e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">3.95e5</td>-<td class="org-right">3.95e5</td>-</tr>--<tr>-<td class="org-left">sumPoly</td>-<td class="org-right">3.85e5</td>-<td class="org-right">3.85e5</td>-<td class="org-right">3.84e5</td>-<td class="org-right">3.84e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">3.85e5</td>-<td class="org-right">3.85e5</td>-</tr>--<tr>-<td class="org-left">sumSum</td>-<td class="org-right">4.06e5</td>-<td class="org-right">4.06e5</td>-<td class="org-right">4.06e5</td>-<td class="org-right">4.06e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">4.06e5</td>-<td class="org-right">4.06e5</td>-</tr>--<tr>-<td class="org-left">sumTail</td>-<td class="org-right">3.06e5</td>-<td class="org-right">3.53e5</td>-<td class="org-right">3.06e5</td>-<td class="org-right">3.06e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">3.08e5</td>-<td class="org-right">3.06e5</td>-</tr>--<tr>-<td class="org-left">sumTailLazy</td>-<td class="org-right">3.01e5</td>-<td class="org-right">3.01e5</td>-<td class="org-right">3.01e5</td>-<td class="org-right">3.01e5</td>-<td class="org-right">1.66e2</td>-<td class="org-right">3.01e5</td>-<td class="org-right">3.01e5</td>-</tr>-</tbody>-</table>---<a id="orgff01033"></a>--## sums--    perf-explore -n 1000 -l 1000 --sums--    label1          label2          old result      new result      change-    -    sumAux          time            5.53e3          5.21e3          improvement-    sumCata         time            5.18e3          4.73e3          improvement-    sumCo           time            6.50e3          6.40e3-    sumCoCase       time            5.16e3          6.03e3          slightly-degraded-    sumCoGo         time            6.11e3          5.88e3-    sumF            time            5.44e3          4.16e3          improvement-    sumFlip         time            7.23e3          7.07e3-    sumFlipLazy     time            6.68e3          6.44e3-    sumFoldr        time            5.23e3          5.00e3-    sumFuse         time            6.85e2          6.81e2-    sumFuseFoldl'   time            6.94e2          6.78e2-    sumFuseFoldr    time            1.04e3          1.02e3-    sumFusePoly     time            6.96e2          6.84e2-    sumLambda       time            4.79e3          4.77e3-    sumMono         time            4.82e3          4.84e3-    sumPoly         time            4.77e3          4.81e3-    sumSum          time            4.95e3          5.05e3-    sumTail         time            7.32e3          7.10e3-    sumTailLazy     time            6.75e3          6.52e3---<a id="org5abd0c1"></a>--## lengths--    perf-explore -n 1000 -l 1000 --lengths--    label1          label2          old result      new result      change          -    -    lengthAux       time            4.44e3          3.68e3          improvement     -    lengthCo        time            4.91e3          4.45e3          improvement     -    lengthCoCase    time            4.90e3          4.44e3          improvement-    lengthF         time            3.38e3          3.21e3-    lengthFMono     time            4.16e3          4.00e3-    lengthFlip      time            5.49e3          4.90e3          improvement-    lengthFlipLazy  time            5.32e3          4.77e3          improvement-    lengthFoldr     time            4.23e3          3.90e3          improvement-    lengthFoldrConsttime            3.98e3          3.74e3          improvement-    lengthTail      time            6.47e3          5.30e3          improvement-    lengthTailLazy  time            6.11e3          5.34e3          improvement---<a id="org01bde6f"></a>--## Space--     perf-explore -n 10 -l 100000 --space +RTS -T -RTS--     label1          label2          old result      new result      change-    -     sum             MaxMem          4.61e6          4.61e6-     sum             allocated       4.20e5          4.20e5-     sum             gcLiveBytes     2.15e5          2.17e5-     sum             gcollects       1.00e-1         1.00e-1-     sum             maxLiveBytes    0.00e0          0.00e0--Data is collected from GHCStats---   allocated_bytes--   gcs--   gcdetails_live_bytes--   max_live_bytes--   max_mem_in_use_bytes---<a id="org753786d"></a>--# Perf.BigO--Perf.BigO represents functionality to determine the complexity order for a computation.--We could do a regression and minimise the error term, but we know that the largest run contains the most information; we would need to weight the simulations according to some heuristic.--Instead, we:---   estimate the order factor for each possible Order, from N3 to N0, setting the highest n run constant factor to zero,--   pick the order based on lowest absolute error result summed across all the runs,--    import qualified Prelude as P-    import Data.List (nub)-    estOrder (\x -> sum $ nub [1..x]) 10 [1,10,100,1000]--    BigOrder {bigOrder = N2, bigFactor = 4.05725, bigConstant = 0.0}---<a id="org47311bd"></a>--## Cache speed+[![img](https://img.shields.io/hackage/v/perf.svg)](https://hackage.haskell.org/package/perf) [![img](https://github.com/tonyday567/perf/workflows/haskell-ci.yml/badge.svg)](https://github.com/tonyday567/perf/actions)+++# Features++`perf` is an experimental library with a focus on the low-level empirics of Haskell code performance. If you are looking for a quick and reliable performance benchmark, criterion and tasty-bench are both good choices. If your results are confounding, however, you may need to dig deeper, and this is the problem space of `perf`.++The library:++-   provides a monad transformer, `PerfT`. The criterion API tends towards an atomistic approach - bust code up into snippets, copy-paste into a bench.hs and measure their isolated performance.  In contrast, with `PerfT` performance can be measured within a code snippet&rsquo;s original context. Differing code points can be labelled and measured as part of a single run, encouraging a much faster observation - experimentation - refactor cycle.++-   is polymorphic to what, exactly, is being measured, so that concepts such as counters, debug checks, time and space performance can share treatment.++-   attempts to measure big O for algorithms that can be defined in terms of input size growth.++-   includes live charting of raw performance results via chart-svg and prettychart+++# Usage++Probably the best introduction to `perf` is via the perf-explore executable:++    perf-explore++    label1          label2          old result      new result      change+    +    sum             time            9.93e3          7.57e3          improvement++Summing [1..1000] took 9,930 nanoseconds, an improvement versus the on file performance previously measured.++Live charts of raw performance measurement can be obtained via the prettychart library with:++    prettychart-watch --watch --filepath other --port 3566++&#x2026; and pointer your browser at localhost:3566++    perf-explore -n 1000 --nocheck --chart++![img](other/perf.svg)++In this particular measure, there was an improvement, dropping from about 10,000 nanos to 8,600 nanos. Increasing the number of measurements:++    perf-explore -n 20000 --nocheck --chart --chartpath other/perf20000.svg++![img](other/perf20000.svg)++Improvements seem to continue as n increases before stabilising (after a GC perhaps) at 3,500 nanos++    perf-explore -n 20000 --order --nocheck --tasty++    label1          label2          results+    +    sum             time            3.51e3+    +    sum:time 3.5 * O(N1)+    tasty:time: 3510++The order of the computation (`\l -> fap sum [1 .. l]`) is O(N1) and the results are very close to the tasty-bench result.++In comparsion, (\l -> fap (\x -> sum [1 .. x]) l):++    perf-explore --nocheck --sumFuse -n 100000 --chart --chartpath other/perffuse.svg --order++![img](other/perffuse.svg)++    perf-explore --nocheck --sumFuse -n 100000 --order++    label1          label2          results+    +    sumFuse         time            6.78e2+    +    sumFuse:time 0.66 * O(N1)++&#x2026; is much faster. Hooray for list fusion!+++# Issues+++## fragility++Results, especially for simple computations, are fragile and can show large variance in performance characteristics in identical runs, and across differing compilations. Whether this is due to library flaws or is just the nature of ghc is an open question.+++## Statistics++> Obligatory disclaimer: statistics is a tricky matter, there is no one-size-fits-all approach. In the absence of a good theory simplistic approaches are as (un)sound as obscure ones. Those who seek statistical soundness should rather collect raw data and process it themselves using a proper statistical toolbox. Data reported by tasty-bench is only of indicative and comparative significance. ~ [tasty-bench](https://hackage.haskell.org/package/tasty-bench-0.4/docs/Test-Tasty-Bench.html#t:Benchmarkable)++> variance introduced by outliers: 88% (severely inflated) ~ [criterion](https://hackage.haskell.org/package/criterion)++The library default is to report the 10th percentile as a summary statistic, and this is a matter of taste, determined mostly by the purpose of the measurement.+++## ffap and fap++    :t ffap++    ffap+      :: (Control.DeepSeq.NFData a, Control.DeepSeq.NFData b, MonadIO m,+          Semigroup t) =>+         Text.Text -> (a -> b) -> a -> PerfT m t b++ffap and fap are broadly similar to criterion&rsquo;s nf and whnf respectively, but passes throught the results of the computation into the monad transformer, enabling in-context measurement.++A fine-grained and detailed examination of the effect of measurement on laziness and on core details would be beneficial to the library.+++## tasty++The library was originally developed before tasty-bench, which does a great job of integrating into the tasty api, and a future refactor may integrate with this, rather than supply idiosyncratic methods.+++## order++BigOrder calculations tend to be fragile and sometimes differ from theory.+++# Development++This org file has been used to develop and document library innovation and testing, and may be of use to users in understanding the library. Note that running `perf` via ghci is very slow compared with an external process which accesses the compiled version of the library.++    :r+    :set -Wno-type-defaults+    :set -Wno-unused-do-bind+    :set -Wno-name-shadowing+    :set -XOverloadedStrings+    :set -XOverloadedLabels+    import Perf+    import Perf.Report+    import Data.FormatN+    import qualified Data.Text as Text+    import qualified Data.Text.IO as Text+    import qualified Data.Map.Strict as Map+    import Control.Monad+    import Data.Bifunctor+    import System.Clock+    import Data.List qualified as List+    import Control.Category ((>>>))+    import Optics.Core+    import Data.Foldable+    import NumHask.Space+    putStrLn "ok"+    import Chart hiding (tick)+    import Prettychart+    import Chart.Examples+    import Perf.Chart+    (disp,q) <- startChartServer Nothing+    disp lineExample+    import Prettyprinter+    import Control.Monad.State.Lazy+    import Text.PrettyPrint.Boxes++    Ok, 11 modules loaded.+    ok+    Setting phasegrhsc it>o  stun... (poTrrtu e9+    160) (cgthrcli->c  to quitg)h++    l = 1000+    n = 1000+    +    :{+    p = do+      ffap "sum" sum [1 .. l]+      ffap "sumfuse" (\x -> sum [1 .. x]) l+    :}+    :t p+    run = runPerfT (times n) p+    :t run+    (res, m) <- run+    :t m+    median . fmap fromIntegral <$> m++    ghci| ghci| ghci| ghci| ghci> p :: (MonadIO m, Semigroup t, Control.DeepSeq.NFData b, Num b,+          Enum b) =>+         PerfT m t b+    run+      :: (Control.DeepSeq.NFData a, Num a, Enum a) =>+         IO (a, Map.Map Text.Text [Nanos])+    m :: Map.Map Text.Text [Nanos]+    fromList [("sum",21978.1),("sumfuse",26710.18)]+++# Details+++## System.Clock++The default clock is MonoticRaw for linux & macOS, and ThreadCPUTime for Windows.+++### resolution++    getRes Monotonic+    getRes Realtime+    getRes ProcessCPUTime+    getRes ThreadCPUTime+    getRes MonotonicRaw++    TimeSpec {sec = 0, nsec = 1000}+    TimeSpec {sec = 0, nsec = 1000}+    TimeSpec {sec = 0, nsec = 1000}+    TimeSpec {sec = 0, nsec = 42}+    TimeSpec {sec = 0, nsec = 42}+++## ticks++The various versions of tick and a variety of algorithms are artifacts of ongoing exploration.++    perf-explore -n 20000 --best --ticks++    algo          stepTime   tick tickForce tickForceArgs tickLazy tickWHNF  times timesn+    sumAux          3.11e3 3.11e3    3.11e3        3.11e3   5.13e0   3.11e3 3.11e3 3.10e3+    sumCata         3.11e3 3.11e3    3.11e3        3.11e3   5.11e0   3.11e3 3.11e3 3.14e3+    sumCo           3.11e3 3.11e3    3.11e3        3.11e3   5.06e0   3.11e3 3.11e3 3.08e3+    sumCoCase       3.11e3 3.11e3    3.11e3        3.11e3   5.11e0   3.11e3 3.11e3 3.08e3+    sumCoGo         3.11e3 3.11e3    3.11e3        3.11e3   5.06e0   3.11e3 3.11e3 3.12e3+    sumF            3.48e3 3.49e3    3.46e3        3.46e3   5.06e0   3.48e3 3.48e3 3.48e3+    sumFlip         3.48e3 3.48e3    3.45e3        3.45e3   5.03e0   3.48e3 3.48e3 3.48e3+    sumFlipLazy     3.48e3 3.48e3    3.45e3        3.45e3   4.96e0   3.48e3 3.48e3 3.45e3+    sumFoldr        3.11e3 3.11e3    3.11e3        3.11e3   5.13e0   3.11e3 3.11e3 3.11e3+    sumFuse         6.54e2 6.54e2    6.54e2        6.54e2   5.17e0   6.54e2 6.54e2 6.39e2+    sumFuseFoldl'   6.54e2 6.54e2    6.54e2        6.54e2   5.00e0   6.54e2 6.54e2 6.44e2+    sumFuseFoldr    9.93e2 9.92e2    9.92e2        9.92e2   5.13e0   9.92e2 9.93e2 9.63e2+    sumFusePoly     6.56e2 6.56e2    6.56e2        6.56e2   5.12e0   6.56e2 6.57e2 6.47e2+    sumLambda       3.48e3 3.49e3    3.48e3        3.48e3   5.12e0   3.48e3 3.48e3 3.55e3+    sumMono         3.48e3 3.48e3    3.46e3        3.46e3   5.00e0   3.48e3 3.48e3 3.50e3+    sumPoly         3.62e3 3.49e3    3.54e3        3.56e3   5.04e0   3.71e3 3.62e3 3.70e3+    sumSum          3.48e3 3.49e3    3.48e3        3.48e3   4.98e0   3.48e3 3.48e3 3.49e3+    sumTail         3.48e3 3.49e3    3.45e3        3.45e3   5.00e0   3.48e3 3.48e3 3.51e3+    sumTailLazy     3.48e3 3.48e3    3.45e3        3.45e3   5.16e0   3.48e3 3.48e3 3.49e3+++## Time+++### What is a tick?++A fundamental operation of Perf.Time is tick, which sandwiches a (strict) function application between two readings of a clock, and returns time in nanoseconds, and the computation result. In this way, the \`Perf\` monad can be inserted into the midst of a computation in an attempt to measure performance in-situ as opposed to sitting off in a separate and decontextualized process.++    :t tick++    tick :: (a -> b) -> a -> IO (Nanos, b)++`tick` returns in the IO monad, because reading a cycle counter is an IO effect. A trivial but fundamental point is that performance measurement effects the computation being measured.+++### tick\_++tick\_ measures the nanoseconds between two immediate clock reads.++    :t tick_++    tick_ :: IO Nanos++    replicateM 10 tick_++    [1833,500,416,416,416,375,375,416,416,416]+++### multiple ticks++    fmap (fmap (fst)) . replicateM 10 $ tick (const ()) ()++    [7000,2333,2000,2208,1958,1959,1959,2000,2000,1959]++Here, `const () ()` was evaluated and took 7 micro-seconds for the first effect, reducing down to 2 msecs after 10 effects.+++### tickIO++`tickIO` measures the evaluation of an IO value.++    :t tickIO++    tickIO :: IO a -> IO (Cycles, a)++    fmap (fmap fst) . replicateM 10 $ tickIO (pure ())++    [5541,1625,1458,1833,1375,1416,1375,1375,1375,1375]+++### sum example++    fmap (expt (Just 2) . fromIntegral) . fst <$> ticks 10 sum ([1..10000] :: [Double])++    ["5.0e5","2.4e5","2.4e5","2.4e5","2.4e5","2.4e5","2.4e5","2.4e5","2.5e5","2.4e5"]++    ts <- ticks 10000 sum ([1..1000] :: [Double])+    print $ average (fmap fromIntegral $ fst ts)++    10747.1975+++## PerfT++`PerfT` allows for multiple measurement points and is polymorphic in what is being measured. It returns a Map of results held in State.++Compare a lower-level usage of ticks, measuring the average of summing to one thousand over one thousand trials:++    first (average . fmap fromIntegral) <$> ticks 1000 sum [1..1000]++    (25947.635,500500)++&#x2026; with PerfT usage++    second (fmap (average . fmap fromIntegral)) <$> runPerfT (times 1000) (sum |$| [1..1000])++    (500500,fromList [("",26217.098)])++An IO example++    exampleIO' :: IO ()+    exampleIO' = do+      txt <- Text.readFile "src/Perf.hs"+      let n = Text.length txt+      Text.putStrLn $ "length of file is: " <> Text.pack (show n)++    exampleIO = execPerfT time (do+      txt <- fam "file_read" (Text.readFile "src/Perf.hs")+      n <- fap "length" Text.length txt+      fam "print_result" (Text.putStrLn $ "length of file is: " <> Text.pack (show n)))++    perf-explore --exampleIO++    length of file is: 1794+    length of file is: 1794+    +    label1          label2          label3          old result      new result      change+    +    normal          file-read       time            2.31e5          1.28e5          improvement+    normal          length          time            2.71e3          2.00e3          improvement+    normal          print-result    time            3.75e4          1.32e4          improvement+    outer           file-read       time            6.05e4          3.64e4          improvement+    outer           length          time            9.59e2          6.25e2          improvement+    outer           outer-total     time            7.39e4          4.02e4          improvement+    outer           print-result    time            9.79e3          1.71e3          improvement+++## Perf.BigO++Perf.BigO represents functionality to determine the complexity order for a computation.++We could do a regression and minimise the error term, but we know that the largest run contains the most information; we would need to weight the simulations according to some heuristic.++Instead, we:++-   estimate the order factor for each possible Order, from N3 to N0, setting the highest n run constant factor to zero,+-   pick the order based on lowest absolute error result summed across all the runs,++    import qualified Prelude as P+    import Data.List (nub)+    estOrder (\x -> sum $ nub [1..x]) 100 [10,100,1000,1000]++    BigOrder {bigOrder = N2, bigFactor = 3.187417}++    import qualified Prelude as P+    import Data.List (nub)+    estOrder (\x -> sum $ [1..x]) 10 [1,10,100,1000]++    BigOrder {bigOrder = N12, bigFactor = 695.0370069284081, bigConstant = 0.0}+++## References++<https://wiki.haskell.org/Performance/GHC>++[The Haskell performance checklist](https://github.com/haskell-perf/checklist)++[ndmitchell/spaceleak: Notes on space leaks](https://github.com/ndmitchell/spaceleak)+++### Core++[5.13. Debugging the compiler](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/debugging.html#options-debugging)++    ghc app/speed.hs -ddump-simpl -ddump-to-file -fforce-recomp -dlint -O++[haskell wiki: Looking at the Core](https://wiki.haskell.org/Performance/GHC#Looking_at_the_Core)++[godbolt](https://godbolt.org/)++[ghc issue 15185: Enum instance for IntX / WordX are inefficient](https://gitlab.haskell.org/ghc/ghc/-/issues/15185)++[fixpt - All About Strictness Analysis (part 1)](https://fixpt.de/blog/2017-12-04-strictness-analysis-part-1.html)+++### Profiling++1.  setup++    [8. Profiling](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/profiling.html#prof-heap)+    +    A typical configuration step for profiling:+    +        cabal configure --enable-library-profiling --enable-executable-profiling -fprof-auto -fprof -write-ghc-environment-files=always+    +    A cabal.project.local with profiling enabled:+    +    > write-ghc-environment-files: always+    > ignore-project: False+    > flags: +prof +prof-auto+    > library-profiling: True+    > executable-profiling: True+    +    Examples from markup-parse R&D:+    +    Executable compilation:+    +        ghc -prof -fprof-auto -rtsopts app/speed0.hs -threaded -fforce-recomp+    +    Executable run:+    +        app/speed0 +RTS -s -p -hc -l -RTS++2.  Space usage output (-s)++        885,263,472 bytes allocated in the heap+               8,507,448 bytes copied during GC+                 163,200 bytes maximum residency (4 sample(s))+                  27,752 bytes maximum slop+                       6 MiB total memory in use (0 MiB lost due to fragmentation)+        +                                             Tot time (elapsed)  Avg pause  Max pause+          Gen  0       207 colls,     0 par    0.009s   0.010s     0.0001s    0.0002s+          Gen  1         4 colls,     0 par    0.001s   0.001s     0.0004s    0.0005s+        +          TASKS: 4 (1 bound, 3 peak workers (3 total), using -N1)+        +          SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)+        +          INIT    time    0.006s  (  0.006s elapsed)+          MUT     time    0.367s  (  0.360s elapsed)+          GC      time    0.010s  (  0.011s elapsed)+          RP      time    0.000s  (  0.000s elapsed)+          PROF    time    0.000s  (  0.000s elapsed)+          EXIT    time    0.001s  (  0.001s elapsed)+          Total   time    0.384s  (  0.380s elapsed)++3.  Cost center profile (-p)++    Dumped to speed0.prof+    +        COST CENTRE MODULE                SRC                                            %time %alloc+        +        token       MarkupParse           src/MarkupParse.hs:(259,1)-(260,20)             50.2   50.4+        wrappedQ'   MarkupParse.FlatParse src/MarkupParse/FlatParse.hs:(215,1)-(217,78)   20.8   23.1+        ws_         MarkupParse.FlatParse src/MarkupParse/FlatParse.hs:(135,1)-(146,4)    14.3    5.5+        eq          MarkupParse.FlatParse src/MarkupParse/FlatParse.hs:243:1-30           10.6   11.1+        gather      MarkupParse           src/MarkupParse.hs:(420,1)-(428,100)             2.4    3.7+        runParser   FlatParse.Basic       src/FlatParse/Basic.hs:(217,1)-(225,24)          1.0    6.0++4.  heap analysis (-hc -l)++        eventlog2html speed0.eventlog+    +    Produces speed0.eventlog.html which contains heap charts.+++### Cache speed  The average cycles per + operation can get down to about 0.7 cycles, and there are about 4 cache registers per cycle, so a sum pipeline uses 2.8 register instructions per +.