Notes on profiling
authorNeil Smith <neil.git@njae.me.uk>
Fri, 17 Dec 2021 12:40:19 +0000 (12:40 +0000)
committerNeil Smith <neil.git@njae.me.uk>
Fri, 17 Dec 2021 12:40:19 +0000 (12:40 +0000)
README.html [new file with mode: 0644]
README.md
advent-of-code21.cabal
advent15/Main.hs

diff --git a/README.html b/README.html
new file mode 100644 (file)
index 0000000..ddd45d3
--- /dev/null
@@ -0,0 +1,159 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
+<head>
+  <meta charset="utf-8" />
+  <meta name="generator" content="pandoc" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
+  <title>Advent of Code 2020</title>
+  <style>
+    code{white-space: pre-wrap;}
+    span.smallcaps{font-variant: small-caps;}
+    span.underline{text-decoration: underline;}
+    div.column{display: inline-block; vertical-align: top; width: 50%;}
+    div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
+    ul.task-list{list-style: none;}
+    pre > code.sourceCode { white-space: pre; position: relative; }
+    pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
+    pre > code.sourceCode > span:empty { height: 1.2em; }
+    .sourceCode { overflow: visible; }
+    code.sourceCode > span { color: inherit; text-decoration: inherit; }
+    div.sourceCode { margin: 1em 0; }
+    pre.sourceCode { margin: 0; }
+    @media screen {
+    div.sourceCode { overflow: auto; }
+    }
+    @media print {
+    pre > code.sourceCode { white-space: pre-wrap; }
+    pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
+    }
+    pre.numberSource code
+      { counter-reset: source-line 0; }
+    pre.numberSource code > span
+      { position: relative; left: -4em; counter-increment: source-line; }
+    pre.numberSource code > span > a:first-child::before
+      { content: counter(source-line);
+        position: relative; left: -1em; text-align: right; vertical-align: baseline;
+        border: none; display: inline-block;
+        -webkit-touch-callout: none; -webkit-user-select: none;
+        -khtml-user-select: none; -moz-user-select: none;
+        -ms-user-select: none; user-select: none;
+        padding: 0 4px; width: 4em;
+        color: #aaaaaa;
+      }
+    pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
+    div.sourceCode
+      {   }
+    @media screen {
+    pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
+    }
+    code span.al { color: #ff0000; font-weight: bold; } /* Alert */
+    code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
+    code span.at { color: #7d9029; } /* Attribute */
+    code span.bn { color: #40a070; } /* BaseN */
+    code span.bu { } /* BuiltIn */
+    code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
+    code span.ch { color: #4070a0; } /* Char */
+    code span.cn { color: #880000; } /* Constant */
+    code span.co { color: #60a0b0; font-style: italic; } /* Comment */
+    code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
+    code span.do { color: #ba2121; font-style: italic; } /* Documentation */
+    code span.dt { color: #902000; } /* DataType */
+    code span.dv { color: #40a070; } /* DecVal */
+    code span.er { color: #ff0000; font-weight: bold; } /* Error */
+    code span.ex { } /* Extension */
+    code span.fl { color: #40a070; } /* Float */
+    code span.fu { color: #06287e; } /* Function */
+    code span.im { } /* Import */
+    code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
+    code span.kw { color: #007020; font-weight: bold; } /* Keyword */
+    code span.op { color: #666666; } /* Operator */
+    code span.ot { color: #007020; } /* Other */
+    code span.pp { color: #bc7a00; } /* Preprocessor */
+    code span.sc { color: #4070a0; } /* SpecialChar */
+    code span.ss { color: #bb6688; } /* SpecialString */
+    code span.st { color: #4070a0; } /* String */
+    code span.va { color: #19177c; } /* Variable */
+    code span.vs { color: #4070a0; } /* VerbatimString */
+    code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
+    .display.math{display: block; text-align: center; margin: 0.5rem auto;}
+  </style>
+  <link rel="stylesheet" href="modest.css" />
+  <!--[if lt IE 9]>
+    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
+  <![endif]-->
+</head>
+<body>
+<header id="title-block-header">
+<h1 class="title">Advent of Code 2020</h1>
+</header>
+<p>Code to solve the <a href="http://adventofcode.com/2020/">Advent of Code</a> puzzles. This year, I’m using the puzzles to develop my skills in <a href="https://wiki.haskell.org/Haskell">Haskell</a>. I’m writing up a <a href="https://work.njae.me.uk/tag/advent-of-code/">commentary on these puzzles and my solutions</a> on my blog.</p>
+<p><a href="http://learnyouahaskell.com/chapters">Learn you a Haskell</a>, <a href="https://www.haskell.org/tutorial/index.html">Introduction to Haskell 98</a>, and <a href="https://hackage.haskell.org/">Hackage</a> are good resources.</p>
+<p>The <a href="https://cabal.readthedocs.io/en/latest/index.html">Cabal user guide</a> and <a href="http://howistart.org/posts/haskell/1/">How I Start: Haskell</a> are good sources of using the tools.</p>
+<h1 id="toolchain">Toolchain</h1>
+<p>Install Ghcup following <a href="https://www.haskell.org/ghcup/install/#installation">the instructions</a>, making sure to load the updated environment with</p>
+<div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="bu">source</span> /home/neil/.ghcup/env</span></code></pre></div>
+<p>and then set the default GHC to use with <code>ghcup set ghc 9.0.1</code> .</p>
+<p>Install <a href="https://haskell-language-server.readthedocs.io/en/latest/configuration.html">Haskell Language Server</a> for Sublime Text</p>
+<h2 id="creating-the-repository-and-project">Creating the repository and project</h2>
+<p>Create the repository as normal: create the project in Gitolite, clone it, and insert the <code>.gitignore</code> and <code>README.md</code> files.</p>
+<p>There’s one package per day, with the code for each package in sub-directories of the root directory.</p>
+<p>Create the basic <code>cabal</code> project.</p>
+<pre><code>cabal init</code></pre>
+<p>Modify the <code>advent-of-code21.cabal</code> file as needed, such as updating the Cabal version and writing the <code>common</code> stanzas.</p>
+<h2 id="creating-subsequent-days">Creating subsequent days</h2>
+<p>Each day lives in a separate directory, with code in the <code>src</code> directory.</p>
+<p>Compile with</p>
+<pre><code>cabal build</code></pre>
+<p>or</p>
+<pre><code>cabal build advent01</code></pre>
+<p>Run with</p>
+<pre><code>cabal run advent01</code></pre>
+<p>If you want to pass in additional RTS parameters, do it like this:</p>
+<pre><code>cabal run advent01 -- +RTS -K0 -RTS</code></pre>
+<p>Run interactively with</p>
+<pre><code>cabal repl advent01</code></pre>
+<p>or</p>
+<pre><code>stack ghci advent01:exe:advent01</code></pre>
+<p>if the first form is ambiguous.</p>
+<p>To profile, use</p>
+<pre><code>cabal run advent01 --enable-profiling -- +RTS -N -p -s -hT</code></pre>
+<p>Or, you can simplify the RTS options by adding them to a new stanza in the cabal file:</p>
+<pre><code>executable advent01prof
+  import: common-extensions, build-directives
+  main-is: advent01/Main.hs
+  build-depends: text, containers, linear, array, pqueue, mtl, lens
+  ghc-options:         -O2 
+                       -Wall 
+                       -threaded 
+                       -rtsopts &quot;-with-rtsopts=-N -p -s -hT&quot;</code></pre>
+<p>then running</p>
+<pre><code>cabal run advent01prof --enable-profiling</code></pre>
+<p>Generate the profile graph with</p>
+<pre><code>hp2ps -M advent01.hp</code></pre>
+<p>For Cabal, look at <a href="https://nikita-volkov.github.io/profiling-cabal-projects/">profiling with Cabal sandboxes</a></p>
+<h1 id="packages">Packages</h1>
+<p>Packages I used a lot:</p>
+<ul>
+<li><a href="https://hackage.haskell.org/package/containers">Containers</a> (and some <a href="https://haskell-containers.readthedocs.io/en/latest/intro.html">better documentation</a>); <a href="https://hackage.haskell.org/package/unordered-containers">Unordered containers</a> is a mostly-equivalent alternative.</li>
+<li><a href="https://hackage.haskell.org/package/attoparsec">Attoparsec</a> (and <a href="https://hackage.haskell.org/package/megaparsec">Megaparsec</a>, and <a href="https://hackage.haskell.org/package/base-4.14.1.0/docs/Text-ParserCombinators-ReadP.html">ReadP</a> once).</li>
+</ul>
+<p>There are somewhat decent <a href="https://markkarpov.com/tutorial/megaparsec.html">tutorials on Megaparsec</a> and <a href="https://www.schoolofhaskell.com/school/starting-with-haskell/libraries-and-frameworks/text-manipulation/attoparsec">Attoparsec</a>.</p>
+<p>Packages I didn’t use much, but need to remember:</p>
+<ul>
+<li><a href="https://hackage.haskell.org/package/arithmoi">Arithmoi</a> for number theory</li>
+<li><a href="https://hackage.haskell.org/package/pointedlist-0.6.1">Pointed List</a> for zipper lists (sometimes circular)</li>
+<li><a href="https://hackage.haskell.org/package/vector">Vector</a> for array-like things</li>
+<li><a href="https://hackage.haskell.org/package/linear">Linear</a> for coordinate-vector like things</li>
+<li><a href="https://hackage.haskell.org/package/grid">Grid</a> for 2-d grids</li>
+<li><a href="https://hackage.haskell.org/package/graph-wrapper">Graph-wrapper</a> for graphs</li>
+<li><a href="https://hackage.haskell.org/package/lens">Lens</a> (and a <a href="https://github.com/ekmett/lens/wiki/Operators">summary of operators</a>). I didn’t use these much this year, but did a lot last year.</li>
+<li><a href="https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-RWS-Lazy.html">RWS</a> (Reader-Writer-State monad stack); again, used a lot last year but not this year</li>
+<li><a href="https://hackage.haskell.org/package/monad-loops-0.4.3/docs/Control-Monad-Loops.html">Monad loops</a>, and <a href="https://conscientiousprogrammer.com/blog/2015/12/11/24-days-of-hackage-2015-day-11-monad-loops-avoiding-writing-recursive-functions-by-refactoring/">a description</a></li>
+<li><a href="https://github.com/jamesdbrock/replace-megaparsec">Replace-Megaparsec</a>, for using Mpc for all sorts of things traditionally done with regex substitutions.</li>
+</ul>
+<h1 id="readme">Readme</h1>
+<p>Build this readme file wth</p>
+<pre><code>pandoc -s README.md &gt; README.html</code></pre>
+<p>(Using the <a href="https://github.com/markdowncss/modest">Modest style</a>.)</p>
+</body>
+</html>
index f7151b3343de5e14b7c2d78cb9195d5d8fb49c8a..7b831f2215ffe46de645d00f3146285c08526de7 100644 (file)
--- a/README.md
+++ b/README.md
@@ -7,8 +7,7 @@ Code to solve the [Advent of Code](http://adventofcode.com/2020/) puzzles. This
 
 [Learn you a Haskell](http://learnyouahaskell.com/chapters), [Introduction to Haskell 98](https://www.haskell.org/tutorial/index.html), and [Hackage](https://hackage.haskell.org/) are good resources.
 
-The [Stack documentation](https://docs.haskellstack.org/en/stable/README/) and [How I Start: Haskell](http://howistart.org/posts/haskell/1/) are good sources of using the tools. 
-
+The [Cabal user guide](https://cabal.readthedocs.io/en/latest/index.html) and [How I Start: Haskell](http://howistart.org/posts/haskell/1/) are good sources of using the tools. 
 
 # Toolchain
 
@@ -38,7 +37,7 @@ Modify the `advent-of-code21.cabal` file as needed, such as updating the Cabal v
 
 ## Creating subsequent days
 
-Each day lives in a separate directory, with its own `package.yaml` file and code in the `src` directory. (I based this configuration from [mstksg's setup](https://github.com/mstksg/advent-of-code-2018).)
+Each day lives in a separate directory, with code in the `src` directory. 
 
 Compile with
 ```
@@ -56,7 +55,7 @@ cabal run advent01
 
 If you want to pass in additional RTS parameters, do it like this:
 ```
-stack exec -- advent01 +RTS -K0 -RTS
+cabal run advent01 -- +RTS -K0 -RTS
 ```
 
 Run interactively with
@@ -70,16 +69,34 @@ stack ghci advent01:exe:advent01
 if the first form is ambiguous. 
 
 To profile, use 
+
 ```
-stack build --executable-profiling --library-profiling --ghc-options="-fprof-auto -rtsopts" advent01
+cabal run advent01 --enable-profiling -- +RTS -N -p -s -hT
 ```
-then run with
+
+Or, you can simplify the RTS options by adding them to a new stanza in the cabal file:
+
 ```
-stack exec --profile -- advent01 +RTS -p -hy
+executable advent01prof
+  import: common-extensions, build-directives
+  main-is: advent01/Main.hs
+  build-depends: text, containers, linear, array, pqueue, mtl, lens
+  ghc-options:         -O2 
+                       -Wall 
+                       -threaded 
+                       -rtsopts "-with-rtsopts=-N -p -s -hT"
 ```
+
+then running 
+
+```
+cabal run advent01prof --enable-profiling
+```
+
+
 Generate the profile graph with
 ```
-stack exec hp2ps advent01.hp
+hp2ps -M advent01.hp
 ```
 
 For Cabal, look at [profiling with Cabal sandboxes](https://nikita-volkov.github.io/profiling-cabal-projects/)
@@ -87,8 +104,6 @@ For Cabal, look at [profiling with Cabal sandboxes](https://nikita-volkov.github
 
 # Packages
 
-Stack is using the [14.16-lts resolver](https://www.stackage.org/lts-16.25) for packages, so make sure you read the [correct documentation for the packages included in it](https://www.stackage.org/lts-16.25/docs). 
-
 Packages I used a lot:
 
 * [Containers](https://hackage.haskell.org/package/containers) (and some [better documentation](https://haskell-containers.readthedocs.io/en/latest/intro.html)); [Unordered containers](https://hackage.haskell.org/package/unordered-containers) is a mostly-equivalent alternative.
index 2ef838cdbf2799394cf5a7a3aa47a8bd8745e804..d200a4fd29fc5a832bf20fb1c75ae74378f906ba 100644 (file)
@@ -1,11 +1,11 @@
-  cabal-version:       3.6
-  -- Initial package description 'advent-of-code21.cabal' generated by 'cabal
-  --  init'.  For further documentation, see
-  -- http://haskell.org/cabal/users-guide/
-
-  name:                advent-of-code21
-  version:             0.1.0.0
-  synopsis: Advent of Code 21 solutions
+cabal-version:       3.6
+-- Initial package description 'advent-of-code21.cabal' generated by 'cabal
+--  init'.  For further documentation, see
+-- http://haskell.org/cabal/users-guide/
+
+name:                advent-of-code21
+version:             0.1.0.0
+synopsis: Advent of Code 21 solutions
 -- description:
 -- bug-reports:
 license: MIT
@@ -169,9 +169,9 @@ executable advent15prof
   import: common-extensions, build-directives
   main-is: advent15/Main.hs
   build-depends: text, containers, linear, array, pqueue, mtl, lens
-  profiling: True
-  library-profiling: True
-  profiling-detail: toplevel-functions
+  -- profiling: True
+  -- library-profiling: True
+  -- profiling-detail: toplevel-functions
   ghc-options:         -O2 
                        -Wall 
                        -threaded 
index 758bdc6efc026c0428b800262dd6fae8cf437d5d..40a152a188969791c03f5dbc986ccc495b8b984f 100644 (file)
@@ -35,7 +35,6 @@ makeLenses ''Cave
 
 type CaveContext = Reader Cave
 
-
 data Agendum s = 
     Agendum { _current :: s
             , _trail :: Q.Seq s
@@ -50,9 +49,9 @@ type ExploredStates s = S.Set s
 
 class (Eq s, Ord s, Show s) => SearchState s where
     unwrapPos :: s -> BasePosition
+    emptySearchState :: s
     successors :: s -> CaveContext (Q.Seq s)
     estimateCost :: s -> CaveContext Int
-    emptySearchState :: s
     isGoal :: s -> CaveContext Bool
     entryCost :: s -> CaveContext Int
 
@@ -64,37 +63,37 @@ instance SearchState Position where
   emptySearchState = Position (V2 0 0)
 
   -- successors :: Position -> CaveContext (Q.Seq Position)
-  successors here = 
+  successors (Position here) = 
     do grid <- asks _grid
        let neighbours = 
             filter (inRange (bounds grid))  
-              [ (unwrapPos here) ^+^ delta
+              [ here ^+^ delta
               | delta <- [V2 -1 0, V2 1 0, V2 0 -1, V2 0 1]
               ]
        let succs = Q.fromList $ map Position neighbours
        return succs
 
   -- estimateCost :: Position -> CaveContext Int
-  estimateCost here = 
+  estimateCost (Position here) = 
     do goal <- asks _goal
-       let (V2 dr dc) = (unwrapPos here) ^-^ goal
+       let (V2 dr dc) = here ^-^ goal
        return $ (abs dr) + (abs dc)
 
   -- isGoal :: here -> CaveContext Bool
-  isGoal here = 
+  isGoal (Position here) = 
     do goal <- asks _goal
-       return $ (unwrapPos here) == goal
+       return $ here == goal
 
-  entryCost here = 
+  entryCost (Position here) = 
     do grid <- asks _grid
-       return $ grid ! (unwrapPos here)
+       return $ grid ! here
 
 instance SearchState TiledPosition where
 
-  emptySearchState = TiledPosition (V2 0 0)
-
   unwrapPos (TiledPosition p) = p
 
+  emptySearchState = TiledPosition (V2 0 0)
+
   -- successors :: Position -> CaveContext (Q.Seq Position)
   successors (TiledPosition here) = 
     do grid <- asks _grid