From da7ce507eaddb2c950ec7c08b3fe91d10e49bfeb Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Fri, 17 Dec 2021 12:40:19 +0000 Subject: [PATCH] Notes on profiling --- README.html | 159 +++++++++++++++++++++++++++++++++++++++++ README.md | 35 ++++++--- advent-of-code21.cabal | 22 +++--- advent15/Main.hs | 23 +++--- 4 files changed, 206 insertions(+), 33 deletions(-) create mode 100644 README.html diff --git a/README.html b/README.html new file mode 100644 index 0000000..ddd45d3 --- /dev/null +++ b/README.html @@ -0,0 +1,159 @@ + + + + + + + Advent of Code 2020 + + + + + +
+

Advent of Code 2020

+
+

Code to solve the Advent of Code puzzles. This year, I’m using the puzzles to develop my skills in Haskell. I’m writing up a commentary on these puzzles and my solutions on my blog.

+

Learn you a Haskell, Introduction to Haskell 98, and Hackage are good resources.

+

The Cabal user guide and How I Start: Haskell are good sources of using the tools.

+

Toolchain

+

Install Ghcup following the instructions, making sure to load the updated environment with

+
source /home/neil/.ghcup/env
+

and then set the default GHC to use with ghcup set ghc 9.0.1 .

+

Install Haskell Language Server for Sublime Text

+

Creating the repository and project

+

Create the repository as normal: create the project in Gitolite, clone it, and insert the .gitignore and README.md files.

+

There’s one package per day, with the code for each package in sub-directories of the root directory.

+

Create the basic cabal project.

+
cabal init
+

Modify the advent-of-code21.cabal file as needed, such as updating the Cabal version and writing the common stanzas.

+

Creating subsequent days

+

Each day lives in a separate directory, with code in the src directory.

+

Compile with

+
cabal build
+

or

+
cabal build advent01
+

Run with

+
cabal run advent01
+

If you want to pass in additional RTS parameters, do it like this:

+
cabal run advent01 -- +RTS -K0 -RTS
+

Run interactively with

+
cabal repl advent01
+

or

+
stack ghci advent01:exe:advent01
+

if the first form is ambiguous.

+

To profile, use

+
cabal run advent01 --enable-profiling -- +RTS -N -p -s -hT
+

Or, you can simplify the RTS options by adding them to a new stanza in the cabal file:

+
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

+
hp2ps -M advent01.hp
+

For Cabal, look at profiling with Cabal sandboxes

+

Packages

+

Packages I used a lot:

+ +

There are somewhat decent tutorials on Megaparsec and Attoparsec.

+

Packages I didn’t use much, but need to remember:

+ +

Readme

+

Build this readme file wth

+
pandoc -s README.md > README.html
+

(Using the Modest style.)

+ + diff --git a/README.md b/README.md index f7151b3..7b831f2 100644 --- 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. diff --git a/advent-of-code21.cabal b/advent-of-code21.cabal index 2ef838c..d200a4f 100644 --- a/advent-of-code21.cabal +++ b/advent-of-code21.cabal @@ -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 diff --git a/advent15/Main.hs b/advent15/Main.hs index 758bdc6..40a152a 100644 --- a/advent15/Main.hs +++ b/advent15/Main.hs @@ -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 -- 2.34.1