16
votes

I have a TH-heavy file which takes around 30 seconds to compile. What are some techniques I can use to help debug the performance of my Template Haskell?

2
I've actually discovered that, in said file, the TH runs instantly and all the time is spent by GHC doing instance resolution. Still interested in this question though.James Koppel
Maybe you could make a Quasi instance for some monad that runs in IO at run time, then you can use the standard profiling tools. The monad could have a list of reified Info's and Locations (maybe generated by TH?), so that you can still use reify.bennofs

2 Answers

2
votes

If I understand compile flow of TH correctly, the ordinary haskell functions are being executed while splicing at compile time. But you can run then at the runtime on your own, of course.

For example you have something like $(foo x y ...) in your TH-heavy file. Create another file and call 'foo x y' there but don't splice the result. Then you'll be able to profile 'foo' as usual. If the bottleneck is at the AST generation stage you'll locate it. Don't forget to consider lazyness.

0
votes

As of GHC 8, this can be done with -fexternal-interpreter.

Compile the library defining the TH function with profiling enabled, then compile the code* which uses the TH function in a splice with GHC options -fexternal-interpreter -opti+RTS -opti-p. This should produce a file called ghc-iserv-prof.prof.

This approach has the advantage that you can use the full functionality of the Q monad.

* A benchmark suite in the same cabal project as the TH library (but in a different hs-source-dir) also works. It might even work with a TH function defined and used in the same library, but I think you'll be profiling interpreted code then.