Lesson 23 / 25

Performance, Profiling and Tooling

Build optimised programs, profile them and keep code consistent.

Making Haskell fast and maintainable

GHC is an optimising compiler: build releases with -O2 (Cabal uses -O1 by default), and use -threaded with +RTS -N for multicore programs. Haskell can be very fast, but performance needs attention to data representation and strictness: use Text, ByteString, Vector and strict maps instead of String and lists for large data; add strict fields and strict accumulators; avoid nub (quadratic) in favour of Set or Map; and beware of space leaks from laziness. Profile before optimising: build with profiling (cabal build --enable-profiling) and run with +RTS -p for a time and allocation report, +RTS -s for garbage collector statistics, and heap profiles (-hT or -hc) viewed with eventlog2html to find leaks. Criterion or tasty-bench benchmark functions reliably. For code quality: HLint suggests simplifications, Ormolu or Fourmolu format code, -Wall -Werror in CI catches warnings, and HLS in the editor shows types, errors and refactorings as you type. Haddock generates documentation from comments.

Profiling and quality commands

Optimised builds, RTS statistics, profiling and linting.

# optimised, multicore build
cabal build --ghc-options="-O2 -threaded -rtsopts"
cabal run shop -- +RTS -N -s          # -N: all cores, -s: GC and memory summary

# time and allocation profile
cabal run shop --enable-profiling -- +RTS -p    # writes shop.prof

# heap profile by closure type, rendered as HTML
cabal run shop --enable-profiling -- +RTS -hT -l
eventlog2html shop.eventlog

# benchmarks (tasty-bench or criterion suite in the .cabal file)
cabal bench

# code quality
hlint src app test                    # suggestions such as "use concatMap"
fourmolu --mode inplace $(git ls-files '*.hs')
cabal build --ghc-options="-Wall -Werror"
cabal haddock                         # generate API documentation

A doctor's check-up before surgery

Profiling is the check-up: it tells you which organ actually hurts. Optimising without it is surgery on a guess, often on code that was never the problem.

Quick check: Which RTS flag prints a garbage collection and memory usage summary?

  • +RTS -N
  • +RTS -s
  • +RTS -p
  • -O2
Answer

+RTS -s — +RTS -s prints allocation, GC and memory statistics at exit.