Significant GHCi speed regression with :module and `let` in GHC 8.2.1
I recently noticed that the performance of doctest
in GHC 8.2.1 (see the corresponding doctest issue) can be much, much worse than in previous versions of 8.0.2. So bad, in fact, that a project with 865 doctest
examples takes about three hours to complete in 8.2.1, whereas it would only take 8 seconds in 8.0.2.
To reproduce this issue in a fairly minimal way, you can use the following script to generate a file which simulates what doctest
is doing:
-- GenExample.hs
module Main where
import Control.Monad
import System.Environment
import System.Exit
import System.IO
main :: IO ()
main = do
args <- getArgs
case args of
n:_ -> genExamples (read n)
_ -> do hPutStrLn stderr "usage: runghc GenExamples.hs <num-examples>"
exitWith $ ExitFailure 1
genExamples :: Int -> IO ()
genExamples nExamples = do
putStrLn ":l Foo"
ireplicateA_ nExamples genExample
genExample :: Int -> IO ()
genExample i = putStr $ unlines
[ ":m *Foo"
, "example : \"expr" ++ show i ++ "\""
, "let foo = it"
, "\"marker\""
, "let it = foo"
]
ireplicateA_ :: Applicative m => Int -> (Int -> m a) -> m ()
ireplicateA_ cnt0 f =
loop cnt0 0
where
loop cnt n
| cnt <= 0 = pure ()
| otherwise = f n *> (loop (cnt - 1) $! (n + 1))
You'll also need this file:
-- Foo.hs
module Foo where
example :: Char
example = 'a'
First, use GenExample
to generate a GHCi script:
$ runghc GenExample.hs 500 > Example.script
Now you can run the script like so (using GHCi 8.0.2 as an example):
$ /opt/ghc/8.0.2/bin/ghci -ghci-script Example.script Foo.hs
With GHCi 8.0.2, this takes about three seconds. But with GHCi 8.2.1, this takes about 35 seconds!