Skip to content

GHC with -DDEBUG is really slow

I always build GHC with -DDEBUG because that catches many bugs at source. But I've noticed that my built compilers are pretty slow, especially if I build stage1 with -O0 which I often do because I can iterate faster.

I think it's currently extra slow (e.g it can take 20 minutes for the stage1 compiler, built with -O0, to compile a single module). I bet this is my fault -- perhaps I have recently added an 'assert' somewhere that is egregiously expensive. (I'm sure that most of the asserts are fine.) (I should think that the -O0 bit is just a constant factor worsening but I suppose it could interact badly and make some assert much more expensive.)

I'd love help with figuring this out.

To help with reproducibilty, here's the hadrian/UserSettings.hs file that I use, based on hadrian/src/UserSettings.hs. After that it's hadrian/build

-- Ensure we don't expose any unfoldings to guarantee quick rebuilds
{-# OPTIONS_GHC -O0 #-}

-- If you want to customise your build you should copy this file from
-- hadrian/src/UserSettings.hs to hadrian/UserSettings.hs and edit your copy.
-- If you don't copy the file your changes will be tracked by git and you can
-- accidentally commit them.
--
-- See doc/user-settings.md for instructions, and src/Flavour.hs for auxiliary
-- functions for manipulating flavours.
-- Please update doc/user-settings.md when committing changes to this file.
module UserSettings (
    userFlavours, userPackages, userDefaultFlavour,
    verboseCommand, buildProgressColour, successColour, finalStage
    ) where

import qualified Data.Set as Set
import Oracles.Flag( platformSupportsSharedLibs )
import Flavour.Type
import Expression
import {-# SOURCE #-} Settings.Default

-- See doc/user-settings.md for instructions.
-- Please update doc/user-settings.md when committing changes to this file.

-- | Name of the default flavour, i.e the one used when no --flavour=<name>
--   argument is passed to Hadrian.
userDefaultFlavour :: String
userDefaultFlavour = "user"

-- | User-defined build flavours. See 'userFlavour' as an example.
userFlavours :: [Flavour]
userFlavours = [userFlavour] -- Add more build flavours if need be.

-- | This is an example user-defined build flavour. Feel free to modify it and
-- use by passing @--flavour=user@ from the command line.
userFlavour :: Flavour
-- Modify other settings here.
userFlavour = defaultFlavour
    { name = "user"

    -- No profiled libraries
       -- This cargo-culted invocation is a bit obscure
    , libraryWays = Set.fromList <$>
                    mconcat
                    [ pure [vanilla]
-- Switch off profiling by default
--                    , notStage0 ? pure [profiling]
                    , notStage0 ? platformSupportsSharedLibs ? pure [dynamic] ]

    -- Assertions on, always
       -- Actually I'm not sure what this does
    , ghcDebugAssertions = const True     -- <---- I thought this switched on -DDEBUG but it doesn't (at least not always)

    -- Everything built with the stage-1 compiler has -ticky, and -dcore-lint
    -- Notably, the libraries
    , args = mydefaultArgs
             <> (builder Ghc ? (arg "-dcore-lint" <> arg "-DDEBUG"))    -- <------------- Always -DDEBUG
             <> (builder Ghc ? stage1 ? arg "-ticky")                   -- <--- and ticky (but that's a small issue)
    }

-- | All default command line arguments.
mydefaultArgs :: Args
mydefaultArgs = mconcat
    [ defaultBuilderArgs
    , sourceArgs mydefaultSourceArgs
    , defaultPackageArgs ]

-- | Default source arguments, e.g. optimisation settings.
mydefaultSourceArgs :: SourceArgs
mydefaultSourceArgs = SourceArgs
    { hsDefault  = mconcat [ stage0    ? arg "-O"
                           , notStage0 ? arg "-O2"
                           , arg "-H32m" ]
    , hsLibrary  = notStage0 ? arg "-haddock"
    , hsCompiler = stage0 ? arg "-O0"           -- <----------------- Compile stage1 compile with -O0
--    , hsCompiler = mempty
    , hsGhc      = mempty }



-- | Add user-defined packages. Note, this only lets Hadrian know about the
-- existence of a new package; to actually build it you need to create a new
-- build flavour, modifying the list of packages that are built by default.
userPackages :: [Package]
userPackages = []

-- | Set to 'True' to print full command lines during the build process. Note:
-- this is a 'Predicate', hence you can enable verbose output only for certain
-- targets, e.g.: @verboseCommand = package ghcPrim@.
verboseCommand :: Predicate
verboseCommand = do
    verbosity <- expr getVerbosity
    return $ verbosity >= Verbose

-- | Set colour for build progress messages (e.g. executing a build command).
buildProgressColour :: BuildProgressColour
buildProgressColour = mkBuildProgressColour (Dull Magenta)

-- | Set colour for success messages (e.g. a package is built successfully).
successColour :: SuccessColour
successColour = mkSuccessColour (Dull Green)

-- | Stop after building the StageN compiler.
-- For example, setting the 'finalStage' to 'Stage1' will just build the
-- 'Stage1' compiler. Setting it to 'Stage3' will build the 'Stage3'
-- compiler. Setting it to 'Stage0' will mean nothing gets built at all.
finalStage :: Stage
finalStage = Stage2
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information