Hannes Siebenhandl pushed to branch wip/fendor/ghc-sample-profiler at Glasgow Haskell Compiler / GHC

Commits:

9 changed files:

Changes:

  • .gitmodules
    ... ... @@ -118,3 +118,6 @@
    118 118
     [submodule "libraries/file-io"]
    
    119 119
     	path = libraries/file-io
    
    120 120
     	url = https://gitlab.haskell.org/ghc/packages/file-io.git
    
    121
    +[submodule "ghc-debug"]
    
    122
    +	path = ghc-debug
    
    123
    +	url = git@gitlab.haskell.org:ghc/ghc-debug.git

  • ghc-debug
    1
    +Subproject commit 1b0f36fab86e9baa9734c88dcc1dbe17d10d8c93

  • ghc/GHC/EventLog/Sample.hs
    1
    +{-# LANGUAGE NamedFieldPuns    #-}
    
    2
    +{-# LANGUAGE OverloadedStrings #-}
    
    3
    +{-# LANGUAGE LambdaCase        #-}
    
    4
    +{-# LANGUAGE MagicHash #-}
    
    5
    +{-# LANGUAGE UnboxedTuples #-}
    
    6
    +{-# LANGUAGE CPP #-}
    
    7
    +
    
    8
    +module GHC.EventLog.Sample where
    
    9
    +import Prelude
    
    10
    +
    
    11
    +import Control.Concurrent
    
    12
    +import Control.Exception
    
    13
    +import Control.Monad
    
    14
    +import qualified Data.ByteString.Lazy as LBS
    
    15
    +import qualified Data.List as List
    
    16
    +import GHC.Conc
    
    17
    +import GHC.Conc.Sync
    
    18
    +
    
    19
    +import Control.Concurrent
    
    20
    +import Control.Monad (replicateM, when)
    
    21
    +import Data.Binary
    
    22
    +import Data.Binary.Get
    
    23
    +import Data.Binary.Put
    
    24
    +import qualified Data.ByteString as B
    
    25
    +import qualified Data.ByteString.Unsafe as BU
    
    26
    +import qualified System.IO.Unsafe as Unsafe
    
    27
    +import qualified Data.ByteString.Lazy as LBS
    
    28
    +import Data.Text (Text)
    
    29
    +import qualified Data.Text as Text
    
    30
    +import Data.Typeable (cast)
    
    31
    +import Data.Maybe
    
    32
    +import qualified Data.List.NonEmpty as NonEmpty
    
    33
    +import Unsafe.Coerce
    
    34
    +import GHC.Exts (Ptr(..), Int(..), traceBinaryEvent#)
    
    35
    +import GHC.IO (IO(..))
    
    36
    +import GHC.Stack.Annotation.Experimental
    
    37
    +
    
    38
    +import GHC.Stack.CloneStack (StackSnapshot(..), cloneThreadStack)
    
    39
    +import GHC.Internal.Conc.Sync
    
    40
    +
    
    41
    +import GHC.Internal.Conc.Sync
    
    42
    +import GHC.Internal.InfoProv.Types (InfoProv(..), lookupIpProvId)
    
    43
    +import GHC.Internal.Heap.Closures
    
    44
    +import qualified GHC.Internal.Stack.Decode as Decode
    
    45
    +import GHC.Internal.Stack.Types
    
    46
    +
    
    47
    +import Control.Monad (replicateM)
    
    48
    +import Data.Binary
    
    49
    +import Data.Binary.Put
    
    50
    +import Data.Binary.Get
    
    51
    +
    
    52
    +import GHC.Internal.RTS.Flags.Test
    
    53
    +
    
    54
    +import Debug.Trace
    
    55
    +import GHC.Profiling.Eras
    
    56
    +
    
    57
    +traceBinaryEventIO :: B.ByteString -> IO ()
    
    58
    +traceBinaryEventIO bytes = traceBinaryEventIO' bytes
    
    59
    +
    
    60
    +traceBinaryEventIO' :: B.ByteString -> IO ()
    
    61
    +traceBinaryEventIO' bytes =
    
    62
    +  BU.unsafeUseAsCStringLen bytes $ \(Ptr p, I# n) -> IO $ \s ->
    
    63
    +    case traceBinaryEvent# p n s of
    
    64
    +      s' -> (# s', () #)
    
    65
    +
    
    66
    +data SamplerThread = MkSamplerThread
    
    67
    +  { samplerThreadId :: ThreadId
    
    68
    +  } deriving (Show, Eq, Ord)
    
    69
    +
    
    70
    +withSampleProfiler :: Int -> IO a -> IO a
    
    71
    +withSampleProfiler delay act = do
    
    72
    +  enabled <- getUserEventTracingEnabled
    
    73
    +  if enabled
    
    74
    +    then bracket setupSamplers tearDownSamplers (const act)
    
    75
    +    else act
    
    76
    +  where
    
    77
    +    setupSamplers = do
    
    78
    +      samplerThreadConfigMVar <- newEmptyMVar
    
    79
    +      sid <- forkIO $ do
    
    80
    +        config <- takeMVar samplerThreadConfigMVar
    
    81
    +        sampleThreadId <- myThreadId
    
    82
    +        labelThread sampleThreadId "Sample Profiler Thread"
    
    83
    +        forever $ do
    
    84
    +          tids <- listThreads
    
    85
    +          userThreads <- filterM (isThreadOfInterest config) tids
    
    86
    +          forM_ userThreads $ \tid ->
    
    87
    +            sampleToEventlog tid
    
    88
    +          -- TODO: this is wrong, we don't sample every delay time as sampling takes time as well
    
    89
    +          threadDelay delay
    
    90
    +
    
    91
    +      let sampleThreadConf = MkSamplerThread
    
    92
    +            { samplerThreadId = sid
    
    93
    +            }
    
    94
    +      putMVar samplerThreadConfigMVar sampleThreadConf
    
    95
    +      pure sampleThreadConf
    
    96
    +
    
    97
    +    tearDownSamplers MkSamplerThread{samplerThreadId} =
    
    98
    +      killThread samplerThreadId
    
    99
    +
    
    100
    +    isThreadOfInterest :: SamplerThread -> ThreadId -> IO Bool
    
    101
    +    isThreadOfInterest config tid = do
    
    102
    +      lbl <- threadLabel tid
    
    103
    +      pure $ not $ or
    
    104
    +        [ isProfilerThread config tid lbl
    
    105
    +        , isBuiltinThread tid lbl
    
    106
    +        ]
    
    107
    +
    
    108
    +isProfilerThread :: SamplerThread -> ThreadId -> Maybe String -> Bool
    
    109
    +isProfilerThread MkSamplerThread {samplerThreadId} tid lbl = tid == samplerThreadId
    
    110
    +
    
    111
    +isBuiltinThread :: ThreadId -> Maybe String -> Bool
    
    112
    +isBuiltinThread _    Nothing    = False
    
    113
    +isBuiltinThread _tid (Just lbl) =
    
    114
    +  lbl `elem` ["TimerManager"] || "IOManager on cap" `List.isPrefixOf` lbl
    
    115
    +
    
    116
    +
    
    117
    +sampleToEventlog :: ThreadId -> IO ()
    
    118
    +sampleToEventlog tid = do
    
    119
    +  sampleThread tid >>= \ case
    
    120
    +    Nothing -> pure ()
    
    121
    +    Just threadSample -> do
    
    122
    +      msg <- serializeThreadSample threadSample
    
    123
    +      traceBinaryEventIO $ LBS.toStrict msg
    
    124
    +
    
    125
    +
    
    126
    +----
    
    127
    +
    
    128
    +
    
    129
    +newtype CapabilityId =
    
    130
    +  CapabilityId
    
    131
    +    { getCapabilityId :: Word64
    
    132
    +    }
    
    133
    +  deriving (Show, Eq, Ord)
    
    134
    +
    
    135
    +data ThreadSample =
    
    136
    +  ThreadSample
    
    137
    +    { threadSampleId :: ThreadId
    
    138
    +    , threadSampleCapability :: CapabilityId
    
    139
    +    , threadSampleStackSnapshot :: StackSnapshot
    
    140
    +    }
    
    141
    +
    
    142
    +sampleThread :: ThreadId -> IO (Maybe ThreadSample)
    
    143
    +sampleThread tid = do
    
    144
    +  (cap, blocked) <- threadCapability tid
    
    145
    +  if blocked
    
    146
    +    then pure Nothing
    
    147
    +    else do
    
    148
    +      stack <- cloneThreadStack tid
    
    149
    +      pure $ Just $ ThreadSample
    
    150
    +        { threadSampleId = tid
    
    151
    +        , threadSampleCapability = CapabilityId $ intToWord64 cap
    
    152
    +        , threadSampleStackSnapshot = stack
    
    153
    +        }
    
    154
    +
    
    155
    +serializeThreadSample :: ThreadSample -> IO LBS.ByteString
    
    156
    +serializeThreadSample sample = do
    
    157
    +  callStackMessage <- threadSampleToCallStackMessage sample
    
    158
    +  pure $ runPut $ put callStackMessage
    
    159
    +
    
    160
    +deserializeCallStackMessage :: LBS.ByteString -> Either String CallStackMessage
    
    161
    +deserializeCallStackMessage = Right . runGet get
    
    162
    +
    
    163
    +-- Message format:
    
    164
    +--
    
    165
    +-- MESSAGE
    
    166
    +--  := "CA" "11" <STACK>
    
    167
    +-- STACK
    
    168
    +--  := <capability: Word32> <threadId: Word32> <length: Word32> <ENTRY>+
    
    169
    +-- ENTRY
    
    170
    +--  := "01" <ipe: Word64>
    
    171
    +--   | "02" <string: STRING>
    
    172
    +--   | "03" <row: Word32> <col: Word32> <function: CStringLen> <filename: CStringLen>
    
    173
    +-- CStringLen
    
    174
    +--   := <length: Word8> <Char>+
    
    175
    +
    
    176
    +data CallStackMessage =
    
    177
    +  MkCallStackMessage
    
    178
    +    { callThreadId :: Word64
    
    179
    +    , callCapabilityId :: CapabilityId
    
    180
    +    , callStack :: [StackItem]
    
    181
    +    }
    
    182
    +  deriving (Eq, Ord, Show)
    
    183
    +
    
    184
    +data StackItem
    
    185
    +  = IpeId !Word64
    
    186
    +  | UserMessage !String
    
    187
    +  | SourceLocation !SourceLocation
    
    188
    +  deriving (Eq, Ord, Show)
    
    189
    +
    
    190
    +data SourceLocation =
    
    191
    +  MkSourceLocation
    
    192
    +    { line :: !Word32
    
    193
    +    , column :: !Word32
    
    194
    +    , functionName :: !Text
    
    195
    +    , fileName :: !Text
    
    196
    +    }
    
    197
    +  deriving (Eq, Ord, Show)
    
    198
    +
    
    199
    +instance Binary CallStackMessage where
    
    200
    +  put msg = do
    
    201
    +    putByteString "CA"
    
    202
    +    putByteString "11"
    
    203
    +    putWord32 $ word64ToWord32 $ getCapabilityId $ callCapabilityId msg
    
    204
    +    putWord32 $ word64ToWord32 $ callThreadId msg
    
    205
    +    putWord8 $ intToWord8 $ min cutOffLength $ length $ callStack msg -- TODO: limit number of stack entries to 2^32
    
    206
    +    mapM_ put $ take cutOffLength $ callStack msg
    
    207
    +
    
    208
    +  get = do
    
    209
    +    _ <- getByteString 2 -- CA
    
    210
    +    _ <- getByteString 2 -- 11
    
    211
    +    capId <- getWord32
    
    212
    +    tid <- getWord32
    
    213
    +    len <- getWord8
    
    214
    +    items <- replicateM (word8ToInt len) get
    
    215
    +    pure MkCallStackMessage
    
    216
    +      { callThreadId = word32ToWord64 tid
    
    217
    +      , callCapabilityId = CapabilityId $ word32ToWord64 capId
    
    218
    +      , callStack = items
    
    219
    +      }
    
    220
    +
    
    221
    +instance Binary SourceLocation where
    
    222
    +  put loc = do
    
    223
    +    putWord32 $ line loc
    
    224
    +    putWord32 $ column loc
    
    225
    +    putStringLen $ Text.unpack $ functionName loc
    
    226
    +    putStringLen $ Text.unpack $ fileName loc
    
    227
    +
    
    228
    +  get = do
    
    229
    +    MkSourceLocation
    
    230
    +      <$> getWord32
    
    231
    +      <*> getWord32
    
    232
    +      <*> (Text.pack <$> getStringLen)
    
    233
    +      <*> (Text.pack <$> getStringLen)
    
    234
    +
    
    235
    +instance Binary StackItem where
    
    236
    +  put = \ case
    
    237
    +    IpeId ipeId -> do
    
    238
    +      putWord8 1
    
    239
    +      putWord64 ipeId
    
    240
    +    UserMessage msg -> do
    
    241
    +      putWord8 2
    
    242
    +      putStringLen msg
    
    243
    +    SourceLocation loc -> do
    
    244
    +      putWord8 3
    
    245
    +      put loc
    
    246
    +
    
    247
    +  get = do
    
    248
    +    getWord8 >>= \ case
    
    249
    +      1 -> IpeId <$> getWord64
    
    250
    +      2 -> UserMessage <$> getStringLen
    
    251
    +      3 -> SourceLocation <$> get
    
    252
    +      n -> fail $ "StackItem: Unexpected tag byte encounter: " <> show n
    
    253
    +
    
    254
    +decodeStackWithIpProvId :: StackSnapshot -> IO [(StackFrame, Maybe Word64)]
    
    255
    +decodeStackWithIpProvId snapshot = do
    
    256
    +  concat . snd <$> Decode.decodeStackWithFrameUnpack unpackStackFrameWithIpProvId snapshot
    
    257
    +
    
    258
    +unpackStackFrameWithIpProvId :: Decode.StackFrameLocation -> IO (StackFrame, Maybe Word64)
    
    259
    +unpackStackFrameWithIpProvId stackFrameLoc = do
    
    260
    +  Decode.unpackStackFrameTo stackFrameLoc
    
    261
    +    (\ info infoKey nextChunk@(StackSnapshot stack#) -> do
    
    262
    +      framesWithIpe <- decodeStackWithIpProvId nextChunk
    
    263
    +      mIpeId <- lookupIpProvId infoKey
    
    264
    +      pure
    
    265
    +        ( UnderflowFrame
    
    266
    +            { info_tbl = info,
    
    267
    +              nextChunk =
    
    268
    +                GenStgStackClosure
    
    269
    +                  { ssc_info = info,
    
    270
    +                    ssc_stack_size = Decode.getStackFields stack#,
    
    271
    +                    ssc_stack = map fst framesWithIpe
    
    272
    +                  }
    
    273
    +            }
    
    274
    +        , mIpeId
    
    275
    +        )
    
    276
    +
    
    277
    +    )
    
    278
    +    (\ frame infoKey -> do
    
    279
    +      mIpeId <- lookupIpProvId infoKey
    
    280
    +      pure (frame, mIpeId)
    
    281
    +    )
    
    282
    +
    
    283
    +threadSampleToCallStackMessage :: ThreadSample -> IO CallStackMessage
    
    284
    +threadSampleToCallStackMessage sample = do
    
    285
    +  frames <- decodeStackWithIpProvId $ threadSampleStackSnapshot sample
    
    286
    +  let stackMessages = fmap List.head . List.group $ mapMaybe (uncurry stackFrameToStackItem) frames
    
    287
    +  pure MkCallStackMessage
    
    288
    +    { callThreadId = fromThreadId $ threadSampleId sample
    
    289
    +    , callCapabilityId = threadSampleCapability sample
    
    290
    +    , callStack = stackMessages
    
    291
    +    }
    
    292
    +
    
    293
    +stackFrameToStackItem :: StackFrame -> Maybe Word64 -> Maybe StackItem
    
    294
    +stackFrameToStackItem frame mIpe =
    
    295
    +  case frame of
    
    296
    +    AnnFrame { annotation = Box someStackAnno } ->
    
    297
    +      case unsafeCoerce someStackAnno of
    
    298
    +        SomeStackAnnotation ann ->
    
    299
    +          case cast ann of
    
    300
    +            Just (CallStackAnnotation cs) ->
    
    301
    +              case getCallStack cs of
    
    302
    +                [] -> Nothing
    
    303
    +                ((name, sourceLoc):_) ->
    
    304
    +                  Just $ SourceLocation $ MkSourceLocation
    
    305
    +                    { line = intToWord32 $ srcLocStartLine sourceLoc
    
    306
    +                    , column = intToWord32 $ srcLocStartCol sourceLoc
    
    307
    +                    , functionName = Text.pack $ name
    
    308
    +                    , fileName = Text.pack $ srcLocFile sourceLoc
    
    309
    +                    }
    
    310
    +
    
    311
    +            Nothing -> case cast ann of
    
    312
    +              Just (StringAnnotation msg) ->
    
    313
    +                Just $ UserMessage msg
    
    314
    +              Nothing ->
    
    315
    +                Nothing
    
    316
    +    _ ->
    
    317
    +      IpeId <$> mIpe
    
    318
    +
    
    319
    +--------
    
    320
    +
    
    321
    +cutOffLength :: Int
    
    322
    +cutOffLength = 255
    
    323
    +
    
    324
    +putStringLenWithTag :: Word8 -> String -> Put
    
    325
    +putStringLenWithTag tag msg =
    
    326
    +  putWord8 tag <> putStringLen msg
    
    327
    +
    
    328
    +putStringLen :: String -> Put
    
    329
    +putStringLen msg =
    
    330
    +  putWord8 len <> putStringUtf8 msg
    
    331
    +  where
    
    332
    +    shortName = take cutOffLength msg
    
    333
    +    -- this is safe as we made sure that cutOffLength fits in a Word8
    
    334
    +    len = intToWord8 $ length shortName
    
    335
    +
    
    336
    +getStringLen :: Get String
    
    337
    +getStringLen = do
    
    338
    +  len <- getWord8
    
    339
    +  replicateM (word8ToInt len) get
    
    340
    +
    
    341
    +putWord64 :: Word64 -> Put
    
    342
    +putWord64 = putWord64be
    
    343
    +
    
    344
    +putWord32 :: Word32 -> Put
    
    345
    +putWord32 = putWord32be
    
    346
    +
    
    347
    +getWord64 :: Get Word64
    
    348
    +getWord64 = getWord64be
    
    349
    +
    
    350
    +getWord32 :: Get Word32
    
    351
    +getWord32 = getWord32be
    
    352
    +
    
    353
    +word64ToWord32 :: Word64 -> Word32
    
    354
    +word64ToWord32 = fromIntegral
    
    355
    +
    
    356
    +word32ToWord64 :: Word32 -> Word64
    
    357
    +word32ToWord64 = fromIntegral
    
    358
    +
    
    359
    +word32ToInt :: Word32 -> Int
    
    360
    +word32ToInt = fromIntegral
    
    361
    +
    
    362
    +word64ToInt :: Word64 -> Int
    
    363
    +word64ToInt = fromIntegral
    
    364
    +
    
    365
    +intToWord64 :: Int -> Word64
    
    366
    +intToWord64 = fromIntegral
    
    367
    +
    
    368
    +intToWord32 :: Int -> Word32
    
    369
    +intToWord32 = fromIntegral
    
    370
    +
    
    371
    +intToWord8 :: Int -> Word8
    
    372
    +intToWord8 = fromIntegral
    
    373
    +
    
    374
    +word8ToInt :: Word8 -> Int
    
    375
    +word8ToInt = fromIntegral
    
    376
    +

  • ghc/Main.hs
    ... ... @@ -33,6 +33,7 @@ import GHC.Driver.Backpack ( doBackpack )
    33 33
     import GHC.Driver.Plugins
    
    34 34
     import GHC.Driver.Config.Logger (initLogFlags)
    
    35 35
     import GHC.Driver.Config.Diagnostic
    
    36
    +import GHC.Driver.Monad
    
    36 37
     
    
    37 38
     import GHC.Platform
    
    38 39
     import GHC.Platform.Host
    
    ... ... @@ -92,6 +93,14 @@ import Data.List ( isPrefixOf, partition, intercalate )
    92 93
     import Prelude
    
    93 94
     import qualified Data.List.NonEmpty as NE
    
    94 95
     
    
    96
    +#if defined(GHC_DEBUG)
    
    97
    +import GHC.Debug.Stub
    
    98
    +#endif
    
    99
    +
    
    100
    +#if defined(SAMPLE_TRACER)
    
    101
    +import GHC.EventLog.Sample
    
    102
    +#endif
    
    103
    +
    
    95 104
     -----------------------------------------------------------------------------
    
    96 105
     -- ToDo:
    
    97 106
     
    
    ... ... @@ -104,8 +113,24 @@ import qualified Data.List.NonEmpty as NE
    104 113
     -----------------------------------------------------------------------------
    
    105 114
     -- GHC's command-line interface
    
    106 115
     
    
    116
    +withGhcSampleProfiler :: IO () -> IO ()
    
    117
    +#if defined(SAMPLE_TRACER)
    
    118
    +withGhcSampleProfiler =
    
    119
    +  withSampleProfiler 10000
    
    120
    +#else
    
    121
    +withGhcSampleProfiler =
    
    122
    +  id
    
    123
    +#endif
    
    124
    +
    
    125
    +debugWrapper :: IO a -> IO a
    
    126
    +#if defined(GHC_DEBUG)
    
    127
    +debugWrapper = withGhcDebug
    
    128
    +#else
    
    129
    +debugWrapper = id
    
    130
    +#endif
    
    131
    +
    
    107 132
     main :: IO ()
    
    108
    -main = do
    
    133
    +main = withGhcSampleProfiler $ do
    
    109 134
        hSetBuffering stdout LineBuffering
    
    110 135
        hSetBuffering stderr LineBuffering
    
    111 136
     
    
    ... ... @@ -152,8 +177,10 @@ main = do
    152 177
                                 ShowGhcUsage           -> showGhcUsage  dflags
    
    153 178
                                 ShowGhciUsage          -> showGhciUsage dflags
    
    154 179
                                 PrintWithDynFlags f    -> putStrLn (f dflags)
    
    155
    -                Right postLoadMode ->
    
    156
    -                    main' postLoadMode units dflags argv3 flagWarnings
    
    180
    +                Right postLoadMode -> do
    
    181
    +                    reifyGhc $ \session -> debugWrapper $
    
    182
    +                      reflectGhc (main' postLoadMode units dflags argv3 flagWarnings) session
    
    183
    +
    
    157 184
     
    
    158 185
     main' :: PostLoadMode -> [String] -> DynFlags -> [Located String] -> [Warn]
    
    159 186
           -> Ghc ()
    

  • ghc/ghc-bin.cabal.in
    ... ... @@ -22,11 +22,21 @@ Flag internal-interpreter
    22 22
         Default: False
    
    23 23
         Manual: True
    
    24 24
     
    
    25
    +Flag ghc-debug
    
    26
    +    Description: Build with support for ghc-debug.
    
    27
    +    Default: False
    
    28
    +    Manual: True
    
    29
    +
    
    25 30
     Flag threaded
    
    26 31
         Description: Link the ghc executable against the threaded RTS
    
    27 32
         Default: True
    
    28 33
         Manual: True
    
    29 34
     
    
    35
    +Flag sampleTracer
    
    36
    +    Description: Link the ghc executable against the threaded RTS
    
    37
    +    Default: False
    
    38
    +    Manual: True
    
    39
    +
    
    30 40
     Executable ghc
    
    31 41
         Default-Language: GHC2021
    
    32 42
     
    
    ... ... @@ -42,9 +52,20 @@ Executable ghc
    42 52
                        filepath   >= 1.5 && < 1.6,
    
    43 53
                        containers >= 0.5 && < 0.9,
    
    44 54
                        transformers >= 0.5 && < 0.7,
    
    55
    +                   ghc-internal, ghc-experimental, binary,
    
    56
    +                   text,
    
    45 57
                        ghc-boot      == @ProjectVersionMunged@,
    
    46 58
                        ghc           == @ProjectVersionMunged@
    
    47 59
     
    
    60
    +    if flag(sampleTracer)
    
    61
    +        CPP-OPTIONS: -DSAMPLE_TRACER
    
    62
    +        other-modules:
    
    63
    +            GHC.EventLog.Sample
    
    64
    +
    
    65
    +    if flag(ghc-debug)
    
    66
    +        build-depends: ghc-debug-stub
    
    67
    +        CPP-OPTIONS: -DGHC_DEBUG
    
    68
    +
    
    48 69
         if os(windows)
    
    49 70
             Build-Depends: Win32  >= 2.3 && < 2.15
    
    50 71
         else
    

  • hadrian/src/Packages.hs
    ... ... @@ -12,7 +12,7 @@ module Packages (
    12 12
         runGhc, semaphoreCompat, stm, templateHaskell, terminfo, text, time, timeout,
    
    13 13
         transformers, unlit, unix, win32, xhtml,
    
    14 14
         lintersCommon, lintNotes, lintCodes, lintCommitMsg, lintSubmoduleRefs, lintWhitespace,
    
    15
    -    ghcPackages, isGhcPackage,
    
    15
    +    ghcPackages, isGhcPackage, ghc_debug_convention, ghc_debug_stub,
    
    16 16
     
    
    17 17
         -- * Package information
    
    18 18
         crossPrefix, programName, nonHsMainPackage, programPath, timeoutPath,
    
    ... ... @@ -43,7 +43,9 @@ ghcPackages =
    43 43
         , terminfo, text, time, transformers, unlit, unix, win32, xhtml, fileio
    
    44 44
         , timeout
    
    45 45
         , lintersCommon
    
    46
    -    , lintNotes, lintCodes, lintCommitMsg, lintSubmoduleRefs, lintWhitespace ]
    
    46
    +    , lintNotes, lintCodes, lintCommitMsg, lintSubmoduleRefs, lintWhitespace
    
    47
    +    , ghc_debug_convention
    
    48
    +    , ghc_debug_stub ]
    
    47 49
     
    
    48 50
     -- TODO: Optimise by switching to sets of packages.
    
    49 51
     isGhcPackage :: Package -> Bool
    
    ... ... @@ -133,6 +135,8 @@ unlit = util "unlit"
    133 135
     unix                = lib  "unix"
    
    134 136
     win32               = lib  "Win32"
    
    135 137
     xhtml               = lib  "xhtml"
    
    138
    +ghc_debug_convention = lib "ghc-debug-convention" `setPath` "ghc-debug/convention"
    
    139
    +ghc_debug_stub       = lib "ghc-debug-stub" `setPath` "ghc-debug/stub"
    
    136 140
     
    
    137 141
     lintersCommon       = lib     "linters-common"      `setPath` "linters/linters-common"
    
    138 142
     lintNotes           = linter  "lint-notes"
    

  • hadrian/src/Settings/Default.hs
    ... ... @@ -174,6 +174,8 @@ stage1Packages = do
    174 174
             , unlit
    
    175 175
             , xhtml
    
    176 176
             , if winTarget then win32 else unix
    
    177
    +        , ghc_debug_convention
    
    178
    +        , ghc_debug_stub
    
    177 179
             ]
    
    178 180
           , when (not cross)
    
    179 181
             [ hpcBin
    

  • hadrian/src/Settings/Packages.hs
    ... ... @@ -116,6 +116,7 @@ packageArgs = do
    116 116
     
    
    117 117
               , builder (Cabal Flags) ? mconcat
    
    118 118
                 [ (expr (ghcWithInterpreter stage)) `cabalFlag` "internal-interpreter"
    
    119
    +            , notStage0 `cabalFlag` "ghc-debug"
    
    119 120
                 , ifM stage0
    
    120 121
                       -- We build a threaded stage 1 if the bootstrapping compiler
    
    121 122
                       -- supports it.
    
    ... ... @@ -124,6 +125,7 @@ packageArgs = do
    124 125
                       -- We build a threaded stage N, N>1 if the configuration calls
    
    125 126
                       -- for it.
    
    126 127
                       (compilerStageOption ghcThreaded `cabalFlag` "threaded")
    
    128
    +            , notStage0 `cabalFlag` "sampleTracer"
    
    127 129
                 ]
    
    128 130
               ]
    
    129 131
     
    

  • instructions.md
    1
    +# Building GHC
    
    2
    +
    
    3
    +* Add the following to _build/hadrian.settings
    
    4
    +
    
    5
    +```
    
    6
    +stage1.*.ghc.hs.opts += -finfo-table-map -fdistinct-constructor-tables
    
    7
    +```
    
    8
    +
    
    9
    +* Build GHC as normal
    
    10
    +
    
    11
    +```
    
    12
    +./hadrian/build -j8
    
    13
    +```
    
    14
    +
    
    15
    +* The result is a ghc-debug enabled compiler
    
    16
    +
    
    17
    +# Building a debugger
    
    18
    +
    
    19
    +* Use the compiler you just built to build ghc-debug
    
    20
    +
    
    21
    +```
    
    22
    +cd ghc-debug
    
    23
    +cabal update
    
    24
    +cabal new-build debugger -w ../_build/stage1/bin/ghc
    
    25
    +```
    
    26
    +
    
    27
    +# Running the debugger
    
    28
    +
    
    29
    +Modify `test/Test.hs` to implement the debugging thing you want to do. Perhaps
    
    30
    +start with `p30`, which is a program to generate a profile.
    
    31
    +
    
    32
    +
    
    33
    +* Start the process you want to debug
    
    34
    +```
    
    35
    +GHC_DEBUG_SOCKET=/tmp/ghc-debug build-cabal
    
    36
    +```
    
    37
    +
    
    38
    +* Start the debugger
    
    39
    +```
    
    40
    +cabal new-run debugger -w ...
    
    41
    +```
    
    42
    +
    
    43
    +* Open a ticket about the memory issue you find.
    
    44
    +
    
    45
    +