Haskell Profiling: Understanding Program Behavior & Tools, Study notes of Computer Science

A portion of a university course cs 410/510 on advanced programming, focusing on profiling in haskell. It covers the importance of writing qualitatively good code, understanding program behavior, and using profiling tools to identify performance hot-spots. The document also includes examples of parsing and execution statistics in hugs.

Typology: Study notes

Pre 2010

Uploaded on 08/16/2009

koofers-user-lpt
koofers-user-lpt 🇺🇸

5

(1)

10 documents

1 / 42

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
1
CS 410/510: Advanced
Programming
Profiling in Haskell
Mark P Jones
Portland State University
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a

Partial preview of the text

Download Haskell Profiling: Understanding Program Behavior & Tools and more Study notes Computer Science in PDF only on Docsity!

CS 410/510: Advanced

Programming

Profiling in Haskell

Mark P Jones

Portland State University

What makes a good program?

! " Qualitative factors:

!" Correctness

!" Maintainability, readability,

understandability, portability, flexibility, …

!" Use of appropriate abstractions and idioms

! " Quantitative factors:

!" Performance, Predictability, …

!" Time, Memory, Disk, Bandwidth, …

Profiling Tools:

! " Two broad approaches:

!" Instrumentation

!" Sampling

! " Standard Advice:

!" Focus on writing qualitatively good code first

!" Once that’s working, use profiling tools to

identify performance hot-spots and obtain

quantitatively good code

Form Follows Function:

expr, term, atom :: Parser Int expr = term "+" expr -- return (l+r) | term "-" expr -- return (l-r) | term term = atom "" term -- return (lr) | atom "/" term -- return (ldivr) | atom atom = "-" atom -- return (negate x) | "(" expr ")" -- return n | number

Parsing Examples:

Parsing> parse expr "1+2" [3] Parsing> parse expr "(1+2) * 3" [] Parsing> parse expr "(1+2)3" [9] Parsing> parse expr "((1+2)3)+1" [10] Parsing> parse expr "(((1+2)3)+1)8" [80] Parsing> parse expr "((((1+2)3)+1)8)" [80] Parsing>

Execution Statistics in Hugs:

! " Mechanisms:

!" Enable the collection of execution statistics

using :set +s

!" Turn on messages when garbage collection

occurs using :set +g

!" Change total heap size (when loading Hugs)

using hugs –hSize

! " Measures:

!" Cells : a chunk of memory

!" Reductions : a single rewrite step

Observing Garbage Collection:

Parsing> :set TOGGLES: groups begin with +/- to turn options on/off resp. s Print no. reductions/cells after eval … OTHER OPTIONS: (leading + or - makes no difference) hnum Set heap size (cannot be changed within Hugs) … Current settings: +squR - tgl.QwkIT -h1000000 - p"%s> " -r$$ -c … Parsing> length [1..200000] {{Gc:979946}}{{Gc:979945}}{{Gc:979947}}{{Gc:979946}}{{Gc: 979947}} 200000 (4200043 reductions, 5598039 cells, 5 garbage collections) {{Gc:979983}}Parsing>

Observing Garbage Collection:

$ hugs -h100000 +gs … Hugs> length [1..200000] {{Gc:86831}}{{Gc:86830}}{{Gc:86832}}{{Gc:86833}}{{Gc:86828}}… {{Gc:86828}}{{Gc:86829}}{{Gc:86828}}{{Gc:86828}} 200000 (4200054 reductions, 5598125 cells, 64 garbage collections) {{Gc:86866}}Hugs> :q $ hugs -h8M +gs … Hugs> length [1..200000] 200000 (4200054 reductions, 5598125 cells) {{Gc:7986866}}Hugs>:q

Observations:

! " Note that: 100000 – 86866 = 13134 = 26379 – 13245

! " So we can conclude that Hugs:

!" uses 13134 cells for internal state
!" needs at least 26379 cells to load

! " Possible profile of memory usage during startup:

26, 13134

Heap size, Residency, Allocation: ! " Heap size measures maximum capacity ! " Residency measures amount of memory that is actually in use at any given time ! " Haskell programs allocate constantly (and, simultaneously, create garbage) ! " Total allocation may exceed heap size

Parsing> :set +s Parsing> parse expr (addParens 1 "1") [1] (15060 reductions, 20628 cells) Parsing> parse expr (addParens 2 "1") [1] (137062 reductions, 187767 cells) Parsing> parse expr (addParens 3 "1") [1] (1234954 reductions, 1691736 cells, 1 garbage collection) Parsing> parse expr (addParens 4 "1") [1] (11115840 reductions, 15227127 cells, 15 garbage collections) Parsing> parse expr (addParens 5 "1") [1] (100043656 reductions, 137045268 cells, 139 garbage collections) Parsing> Rapid increases in reductions and cell counts

$ hugs -h26379 +sg Hugs> :l altParsing.lhs Parsing> :gc Garbage collection recovered 6462 cells Parsing> parse expr "1" [1] (1367 reductions, 1881 cells) {{Gc:6304}}Parsing> parse expr (addParens 1 "1") {{Gc:6218}}{{Gc:6213}}{{Gc:6217}}[1] (15073 reductions, 20665 cells, 3 garbage collections) {{Gc:6281}}Parsing> parse expr (addParens 5 "1") {{Gc:6044}}{{Gc:6072}}{{Gc:6066}}{{Gc:6076}}{{Gc:6072}}{{Gc: 6081}}{{Gc:6063}}{{Gc:6085}}{{Gc:6068}}{{Gc:6090}}{{Gc:6062}}... {{Gc:6113}}{{Gc:6078}}{{Gc^C:6048}}{Interrupted!} (16505831 reductions, 22610720 cells, 3713 garbage collections) {{Gc:6048}}Parsing> Memory is not the problem here:

Analysis (2):

19 parens reductions cells log reds log cells 1 15060 20628 4.177824972 4. 2 137062 187767 5.136917065 5. 3 1234954 1691736 6.091650781 6. 4 11115840 15227127 7.045942287 7. 5 100043656 137045268 8.000189554 8.

Why Exponential Behavior?

expr, term, atom :: Parser Int expr = do l <- term; string "+"; r <- expr; return (l+r) ||| do l <- term; string "-"; r <- expr; return (l-r) ||| term term = do l <- atom; string ""; r <- term; return (lr) ||| do l <- atom; string "/"; r <- term; return (ldivr) ||| atom atom = do string "-"; x <- atom; return (negate x) ||| do string "("; n <- expr; string ")"; return n ||| number Recall this grammar …