Skip to content

Haddock spends a lot of time building code if TemplateHaskell is enabled

Summary

I'm looking at Haddock's performance, and noticed that the time for building Haddock in persistent-test is absolutely dominated by doing code generation.

I've attached a profiteur HTML in a gist in this upstream Haddock issue: https://github.com/haskell/haddock/issues/1547 Happy to add a .prof if that's easier.

This happens when TemplateHaskell or QuasiQuotes is enabled, even if TemplateHaskell is not actually used. If I disable the extensions, then much less code is generated.

Here's the log output with TemplateHaskell on:

[41 of 41] Compiling UpsertTest       ( src/UpsertTest.hs, /tmp/ghc927461_0/ghc_86.o )
*** Parser [UpsertTest]:
!!! Parser [UpsertTest]: finished in 1.48 milliseconds, allocated 4.784 megabytes
*** Renamer/typechecker [UpsertTest]:
*** processModule:
*** createInterface:
!!! createInterface: finished in 0.40 milliseconds, allocated 2.046 megabytes
!!! processModule: finished in 0.66 milliseconds, allocated 2.371 megabytes
!!! Renamer/typechecker [UpsertTest]: finished in 17.32 milliseconds, allocated 32.451 megabytes
*** Desugar [UpsertTest]:
Result size of Desugar (before optimization)
  = {terms: 4,246, types: 4,980, coercions: 882, joins: 0/672}
Result size of Desugar (after optimization)
  = {terms: 2,890, types: 3,218, coercions: 701, joins: 0/160}
!!! Desugar [UpsertTest]: finished in 5.89 milliseconds, allocated 11.031 megabytes
*** Simplifier [UpsertTest]:
Result size of Simplifier iteration=1
  = {terms: 3,069, types: 3,432, coercions: 1,027, joins: 0/166}
Result size of Simplifier
  = {terms: 3,048, types: 3,412, coercions: 1,023, joins: 0/165}
!!! Simplifier [UpsertTest]: finished in 9.64 milliseconds, allocated 17.176 megabytes
*** CoreTidy [UpsertTest]:
!!! CoreTidy [UpsertTest]: finished in 0.75 milliseconds, allocated 2.167 megabytes
Result size of Tidy Core
  = {terms: 3,048, types: 3,412, coercions: 1,023, joins: 0/165}
*** CorePrep [UpsertTest]:
Result size of CorePrep
  = {terms: 5,098, types: 5,952, coercions: 1,023, joins: 0/1,144}
!!! CorePrep [UpsertTest]: finished in 4.04 milliseconds, allocated 6.778 megabytes
*** CoreToStg [UpsertTest]:
*** Stg2Stg:
!!! CoreToStg [UpsertTest]: finished in 2.15 milliseconds, allocated 5.676 megabytes
*** CodeGen [UpsertTest]:
!!! CodeGen [UpsertTest]: finished in 228.48 milliseconds, allocated 258.712 megabytes
*** WriteIface [/tmp/ghc927461_0/ghc_85.hi]:
!!! WriteIface [/tmp/ghc927461_0/ghc_85.hi]: finished in 0.22 milliseconds, allocated 1.194 megabytes

With TemplateHaskell disabled,

[41 of 41] Compiling UpsertTest       ( src/UpsertTest.hs, nothing )
*** Parser [UpsertTest]:
!!! Parser [UpsertTest]: finished in 1.95 milliseconds, allocated 4.994 megabytes
*** Renamer/typechecker [UpsertTest]:
*** processModule:
*** createInterface:
!!! createInterface: finished in 1.39 milliseconds, allocated 2.073 megabytes
!!! processModule: finished in 1.66 milliseconds, allocated 2.398 megabytes
!!! Renamer/typechecker [UpsertTest]: finished in 17.57 milliseconds, allocated 33.295 megabytes
*** Desugar [UpsertTest]:
Result size of Desugar (before optimization)
  = {terms: 4,246, types: 4,980, coercions: 882, joins: 0/672}
Result size of Desugar (after optimization)
  = {terms: 2,890, types: 3,218, coercions: 701, joins: 0/160}
!!! Desugar [UpsertTest]: finished in 5.93 milliseconds, allocated 10.748 megabytes
*** CoreTidy [UpsertTest]:
!!! CoreTidy [UpsertTest]: finished in 0.13 milliseconds, allocated 0.033 megabytes

One easy win here is only doing code gen if the module actually uses TemplateHaskell - I feel like GHC has a way of knowing this ahead-of-time, since the old recompilation-avoidance logic would skip recompiling a module with TemplateHaskell enabled unless the module actually used TemplateHaskell.

Steps to reproduce

Either build haddock with profiling and use that to build docs, or, for a much easier time, do:

git clone git@github.com:yesodweb/persistent
cd persistent
cabal haddock --haddock-options="--optgc=\"-v2\""

and look at the output for CodeGen printing.

Expected behavior

Ideally, not do code generation unless the module really requires it, and not just assume that it does.

Environment

  • GHC version used: 9.4.3, 9.4.2

Optional:

  • Operating System:
  • System Architecture:
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information