Hannes Siebenhandl pushed to branch wip/fendor/hpc-bc-support at Glasgow Haskell Compiler / GHC

Commits:

29 changed files:

Changes:

  • compiler/GHC/ByteCode/Asm.hs
    ... ... @@ -72,6 +72,7 @@ import GHC.Float (castFloatToWord32, castDoubleToWord64)
    72 72
     
    
    73 73
     import qualified Data.List as List ( any )
    
    74 74
     import GHC.Exts
    
    75
    +import qualified GHC.Data.Strict as Strict
    
    75 76
     
    
    76 77
     
    
    77 78
     -- -----------------------------------------------------------------------------
    
    ... ... @@ -111,8 +112,9 @@ assembleBCOs
    111 112
       -> [(Name, ByteString)]
    
    112 113
       -> Maybe InternalModBreaks
    
    113 114
       -> [SptEntry]
    
    115
    +  -> Strict.Maybe ByteCodeHpcInfo
    
    114 116
       -> IO CompiledByteCode
    
    115
    -assembleBCOs profile proto_bcos tycons top_strs modbreaks spt_entries = do
    
    117
    +assembleBCOs profile proto_bcos tycons top_strs modbreaks spt_entries use_hpc = do
    
    116 118
       -- TODO: the profile should be bundled with the interpreter: the rts ways are
    
    117 119
       -- fixed for an interpreter
    
    118 120
       let itbls = mkITbls profile tycons
    
    ... ... @@ -123,6 +125,7 @@ assembleBCOs profile proto_bcos tycons top_strs modbreaks spt_entries = do
    123 125
         , bc_strs = top_strs
    
    124 126
         , bc_breaks = modbreaks
    
    125 127
         , bc_spt_entries = spt_entries
    
    128
    +    , bc_hpc_info = use_hpc
    
    126 129
         }
    
    127 130
     
    
    128 131
     -- Note [Allocating string literals]
    
    ... ... @@ -856,6 +859,12 @@ assembleI platform i = case i of
    856 859
         emit_ bci_BRK_FUN [ Op p1, Op info_addr, Op info_unitid_addr
    
    857 860
                           , SmallOp ix_hi, SmallOp ix_lo, Op np ]
    
    858 861
     
    
    862
    +  HPC_TICK lbl ix -> do
    
    863
    +    p <- lit1 (BCONPtrLbl lbl)
    
    864
    +    let ix_hi = fromIntegral (ix `shiftR` 16)
    
    865
    +        ix_lo = fromIntegral (ix .&. 0xffff)
    
    866
    +    emit_ bci_HPC_TICK [Op p, SmallOp ix_hi, SmallOp ix_lo]
    
    867
    +
    
    859 868
     #if MIN_VERSION_rts(1,0,3)
    
    860 869
       BCO_NAME name            -> do np <- lit1 (BCONPtrStr name)
    
    861 870
                                      emit_ bci_BCO_NAME [Op np]
    

  • compiler/GHC/ByteCode/Instr.hs
    ... ... @@ -15,6 +15,7 @@ import GHC.ByteCode.Types
    15 15
     import GHC.Cmm.Type (Width)
    
    16 16
     import GHC.StgToCmm.Layout     ( ArgRep(..) )
    
    17 17
     import GHC.Utils.Outputable
    
    18
    +import GHC.Data.FastString     ( FastString )
    
    18 19
     import GHC.Types.Name
    
    19 20
     import GHC.Types.Literal
    
    20 21
     import GHC.Types.Unique
    
    ... ... @@ -257,6 +258,7 @@ data BCInstr
    257 258
     
    
    258 259
        -- Breakpoints
    
    259 260
        | BRK_FUN          !InternalBreakpointId
    
    261
    +   | HPC_TICK         !FastString !Word32
    
    260 262
     
    
    261 263
     #if MIN_VERSION_rts(1,0,3)
    
    262 264
        -- | A "meta"-instruction for recording the name of a BCO for debugging purposes.
    
    ... ... @@ -452,6 +454,7 @@ instance Outputable BCInstr where
    452 454
                                  = text "BRK_FUN" <+> text "<breakarray>"
    
    453 455
                                    <+> ppr info_mod <+> ppr infox
    
    454 456
                                    <+> text "<cc>"
    
    457
    +   ppr (HPC_TICK lbl ix)     = text "HPC_TICK" <+> ppr lbl <+> ppr ix
    
    455 458
     #if MIN_VERSION_rts(1,0,3)
    
    456 459
        ppr (BCO_NAME nm)         = text "BCO_NAME" <+> text (show nm)
    
    457 460
     #endif
    
    ... ... @@ -578,6 +581,7 @@ bciStackUse OP_INDEX_ADDR{} = 0
    578 581
     
    
    579 582
     bciStackUse SWIZZLE{}             = 0
    
    580 583
     bciStackUse BRK_FUN{}             = 0
    
    584
    +bciStackUse HPC_TICK{}            = 0
    
    581 585
     
    
    582 586
     -- These insns actually reduce stack use, but we need the high-tide level,
    
    583 587
     -- so can't use this info.  Not that it matters much.
    

  • compiler/GHC/ByteCode/Types.hs
    ... ... @@ -25,6 +25,9 @@ module GHC.ByteCode.Types
    25 25
       -- * Mod Breaks
    
    26 26
       , ModBreaks (..), BreakpointId(..), BreakTickIndex
    
    27 27
     
    
    28
    +  -- * Hpc Info
    
    29
    +  , ByteCodeHpcInfo(..)
    
    30
    +
    
    28 31
       -- * Internal Mod Breaks
    
    29 32
       , InternalModBreaks(..), CgBreakInfo(..), seqInternalModBreaks
    
    30 33
       -- ** Internal breakpoint identifier
    
    ... ... @@ -35,6 +38,7 @@ import GHC.Prelude
    35 38
     
    
    36 39
     import GHC.Data.FastString
    
    37 40
     import GHC.Data.FlatBag
    
    41
    +import qualified GHC.Data.Strict as Strict
    
    38 42
     import GHC.Types.Name
    
    39 43
     import GHC.Types.Name.Env
    
    40 44
     import GHC.Utils.Binary
    
    ... ... @@ -79,6 +83,25 @@ data CompiledByteCode = CompiledByteCode
    79 83
         -- ^ Static pointer table entries which should be loaded along with the
    
    80 84
         -- BCOs. See Note [Grand plan for static forms] in
    
    81 85
         -- "GHC.Iface.Tidy.StaticPtrTable".
    
    86
    +
    
    87
    +  , bc_hpc_info :: !(Strict.Maybe ByteCodeHpcInfo)
    
    88
    +    -- ^ 'ByteCodeHpcInfo' that should be added to the run-time system when this 'CompiledByteCode'
    
    89
    +    -- object is loaded.
    
    90
    +    --
    
    91
    +    -- It is safe to load the same 'ByteCodeHpcInfo' multiple times.
    
    92
    +  }
    
    93
    +
    
    94
    +-- | ByteCode specific HPC information.
    
    95
    +--
    
    96
    +data ByteCodeHpcInfo = ByteCodeHpcInfo
    
    97
    +  { bchi_module_name :: !String
    
    98
    +  -- ^ Name of the module.
    
    99
    +  , bchi_tickbox_name :: !String
    
    100
    +  -- ^ Name of the tick box that has been added via 'CStub'.
    
    101
    +  , bchi_tick_count :: {-# UNPACK #-} !Int
    
    102
    +  -- ^ Number of ticks.
    
    103
    +  , bchi_hash :: {-# UNPACK #-} !Int
    
    104
    +  -- ^ mix-file hash.
    
    82 105
       }
    
    83 106
     
    
    84 107
     -- | A libffi ffi_cif function prototype.
    

  • compiler/GHC/Driver/Backend.hs
    ... ... @@ -712,8 +712,7 @@ backendSupportsHpc (Named NCG) = True
    712 712
     backendSupportsHpc (Named LLVM)        = True
    
    713 713
     backendSupportsHpc (Named ViaC)        = True
    
    714 714
     backendSupportsHpc (Named JavaScript)  = False
    
    715
    --- TODO: @terrorjack thinks that the bytecode backend should support HPC now since (!13493)
    
    716
    -backendSupportsHpc (Named Bytecode) = False
    
    715
    +backendSupportsHpc (Named Bytecode) = True
    
    717 716
     backendSupportsHpc (Named NoBackend)   = True
    
    718 717
     
    
    719 718
     -- | This flag says whether the back end supports foreign
    

  • compiler/GHC/Driver/CodeOutput.hs
    ... ... @@ -343,7 +343,6 @@ outputForeignStubs logger tmpfs dflags unit_state mod location stubs
    343 343
        cplusplus_hdr = "#if defined(__cplusplus)\nextern \"C\" {\n#endif\n"
    
    344 344
        cplusplus_ftr = "#if defined(__cplusplus)\n}\n#endif\n"
    
    345 345
     
    
    346
    -
    
    347 346
     -- It is more than likely that the stubs file will
    
    348 347
     -- turn out to be empty, in which case no file should be created.
    
    349 348
     outputForeignStubs_help :: FilePath -> String -> String -> String -> IO Bool
    

  • compiler/GHC/Driver/Main.hs
    ... ... @@ -134,6 +134,7 @@ import GHC.Driver.Config.Diagnostic
    134 134
     import GHC.Driver.Config.Tidy
    
    135 135
     import GHC.Driver.Hooks
    
    136 136
     import GHC.Driver.GenerateCgIPEStub (generateCgIPEStub, lookupEstimatedTicks)
    
    137
    +import GHC.Driver.Ppr (showSDoc)
    
    137 138
     
    
    138 139
     import GHC.Runtime.Context
    
    139 140
     import GHC.Runtime.Interpreter
    
    ... ... @@ -151,6 +152,7 @@ import GHC.Hs.Dump
    151 152
     import GHC.Hs.Stats         ( ppSourceStats )
    
    152 153
     
    
    153 154
     import GHC.HsToCore
    
    155
    +import GHC.HsToCore.Coverage ( hpcTickBoxes, hpcModuleName )
    
    154 156
     
    
    155 157
     import GHC.StgToByteCode    ( byteCodeGen )
    
    156 158
     import GHC.StgToJS          ( stgToJS )
    
    ... ... @@ -207,6 +209,8 @@ import qualified GHC.StgToCmm as StgToCmm ( codeGen )
    207 209
     import GHC.StgToCmm.Types (CmmCgInfos (..), ModuleLFInfos, LambdaFormInfo(..))
    
    208 210
     import GHC.StgToCmm.CgUtils (CgStream)
    
    209 211
     
    
    212
    +import qualified GHC.ByteCode.Serialize as ByteCode
    
    213
    +
    
    210 214
     import GHC.Cmm
    
    211 215
     import GHC.Cmm.Info.Build
    
    212 216
     import GHC.Cmm.Pipeline
    
    ... ... @@ -237,6 +241,7 @@ import GHC.Types.Var.Set
    237 241
     import GHC.Types.Error
    
    238 242
     import GHC.Types.Fixity.Env
    
    239 243
     import GHC.Types.CostCentre
    
    244
    +import GHC.Types.HpcInfo (HpcInfo (..))
    
    240 245
     import GHC.Types.IPE
    
    241 246
     import GHC.Types.SourceFile
    
    242 247
     import GHC.Types.SrcLoc
    
    ... ... @@ -260,6 +265,7 @@ import GHC.Utils.Touch
    260 265
     import GHC.Data.FastString
    
    261 266
     import GHC.Data.Bag
    
    262 267
     import GHC.Data.OsPath (unsafeEncodeUtf)
    
    268
    +import qualified GHC.Data.Strict as Strict
    
    263 269
     import GHC.Data.StringBuffer
    
    264 270
     import qualified GHC.Data.Stream as Stream
    
    265 271
     import GHC.Data.Maybe
    
    ... ... @@ -297,7 +303,6 @@ import GHC.Cmm.Config (CmmConfig)
    297 303
     import Data.Bifunctor
    
    298 304
     import qualified GHC.Unit.Home.Graph as HUG
    
    299 305
     import GHC.Unit.Home.PackageTable
    
    300
    -import qualified GHC.ByteCode.Serialize as ByteCode
    
    301 306
     
    
    302 307
     {- **********************************************************************
    
    303 308
     %*                                                                      *
    
    ... ... @@ -1185,7 +1190,7 @@ compileWholeCoreBindings hsc_env type_env wcb = do
    1185 1190
         gen_bytecode core_binds stubs foreign_files = do
    
    1186 1191
           let cgi_guts = CgInteractiveGuts wcb_module core_binds
    
    1187 1192
                           (typeEnvTyCons type_env) stubs foreign_files
    
    1188
    -                      Nothing []
    
    1193
    +                      Nothing [] NoHpcInfo
    
    1189 1194
           trace_if logger (text "Generating ByteCode for" <+> ppr wcb_module)
    
    1190 1195
           mkModuleByteCode hsc_env wcb_module wcb_mod_location cgi_guts
    
    1191 1196
     
    
    ... ... @@ -2135,11 +2140,12 @@ data CgInteractiveGuts = CgInteractiveGuts { cgi_module :: Module
    2135 2140
                                                , cgi_foreign_files :: [(ForeignSrcLang, FilePath)]
    
    2136 2141
                                                , cgi_modBreaks ::  Maybe ModBreaks
    
    2137 2142
                                                , cgi_spt_entries :: [SptEntry]
    
    2143
    +                                           , cgi_hpc_info :: HpcInfo
    
    2138 2144
                                                }
    
    2139 2145
     
    
    2140 2146
     mkCgInteractiveGuts :: CgGuts -> CgInteractiveGuts
    
    2141
    -mkCgInteractiveGuts CgGuts{cg_module, cg_binds, cg_tycons, cg_foreign, cg_foreign_files, cg_modBreaks, cg_spt_entries}
    
    2142
    -  = CgInteractiveGuts cg_module cg_binds cg_tycons cg_foreign cg_foreign_files cg_modBreaks cg_spt_entries
    
    2147
    +mkCgInteractiveGuts CgGuts{cg_module, cg_binds, cg_tycons, cg_foreign, cg_foreign_files, cg_modBreaks, cg_spt_entries, cg_hpc_info}
    
    2148
    +  = CgInteractiveGuts cg_module cg_binds cg_tycons cg_foreign cg_foreign_files cg_modBreaks cg_spt_entries cg_hpc_info
    
    2143 2149
     
    
    2144 2150
     hscInteractive :: HscEnv
    
    2145 2151
                    -> CgInteractiveGuts
    
    ... ... @@ -2162,13 +2168,15 @@ hscGenerateByteCode :: HscEnv -> CgInteractiveGuts -> ModLocation -> IO Compiled
    2162 2168
     hscGenerateByteCode hsc_env cgguts location = do
    
    2163 2169
         let dflags = hsc_dflags hsc_env
    
    2164 2170
         let logger = hsc_logger hsc_env
    
    2171
    +    let platform = targetPlatform dflags
    
    2165 2172
         let CgInteractiveGuts{ -- This is the last use of the ModGuts in a compilation.
    
    2166 2173
                     -- From now on, we just use the bits we need.
    
    2167 2174
                    cgi_module   = this_mod,
    
    2168 2175
                    cgi_binds    = core_binds,
    
    2169 2176
                    cgi_tycons   = tycons,
    
    2170 2177
                    cgi_modBreaks = mod_breaks,
    
    2171
    -               cgi_spt_entries = spt_entries } = cgguts
    
    2178
    +               cgi_spt_entries = spt_entries,
    
    2179
    +               cgi_hpc_info = hpc_info } = cgguts
    
    2172 2180
     
    
    2173 2181
         -------------------
    
    2174 2182
         -- ADD IMPLICIT BINDINGS
    
    ... ... @@ -2193,8 +2201,22 @@ hscGenerateByteCode hsc_env cgguts location = do
    2193 2201
     
    
    2194 2202
         let (stg_binds,_stg_deps) = unzip stg_binds_with_deps
    
    2195 2203
     
    
    2204
    +    -------------------
    
    2205
    +    -- Setup HPC info
    
    2206
    +    let
    
    2207
    +      -- Strict to not retain a reference to the 'cgguts' via 'hpc_info'
    
    2208
    +      !bytecodeHpcInfo = case hpc_info of
    
    2209
    +        NoHpcInfo -> Strict.Nothing
    
    2210
    +        HpcInfo{hpcInfoTickCount, hpcInfoHash} ->
    
    2211
    +          Strict.Just ByteCodeHpcInfo
    
    2212
    +            { bchi_tick_count = hpcInfoTickCount
    
    2213
    +            , bchi_hash = hpcInfoHash
    
    2214
    +            , bchi_tickboxes = showSDoc dflags $ hpcTickBoxes platform this_mod
    
    2215
    +            , bchi_module_name = showSDoc dflags $ hpcModuleName this_mod
    
    2216
    +            }
    
    2217
    +
    
    2196 2218
         -----------------  Generate byte code ------------------
    
    2197
    -    byteCodeGen hsc_env this_mod stg_binds tycons mod_breaks spt_entries
    
    2219
    +    byteCodeGen hsc_env this_mod stg_binds tycons mod_breaks spt_entries bytecodeHpcInfo
    
    2198 2220
     
    
    2199 2221
     -- | Generate a byte code object linkable and write it to a file if `-fwrite-byte-code` is enabled.
    
    2200 2222
     generateAndWriteByteCode :: HscEnv -> CgInteractiveGuts -> ModLocation -> IO ModuleByteCode
    
    ... ... @@ -2843,6 +2865,7 @@ hscCompileCoreExpr' hsc_env srcspan ds_expr = do
    2843 2865
                     []
    
    2844 2866
                     Nothing -- modbreaks
    
    2845 2867
                     [] -- spt entries
    
    2868
    +                Strict.Nothing -- no hpc info
    
    2846 2869
     
    
    2847 2870
           {- load it -}
    
    2848 2871
           bco_time <- getCurrentTime
    

  • compiler/GHC/Driver/Session.hs
    ... ... @@ -3791,12 +3791,6 @@ makeDynFlagsConsistent dflags
    3791 3791
                pgmError (backendDescription (backend dflags) ++
    
    3792 3792
                          " supports only unregisterised ABI but target platform doesn't use it.")
    
    3793 3793
     
    
    3794
    - | gopt Opt_Hpc dflags && not (backendSupportsHpc (backend dflags))
    
    3795
    -    = let dflags' = gopt_unset dflags Opt_Hpc
    
    3796
    -          warn = "Hpc can't be used with " ++ backendDescription (backend dflags) ++
    
    3797
    -                 ". Ignoring -fhpc."
    
    3798
    -      in loop dflags' warn
    
    3799
    -
    
    3800 3794
      | backendSwappableWithViaC (backend dflags) &&
    
    3801 3795
        platformUnregisterised (targetPlatform dflags)
    
    3802 3796
         = loop (dflags { backend = viaCBackend })
    

  • compiler/GHC/HsToCore.hs
    ... ... @@ -163,20 +163,20 @@ deSugar hsc_env
    163 163
                                            export_set (typeEnvTyCons type_env) binds
    
    164 164
                                   else return (binds, Nothing)
    
    165 165
             ; let modBreaks
    
    166
    -                | Just (_, specs) <- m_tickInfo
    
    166
    +                | Just (_, _, breakpointSpecs) <- m_tickInfo
    
    167 167
                     , breakpointsAllowed dflags
    
    168
    -                = Just $ mkModBreaks (interpreterProfiled $ hscInterp hsc_env) mod specs
    
    168
    +                = Just $ mkModBreaks (interpreterProfiled $ hscInterp hsc_env) mod breakpointSpecs
    
    169 169
                     | otherwise
    
    170 170
                     = Nothing
    
    171 171
     
    
    172 172
             ; ds_hpc_info <- case m_tickInfo of
    
    173
    -            Just (orig_file2, ticks)
    
    173
    +            Just (orig_file2, hpcTicks, _)
    
    174 174
                   | gopt Opt_Hpc $ hsc_dflags hsc_env
    
    175 175
                   -> do
    
    176 176
                   hashNo <- if gopt Opt_Hpc $ hsc_dflags hsc_env
    
    177
    -                then writeMixEntries (hpcDir dflags) mod ticks orig_file2
    
    177
    +                then writeMixEntries (hpcDir dflags) mod hpcTicks orig_file2
    
    178 178
                     else return 0 -- dummy hash when none are written
    
    179
    -              pure $ HpcInfo (fromIntegral $ sizeSS ticks) hashNo
    
    179
    +              pure $ HpcInfo (fromIntegral $ sizeSS hpcTicks) hashNo
    
    180 180
                 _ -> pure $ emptyHpcInfo
    
    181 181
     
    
    182 182
             ; (msgs, mb_res) <- initDs hsc_env tcg_env $
    

  • compiler/GHC/HsToCore/Coverage.hs
    ... ... @@ -6,6 +6,9 @@
    6 6
     module GHC.HsToCore.Coverage
    
    7 7
       ( writeMixEntries
    
    8 8
       , hpcInitCode
    
    9
    +  , hpcStubLabel
    
    10
    +  , hpcModuleName
    
    11
    +  , hpcTickBoxes
    
    9 12
       ) where
    
    10 13
     
    
    11 14
     import GHC.Prelude as Prelude
    
    ... ... @@ -116,24 +119,33 @@ hpcInitCode _ _ (NoHpcInfo {}) = mempty
    116 119
     hpcInitCode platform this_mod (HpcInfo tickCount hashNo)
    
    117 120
      = initializerCStub platform fn_name decls body
    
    118 121
       where
    
    119
    -    fn_name = mkInitializerStubLabel this_mod (fsLit "hpc")
    
    122
    +    fn_name = hpcStubLabel this_mod
    
    120 123
         decls = text "StgWord64 " <> tickboxes <> brackets (int tickCount) <> semi
    
    121 124
         body = text "hs_hpc_module" <>
    
    122 125
                   parens (hcat (punctuate comma [
    
    123
    -                  doubleQuotes full_name_str,
    
    126
    +                  doubleQuotes (hpcModuleName this_mod),
    
    124 127
                       int tickCount, -- really StgWord32
    
    125 128
                       int hashNo,    -- really StgWord32
    
    126 129
                       tickboxes
    
    127 130
                     ])) <> semi
    
    131
    +    tickboxes = hpcTickBoxes platform this_mod
    
    128 132
     
    
    129
    -    tickboxes = pprCLabel platform (mkHpcTicksLabel $ this_mod)
    
    130
    -
    
    131
    -    module_name  = hcat (map (text.charToC) $ BS.unpack $
    
    132
    -                         bytesFS (moduleNameFS (moduleName this_mod)))
    
    133
    -    package_name = hcat (map (text.charToC) $ BS.unpack $
    
    134
    -                         bytesFS (unitFS  (moduleUnit this_mod)))
    
    135
    -    full_name_str
    
    136
    -       | moduleUnit this_mod == mainUnit
    
    137
    -       = module_name
    
    138
    -       | otherwise
    
    139
    -       = package_name <> char '/' <> module_name
    133
    +hpcStubLabel :: Module -> CLabel
    
    134
    +hpcStubLabel this_mod = mkInitializerStubLabel this_mod (fsLit "hpc")
    
    135
    +
    
    136
    +hpcModuleName :: Module -> SDoc
    
    137
    +hpcModuleName this_mod =  full_name_str
    
    138
    +  where
    
    139
    +  full_name_str
    
    140
    +    | moduleUnit this_mod == mainUnit
    
    141
    +    = module_name
    
    142
    +    | otherwise
    
    143
    +    = package_name <> char '/' <> module_name
    
    144
    +  module_name  = hcat (map (text.charToC) $ BS.unpack $
    
    145
    +                    bytesFS (moduleNameFS (moduleName this_mod)))
    
    146
    +
    
    147
    +  package_name = hcat (map (text.charToC) $ BS.unpack $
    
    148
    +                        bytesFS (unitFS  (moduleUnit this_mod)))
    
    149
    +
    
    150
    +hpcTickBoxes :: Platform -> Module -> SDoc
    
    151
    +hpcTickBoxes platform this_mod = pprCLabel platform (mkHpcTicksLabel this_mod)

  • compiler/GHC/HsToCore/Ticks.hs
    ... ... @@ -100,7 +100,7 @@ addTicksToBinds
    100 100
                                     -- hasn't set it), so we have to work from this set.
    
    101 101
             -> [TyCon]              -- ^ Type constructors in this module
    
    102 102
             -> LHsBinds GhcTc
    
    103
    -        -> IO (LHsBinds GhcTc, Maybe (FilePath, SizedSeq Tick))
    
    103
    +        -> IO (LHsBinds GhcTc, Maybe (FilePath, SizedSeq Tick, SizedSeq Tick))
    
    104 104
     
    
    105 105
     addTicksToBinds logger cfg
    
    106 106
                     mod mod_loc exports tyCons binds
    
    ... ... @@ -133,12 +133,13 @@ addTicksToBinds logger cfg
    133 133
     
    
    134 134
               (binds1,st) = foldr tickPass (binds, initTTState) passes
    
    135 135
     
    
    136
    -          extendedMixEntries = ticks st
    
    136
    +          hpcEntries = hpcTicks st
    
    137
    +          breakpointEntries = breakpointTicks st
    
    137 138
     
    
    138 139
          putDumpFileMaybe logger Opt_D_dump_ticked "HPC" FormatHaskell
    
    139 140
            (pprLHsBinds binds1)
    
    140 141
     
    
    141
    -     return (binds1, Just (orig_file2, extendedMixEntries))
    
    142
    +     return (binds1, Just (orig_file2, hpcEntries, breakpointEntries))
    
    142 143
     
    
    143 144
       | otherwise = return (binds, Nothing)
    
    144 145
     
    
    ... ... @@ -1050,23 +1051,31 @@ addTickArithSeqInfo (FromThenTo e1 e2 e3) =
    1050 1051
                     (addTickLHsExpr e2)
    
    1051 1052
                     (addTickLHsExpr e3)
    
    1052 1053
     
    
    1053
    -data TickTransState = TT { ticks       :: !(SizedSeq Tick)
    
    1054
    -                         , ccIndices   :: !CostCentreState
    
    1055
    -                         , recSelTicks :: !(IdEnv CoreTickish)
    
    1054
    +data TickTransState = TT { hpcTicks        :: !(SizedSeq Tick)
    
    1055
    +                         , breakpointTicks :: !(SizedSeq Tick)
    
    1056
    +                         , ccIndices       :: !CostCentreState
    
    1057
    +                         , recSelTicks     :: !(IdEnv CoreTickish)
    
    1056 1058
                              }
    
    1057 1059
     
    
    1058 1060
     initTTState :: TickTransState
    
    1059
    -initTTState = TT { ticks        = emptySS
    
    1060
    -                 , ccIndices    = newCostCentreState
    
    1061
    -                 , recSelTicks  = emptyVarEnv
    
    1061
    +initTTState = TT { hpcTicks        = emptySS
    
    1062
    +                 , breakpointTicks = emptySS
    
    1063
    +                 , ccIndices       = newCostCentreState
    
    1064
    +                 , recSelTicks     = emptyVarEnv
    
    1062 1065
                      }
    
    1063 1066
     
    
    1064
    -addMixEntry :: Tick -> TM Int
    
    1065
    -addMixEntry ent = do
    
    1066
    -  c <- fromIntegral . sizeSS . ticks <$> getState
    
    1067
    +addHpcEntry :: Tick -> TM Int
    
    1068
    +addHpcEntry ent = do
    
    1069
    +  c <- fromIntegral . sizeSS . hpcTicks <$> getState
    
    1067 1070
       setState $ \st ->
    
    1068
    -    st { ticks = addToSS (ticks st) ent
    
    1069
    -       }
    
    1071
    +    st { hpcTicks = addToSS (hpcTicks st) ent }
    
    1072
    +  return c
    
    1073
    +
    
    1074
    +addBreakpointEntry :: Tick -> TM Int
    
    1075
    +addBreakpointEntry ent = do
    
    1076
    +  c <- fromIntegral . sizeSS . breakpointTicks <$> getState
    
    1077
    +  setState $ \st ->
    
    1078
    +    st { breakpointTicks = addToSS (breakpointTicks st) ent }
    
    1070 1079
       return c
    
    1071 1080
     
    
    1072 1081
     addRecSelTick :: Id -> CoreTickish -> TM ()
    
    ... ... @@ -1291,7 +1300,7 @@ mkTickish boxLabel countEntries topOnly pos fvs decl_path = do
    1291 1300
     
    
    1292 1301
       env <- getEnv
    
    1293 1302
       case tickishType env of
    
    1294
    -    HpcTicks -> HpcTick (this_mod env) <$> addMixEntry me
    
    1303
    +    HpcTicks -> HpcTick (this_mod env) <$> addHpcEntry me
    
    1295 1304
     
    
    1296 1305
         ProfNotes -> do
    
    1297 1306
           flavour <- mkHpcCCFlavour <$> getCCIndexM cc_name
    
    ... ... @@ -1300,7 +1309,7 @@ mkTickish boxLabel countEntries topOnly pos fvs decl_path = do
    1300 1309
           return $ ProfNote cc count True{-scopes-}
    
    1301 1310
     
    
    1302 1311
         Breakpoints -> do
    
    1303
    -      i <- addMixEntry me
    
    1312
    +      i <- addBreakpointEntry me
    
    1304 1313
           pure (Breakpoint noExtField (BreakpointId (this_mod env) i) ids)
    
    1305 1314
     
    
    1306 1315
         SourceNotes | RealSrcSpan pos' _ <- pos ->
    
    ... ... @@ -1325,19 +1334,19 @@ mkBinTickBoxHpc :: (Bool -> BoxLabel) -> SrcSpan -> LHsExpr GhcTc
    1325 1334
     mkBinTickBoxHpc boxLabel pos e = do
    
    1326 1335
       env <- getEnv
    
    1327 1336
       binTick <- HsBinTick
    
    1328
    -    <$> addMixEntry (Tick { tick_loc = pos
    
    1337
    +    <$> addHpcEntry (Tick { tick_loc = pos
    
    1329 1338
                               , tick_path = declPath env
    
    1330 1339
                               , tick_ids = []
    
    1331 1340
                               , tick_label = boxLabel True
    
    1332 1341
                               })
    
    1333
    -    <*> addMixEntry (Tick { tick_loc = pos
    
    1342
    +    <*> addHpcEntry (Tick { tick_loc = pos
    
    1334 1343
                               , tick_path = declPath env
    
    1335 1344
                               , tick_ids = []
    
    1336 1345
                               , tick_label = boxLabel False
    
    1337 1346
                               })
    
    1338 1347
         <*> pure e
    
    1339 1348
       tick <- HpcTick (this_mod env)
    
    1340
    -    <$> addMixEntry (Tick { tick_loc = pos
    
    1349
    +    <$> addHpcEntry (Tick { tick_loc = pos
    
    1341 1350
                               , tick_path = declPath env
    
    1342 1351
                               , tick_ids = []
    
    1343 1352
                               , tick_label = ExpBox False
    

  • compiler/GHC/Iface/Tidy.hs
    ... ... @@ -402,6 +402,7 @@ tidyProgram opts (ModGuts { mg_module = mod
    402 402
                               , mg_foreign_files    = foreign_files
    
    403 403
                               , mg_modBreaks        = modBreaks
    
    404 404
                               , mg_boot_exports     = boot_exports
    
    405
    +                          , mg_hpc_info         = hpc_info
    
    405 406
                               }) = do
    
    406 407
     
    
    407 408
       (unfold_env, tidy_occ_env) <- chooseExternalIds opts mod tcs binds imp_rules
    
    ... ... @@ -471,6 +472,7 @@ tidyProgram opts (ModGuts { mg_module = mod
    471 472
                      , cg_dep_pkgs      = S.map snd (dep_direct_pkgs deps)
    
    472 473
                      , cg_modBreaks     = modBreaks
    
    473 474
                      , cg_spt_entries   = spt_entries
    
    475
    +                 , cg_hpc_info      = hpc_info
    
    474 476
                      }
    
    475 477
              , ModDetails { md_types            = tidy_type_env
    
    476 478
                           , md_rules            = tidy_rules
    

  • compiler/GHC/Linker/Loader.hs
    ... ... @@ -137,6 +137,10 @@ import qualified Data.IntMap.Strict as IM
    137 137
     import qualified Data.Map.Strict as M
    
    138 138
     import Foreign.Ptr (nullPtr)
    
    139 139
     import GHC.ByteCode.Serialize
    
    140
    +-- TODO: this import is wrong
    
    141
    +import GHC.HsToCore.Coverage (hpcModuleName)
    
    142
    +import qualified Data.ByteString.Char8 as BS8
    
    143
    +import qualified GHC.Data.Strict as Strict
    
    140 144
     
    
    141 145
     -- Note [Linkers and loaders]
    
    142 146
     -- ~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    ... ... @@ -983,10 +987,9 @@ dynLinkBCOs interp pls keep_spec bcos =
    983 987
             let (bcos_loaded', new_bcos) = rmDupLinkables (bcos_loaded pls) bcos
    
    984 988
                 pls1                     = pls { bcos_loaded = bcos_loaded' }
    
    985 989
     
    
    986
    -            cbcs :: [CompiledByteCode]
    
    987
    -            cbcs = concatMap linkableBCOs new_bcos
    
    990
    +            mbcs = concatMap linkableBCOs new_bcos
    
    988 991
             in do
    
    989
    -          bco_state <- dynLinkCompiledByteCode interp (pkgs_loaded pls) (bco_loader_state pls) traverseHomePackageBytecodeState keep_spec cbcs
    
    992
    +          bco_state <- dynLinkCompiledByteCode interp (pkgs_loaded pls) (bco_loader_state pls) traverseHomePackageBytecodeState keep_spec mbcs
    
    990 993
               return $! pls1 { bco_loader_state = bco_state }
    
    991 994
     
    
    992 995
     dynLinkCompiledByteCode :: Interp
    
    ... ... @@ -996,22 +999,22 @@ dynLinkCompiledByteCode :: Interp
    996 999
                             -> KeepModuleLinkableDefinitions
    
    997 1000
                             -> [CompiledByteCode]
    
    998 1001
                             -> IO BytecodeLoaderState
    
    999
    -dynLinkCompiledByteCode interp pkgs_loaded whole_bytecode_state traverse_bytecode_state keep_spec cbcs = do
    
    1002
    +dynLinkCompiledByteCode interp pkgs_loaded whole_bytecode_state traverse_bytecode_state keep_spec mbcs = do
    
    1000 1003
             st1 <- traverse_bytecode_state whole_bytecode_state $ \bytecode_state -> do
    
    1001 1004
               let
    
    1002 1005
                   le1 = bco_linker_env bytecode_state
    
    1003 1006
                   lb1 = bco_linked_breaks bytecode_state
    
    1004
    -          ie2 <- linkITbls interp (itbl_env le1) (concatMap bc_itbls cbcs)
    
    1005
    -          ae2 <- foldlM (\env cbc -> allocateTopStrings interp (bc_strs cbc) env) (addr_env le1) cbcs
    
    1006
    -          be2 <- allocateBreakArrays interp (breakarray_env lb1) (catMaybes $ map bc_breaks cbcs)
    
    1007
    -          ce2 <- allocateCCS         interp (ccs_env lb1)        (catMaybes $ map bc_breaks cbcs)
    
    1007
    +          ie2 <- linkITbls interp (itbl_env le1) (concatMap bc_itbls mbcs)
    
    1008
    +          ae2 <- foldlM (\env cbc -> allocateTopStrings interp (bc_strs cbc) env) (addr_env le1) mbcs
    
    1009
    +          be2 <- allocateBreakArrays interp (breakarray_env lb1) (catMaybes $ map bc_breaks mbcs)
    
    1010
    +          ce2 <- allocateCCS         interp (ccs_env lb1)        (catMaybes $ map bc_breaks mbcs)
    
    1008 1011
               let le2 = le1 { itbl_env = ie2, addr_env = ae2 }
    
    1009 1012
               let lb2 = lb1 { breakarray_env = be2, ccs_env = ce2 }
    
    1010 1013
               return $! bytecode_state { bco_linker_env = le2, bco_linked_breaks = lb2 }
    
    1011 1014
     
    
    1012 1015
             -- NB: Important to pass the whole bytecode loader state to linkSomeBCOs so that you can find Names in local
    
    1013 1016
             -- and external packages.
    
    1014
    -        names_and_refs <- linkSomeBCOs interp pkgs_loaded st1 cbcs
    
    1017
    +        names_and_refs <- linkSomeBCOs interp pkgs_loaded st1 mbcs
    
    1015 1018
     
    
    1016 1019
             -- We only want to add the external ones to the ClosureEnv
    
    1017 1020
             let (to_add, to_drop) = partition (keepDefinitions keep_spec . fst) names_and_refs
    
    ... ... @@ -1024,7 +1027,9 @@ dynLinkCompiledByteCode interp pkgs_loaded whole_bytecode_state traverse_bytecod
    1024 1027
             traverse_bytecode_state st1 $ \bytecode_state -> do
    
    1025 1028
               let ce2 = extendClosureEnv (closure_env (bco_linker_env bytecode_state)) new_binds
    
    1026 1029
               -- Add SPT entries
    
    1027
    -          mapM_ (linkSptEntry interp ce2) (concatMap bc_spt_entries cbcs)
    
    1030
    +          mapM_ (linkSptEntry interp ce2) (concatMap bc_spt_entries mbcs)
    
    1031
    +          -- Load HPC modules
    
    1032
    +          mapM_ (linkHpcEntry interp . bc_hpc_info) mbcs
    
    1028 1033
               return $! bytecode_state { bco_linker_env = (bco_linker_env bytecode_state) { closure_env = ce2 } }
    
    1029 1034
     
    
    1030 1035
     -- | Register SPT entries for this module in the interpreter
    
    ... ... @@ -1037,8 +1042,14 @@ linkSptEntry interp ce (SptEntry name fpr) = do
    1037 1042
         Nothing -> pprPanic "linkSptEntry" (ppr name)
    
    1038 1043
         Just (_, hval) -> addSptEntry interp fpr hval
    
    1039 1044
     
    
    1040
    -
    
    1041
    -
    
    1045
    +linkHpcEntry :: Interp -> Strict.Maybe ByteCodeHpcInfo -> IO ()
    
    1046
    +linkHpcEntry _interp Strict.Nothing = pure ()
    
    1047
    +linkHpcEntry interp (Strict.Just info) = do
    
    1048
    +  addHpcModule interp
    
    1049
    +    (bchi_module_name info)
    
    1050
    +    (bchi_tick_count info)
    
    1051
    +    (bchi_hash info)
    
    1052
    +    (bchi_tickboxes info)
    
    1042 1053
     
    
    1043 1054
     -- Link a bunch of BCOs and return references to their values
    
    1044 1055
     linkSomeBCOs :: Interp
    

  • compiler/GHC/Linker/Types.hs
    ... ... @@ -214,36 +214,37 @@ data BytecodeLoaderState = BytecodeLoaderState
    214 214
            -- ^ Information about bytecode objects from the home package we have loaded into the interpreter.
    
    215 215
            , externalPackage_loaded :: BytecodeState
    
    216 216
            -- ^ Information about bytecode objects from external packages we have loaded into the interpreter.
    
    217
    +       , hpcInitialised :: !Bool
    
    217 218
            }
    
    218 219
     
    
    219 220
     
    
    220 221
     -- | Find a name loaded from bytecode
    
    221 222
     lookupNameBytecodeState :: BytecodeLoaderState -> Name -> Maybe (Name, ForeignHValue)
    
    222
    -lookupNameBytecodeState (BytecodeLoaderState home_package external_package) name = do
    
    223
    +lookupNameBytecodeState (BytecodeLoaderState home_package external_package _) name = do
    
    223 224
           lookupNameEnv (closure_env (bco_linker_env home_package)) name
    
    224 225
       <|> lookupNameEnv (closure_env (bco_linker_env external_package)) name
    
    225 226
     
    
    226 227
     -- | Look up a break array in the bytecode loader state.
    
    227 228
     lookupBreakArrayBytecodeState :: BytecodeLoaderState -> Module -> Maybe (ForeignRef BreakArray)
    
    228
    -lookupBreakArrayBytecodeState (BytecodeLoaderState home_package external_package) break_mod = do
    
    229
    +lookupBreakArrayBytecodeState (BytecodeLoaderState home_package external_package _) break_mod = do
    
    229 230
       lookupModuleEnv (breakarray_env (bco_linked_breaks home_package)) break_mod
    
    230 231
       <|> lookupModuleEnv (breakarray_env (bco_linked_breaks external_package)) break_mod
    
    231 232
     
    
    232 233
     -- | Look up an info table in the bytecode loader state.
    
    233 234
     lookupInfoTableBytecodeState :: BytecodeLoaderState -> Name -> Maybe (Name, ItblPtr)
    
    234
    -lookupInfoTableBytecodeState (BytecodeLoaderState home_package external_package) info_mod = do
    
    235
    +lookupInfoTableBytecodeState (BytecodeLoaderState home_package external_package _) info_mod = do
    
    235 236
       lookupNameEnv (itbl_env (bco_linker_env home_package)) info_mod
    
    236 237
       <|> lookupNameEnv (itbl_env (bco_linker_env external_package)) info_mod
    
    237 238
     
    
    238 239
     -- | Look up an address in the bytecode loader state.
    
    239 240
     lookupAddressBytecodeState :: BytecodeLoaderState -> Name -> Maybe (Name, AddrPtr)
    
    240
    -lookupAddressBytecodeState (BytecodeLoaderState home_package external_package) addr_mod = do
    
    241
    +lookupAddressBytecodeState (BytecodeLoaderState home_package external_package _) addr_mod = do
    
    241 242
       lookupNameEnv (addr_env (bco_linker_env home_package)) addr_mod
    
    242 243
       <|> lookupNameEnv (addr_env (bco_linker_env external_package)) addr_mod
    
    243 244
     
    
    244 245
     -- | Look up a cost centre stack in the bytecode loader state.
    
    245 246
     lookupCCSBytecodeState :: BytecodeLoaderState -> Module -> Maybe (Array BreakTickIndex (RemotePtr CostCentre))
    
    246
    -lookupCCSBytecodeState (BytecodeLoaderState home_package external_package) ccs_mod = do
    
    247
    +lookupCCSBytecodeState (BytecodeLoaderState home_package external_package _) ccs_mod = do
    
    247 248
       lookupModuleEnv (ccs_env (bco_linked_breaks home_package)) ccs_mod
    
    248 249
       <|> lookupModuleEnv (ccs_env (bco_linked_breaks external_package)) ccs_mod
    
    249 250
     
    
    ... ... @@ -251,6 +252,7 @@ emptyBytecodeLoaderState :: BytecodeLoaderState
    251 252
     emptyBytecodeLoaderState = BytecodeLoaderState
    
    252 253
         { homePackage_loaded = emptyBytecodeState
    
    253 254
         , externalPackage_loaded = emptyBytecodeState
    
    255
    +    , hpcInitialised = False
    
    254 256
         }
    
    255 257
     
    
    256 258
     emptyBytecodeState :: BytecodeState
    

  • compiler/GHC/Runtime/Interpreter.hs
    ... ... @@ -17,6 +17,7 @@ module GHC.Runtime.Interpreter
    17 17
       , mallocData
    
    18 18
       , createBCOs
    
    19 19
       , addSptEntry
    
    20
    +  , addHpcModule
    
    20 21
       , mkCostCentres
    
    21 22
       , costCentreStackInfo
    
    22 23
       , newBreakArray
    
    ... ... @@ -366,6 +367,10 @@ addSptEntry interp fpr ref =
    366 367
       withForeignRef ref $ \val ->
    
    367 368
         interpCmd interp (AddSptEntry fpr val)
    
    368 369
     
    
    370
    +addHpcModule :: Interp -> String -> Int -> Int -> String -> IO ()
    
    371
    +addHpcModule interp modLabel tickNo hash tickboxes  =
    
    372
    +  interpCmd interp (AddHpcModule modLabel tickNo hash tickboxes)
    
    373
    +
    
    369 374
     costCentreStackInfo :: Interp -> RemotePtr CostCentreStack -> IO [String]
    
    370 375
     costCentreStackInfo interp ccs =
    
    371 376
       interpCmd interp (CostCentreStackInfo ccs)
    

  • compiler/GHC/StgToByteCode.hs
    ... ... @@ -20,6 +20,7 @@ import GHC.ByteCode.Types
    20 20
     
    
    21 21
     import GHC.Cmm.CallConv
    
    22 22
     import GHC.Cmm.Expr
    
    23
    +import GHC.Cmm.CLabel (mkHpcTicksLabel, pprCLabel)
    
    23 24
     import GHC.Cmm.Reg ( GlobalArgRegs(..) )
    
    24 25
     import GHC.Cmm.Node
    
    25 26
     import GHC.Cmm.Utils
    
    ... ... @@ -97,6 +98,7 @@ import Control.Monad.IO.Class
    97 98
     import Control.Monad.Trans.Reader (ReaderT(..))
    
    98 99
     import Control.Monad.Trans.State  (StateT(..))
    
    99 100
     import Data.Bifunctor (Bifunctor(..))
    
    101
    +import qualified GHC.Data.Strict as Strict
    
    100 102
     
    
    101 103
     -- -----------------------------------------------------------------------------
    
    102 104
     -- Generating byte code for a complete module
    
    ... ... @@ -107,8 +109,9 @@ byteCodeGen :: HscEnv
    107 109
                 -> [TyCon]
    
    108 110
                 -> Maybe ModBreaks
    
    109 111
                 -> [SptEntry]
    
    112
    +            -> Strict.Maybe ByteCodeHpcInfo
    
    110 113
                 -> IO CompiledByteCode
    
    111
    -byteCodeGen hsc_env this_mod binds tycs mb_modBreaks spt_entries
    
    114
    +byteCodeGen hsc_env this_mod binds tycs mb_modBreaks spt_entries hpc_info
    
    112 115
        = withTiming logger
    
    113 116
                     (text "GHC.StgToByteCode"<+>brackets (ppr this_mod))
    
    114 117
                     (const ()) $ do
    
    ... ... @@ -134,7 +137,7 @@ byteCodeGen hsc_env this_mod binds tycs mb_modBreaks spt_entries
    134 137
             let mod_breaks = case mb_modBreaks of
    
    135 138
                  Nothing -> Nothing
    
    136 139
                  Just mb -> Just $ mkInternalModBreaks this_mod breakInfo mb
    
    137
    -        cbc <- assembleBCOs profile proto_bcos tycs strings mod_breaks spt_entries
    
    140
    +        cbc <- assembleBCOs profile proto_bcos tycs strings mod_breaks spt_entries hpc_info
    
    138 141
     
    
    139 142
             -- Squash space leaks in the CompiledByteCode.  This is really
    
    140 143
             -- important, because when loading a set of modules into GHCi
    
    ... ... @@ -604,6 +607,11 @@ schemeE _d _s _p (StgTick (Breakpoint _ bp_id _) _rhs)
    604 607
        = pprPanic "schemeE: Breakpoint without let binding:"
    
    605 608
             (ppr bp_id <+> text "forgot to run bcPrep?")
    
    606 609
     
    
    610
    +schemeE d s p (StgTick (HpcTick mod ix) rhs) = do
    
    611
    +   platform <- profilePlatform <$> getProfile
    
    612
    +   rhs_code <- schemeE d s p rhs
    
    613
    +   pure (unitOL (HPC_TICK (mkHpcTickLabel platform mod) (fromIntegral ix)) `appOL` rhs_code)
    
    614
    +
    
    607 615
     -- ignore other kinds of tick
    
    608 616
     schemeE d s p (StgTick _ rhs) = schemeE d s p rhs
    
    609 617
     
    
    ... ... @@ -2784,6 +2792,10 @@ getLastBreakTick = BcM $ \env st ->
    2784 2792
     tickFS :: FastString
    
    2785 2793
     tickFS = fsLit "ticked"
    
    2786 2794
     
    
    2795
    +mkHpcTickLabel :: Platform -> Module -> FastString
    
    2796
    +mkHpcTickLabel platform mod =
    
    2797
    +  fsLit (showSDocOneLine defaultSDocContext (pprCLabel platform (mkHpcTicksLabel mod)))
    
    2798
    +
    
    2787 2799
     -- Dehydrating CgBreakInfo
    
    2788 2800
     
    
    2789 2801
     dehydrateCgBreakInfo :: [TyVar] -> [Maybe (Id, Word)] -> Type -> Either InternalBreakLoc BreakpointId -> CgBreakInfo
    

  • compiler/GHC/Types/HpcInfo.hs
    ... ... @@ -18,4 +18,3 @@ data HpcInfo
    18 18
     
    
    19 19
     emptyHpcInfo :: HpcInfo
    
    20 20
     emptyHpcInfo = NoHpcInfo
    21
    -

  • compiler/GHC/Unit/Module/ModGuts.hs
    ... ... @@ -141,8 +141,9 @@ data CgGuts
    141 141
             cg_dep_pkgs  :: !(Set UnitId),      -- ^ Dependent packages, used to
    
    142 142
                                                 -- generate #includes for C code gen
    
    143 143
             cg_modBreaks :: !(Maybe ModBreaks), -- ^ Module breakpoints
    
    144
    -        cg_spt_entries :: [SptEntry]
    
    144
    +        cg_spt_entries :: [SptEntry],
    
    145 145
                     -- ^ Static pointer table entries for static forms defined in
    
    146 146
                     -- the module.
    
    147 147
                     -- See Note [Grand plan for static forms] in "GHC.Iface.Tidy.StaticPtrTable"
    
    148
    +        cg_hpc_info :: HpcInfo
    
    148 149
         }

  • libraries/ghci/GHCi/Coverage.hs
    1
    +{-# LANGUAGE ForeignFunctionInterface #-}
    
    2
    +{-# LANGUAGE LambdaCase #-}
    
    3
    +
    
    4
    +module GHCi.Coverage (
    
    5
    +  hpcAddModule,
    
    6
    +  ) where
    
    7
    +
    
    8
    +import Prelude -- See note [Why do we import Prelude here?]
    
    9
    +
    
    10
    +import Control.Exception
    
    11
    +import qualified Data.ByteString.Char8 as BS8
    
    12
    +import qualified Data.ByteString.Unsafe as B
    
    13
    +import Data.Word
    
    14
    +import Foreign
    
    15
    +import Foreign.C.String (withCAString)
    
    16
    +import GHC.Fingerprint
    
    17
    +import GHC.Foreign (CString)
    
    18
    +import GHCi.ObjLink (lookupSymbol)
    
    19
    +
    
    20
    +-- | Inform the run-time system that the given module name is instrumented via @hpc@
    
    21
    +-- and to collect @.tix@ info.
    
    22
    +--
    
    23
    +-- Starts the `hpc` run-time if it hasn't already been started.
    
    24
    +hpcAddModule ::
    
    25
    +  String ->
    
    26
    +  -- ^ Name of the module to instrument
    
    27
    +  Int ->
    
    28
    +  -- ^ Number of hpc ticks in this module
    
    29
    +  Int ->
    
    30
    +  -- ^ 'HpcInfo's 'hpcInfoHash'
    
    31
    +  String ->
    
    32
    +  -- ^ Name of the ticks array found in the c-stub.
    
    33
    +  IO ()
    
    34
    +hpcAddModule modlName ticks hash tickboxes = do
    
    35
    +  withCAString modlName $ \modlNameLiteral -> do
    
    36
    +    -- we need to find the reference to the ticks array.
    
    37
    +    lookupSymbol tickboxes >>= \ case
    
    38
    +      Nothing -> do
    
    39
    +        -- the symbol is not found, this is a bug!
    
    40
    +        throwIO $ ErrorCall $ "hpcAddModule: failed to find symbol " <> tickboxes
    
    41
    +      Just tickBoxRef -> do
    
    42
    +        -- Calling 'hs_hpc_module' multiple times is safe, it will add the module only once.
    
    43
    +        hpc_register_module modlNameLiteral (fromIntegral ticks) (fromIntegral hash) (castPtr tickBoxRef)
    
    44
    +        -- calling 'hpc_startup' multiple times is safe, it will only be initialised once.
    
    45
    +        hpc_startup
    
    46
    +
    
    47
    +foreign import ccall "hs_hpc_module"
    
    48
    +    hpc_register_module :: CString -> Word32 -> Word32 -> Ptr Word64 -> IO ()
    
    49
    +
    
    50
    +foreign import ccall "startupHpc"
    
    51
    +    hpc_startup :: IO ()

  • libraries/ghci/GHCi/Message.hs
    ... ... @@ -111,6 +111,8 @@ data Message a where
    111 111
     
    
    112 112
       -- | Add entries to the Static Pointer Table
    
    113 113
       AddSptEntry :: Fingerprint -> HValueRef -> Message ()
    
    114
    +  -- | Add module to hpc
    
    115
    +  AddHpcModule :: String -> Int -> Int -> String -> Message ()
    
    114 116
     
    
    115 117
       -- | Malloc some data and return a 'RemotePtr' to it
    
    116 118
       MallocData :: ByteString -> Message (RemotePtr ())
    
    ... ... @@ -607,7 +609,8 @@ getMessage = do
    607 609
           38 -> Msg <$> (ResumeSeq <$> get)
    
    608 610
           39 -> Msg <$> (LookupSymbolInDLL <$> get <*> get)
    
    609 611
           40 -> Msg <$> (WhereFrom <$> get)
    
    610
    -      41 -> Msg <$> (CustomMessage <$> get <*> get)
    
    612
    +      41 -> Msg <$> (AddHpcModule <$> get <*> get <*> get <*> get)
    
    613
    +      42 -> Msg <$> (CustomMessage <$> get <*> get)
    
    611 614
           _  -> error $ "Unknown Message code " ++ (show b)
    
    612 615
     
    
    613 616
     putMessage :: Message a -> Put
    
    ... ... @@ -654,7 +657,8 @@ putMessage m = case m of
    654 657
       ResumeSeq a                 -> putWord8 38 >> put a
    
    655 658
       LookupSymbolInDLL dll str   -> putWord8 39 >> put dll >> put str
    
    656 659
       WhereFrom a                 -> putWord8 40 >> put a
    
    657
    -  CustomMessage tag payload   -> putWord8 41 >> put tag >> put payload
    
    660
    +  AddHpcModule m n h ticks    -> putWord8 41 >> put m >> put n >> put h >> put ticks
    
    661
    +  CustomMessage tag payload   -> putWord8 42 >> put tag >> put payload
    
    658 662
     
    
    659 663
     {-
    
    660 664
     Note [Parallelize CreateBCOs serialization]
    

  • libraries/ghci/GHCi/Run.hs
    ... ... @@ -19,6 +19,7 @@ import GHCi.CreateBCO
    19 19
     import GHCi.InfoTable
    
    20 20
     #endif
    
    21 21
     
    
    22
    +import GHCi.Coverage
    
    22 23
     import qualified GHC.InfoProv as InfoProv
    
    23 24
     import GHCi.Debugger
    
    24 25
     import GHCi.FFI
    
    ... ... @@ -88,6 +89,7 @@ run m = case m of
    88 89
         fmap toRemotePtr <$> lookupSymbolInDLL (fromRemotePtr dll) str
    
    89 90
       FreeHValueRefs rs -> mapM_ freeRemoteRef rs
    
    90 91
       AddSptEntry fpr r -> localRef r >>= sptAddEntry fpr
    
    92
    +  AddHpcModule modl ticks hash tickboxes -> hpcAddModule modl ticks hash tickboxes
    
    91 93
       EvalStmt opts r -> evalStmt opts r
    
    92 94
       ResumeStmt opts r -> resumeStmt opts r
    
    93 95
       AbandonStmt r -> abandonStmt r
    

  • libraries/ghci/ghci.cabal.in
    ... ... @@ -59,6 +59,7 @@ library
    59 59
         if flag(internal-interpreter)
    
    60 60
             CPP-Options: -DHAVE_INTERNAL_INTERPRETER
    
    61 61
             exposed-modules:
    
    62
    +            GHCi.Coverage
    
    62 63
                 GHCi.Run
    
    63 64
                 GHCi.Debugger
    
    64 65
                 GHCi.CreateBCO
    

  • rts/Disassembler.c
    ... ... @@ -101,6 +101,13 @@ disInstr ( StgBCO *bco, int pc )
    101 101
              }
    
    102 102
              debugBelch("\n");
    
    103 103
              break; }
    
    104
    +      case bci_HPC_TICK: {
    
    105
    +         W_ p1, info_wix;
    
    106
    +         p1       = BCO_GET_LARGE_ARG;
    
    107
    +         info_wix = BCO_READ_NEXT_32;
    
    108
    +         debugBelch("HPC_TICK "); printPtr((StgPtr)literals[p1]);
    
    109
    +         debugBelch(" %" FMT_Word "\n", info_wix);
    
    110
    +         break; }
    
    104 111
           case bci_SWIZZLE: {
    
    105 112
              W_     stkoff = BCO_GET_LARGE_ARG;
    
    106 113
              StgInt by     = BCO_GET_LARGE_ARG;
    

  • rts/Hpc.c
    ... ... @@ -270,6 +270,9 @@ hs_hpc_module(char *modName,
    270 270
       HpcModuleInfo *tmpModule;
    
    271 271
       uint32_t i;
    
    272 272
     
    
    273
    +  debugTrace(DEBUG_hpc, "hs_hpc_module(%s, count=%u, hash=%u)\n",
    
    274
    +             modName, modCount, modHashNo);
    
    275
    +
    
    273 276
       if (moduleHash == NULL) {
    
    274 277
           moduleHash = allocStrHashTable();
    
    275 278
       }
    

  • rts/Interpreter.c
    ... ... @@ -1711,7 +1711,7 @@ run_BCO:
    1711 1711
                 &&lbl_bci_TESTEQ_W8 - &&lbl_bci_DEFAULT,
    
    1712 1712
                 &&lbl_bci_PRIMCALL - &&lbl_bci_DEFAULT,
    
    1713 1713
                 &&lbl_bci_BCO_NAME - &&lbl_bci_DEFAULT,
    
    1714
    -            &&lbl_bci_DEFAULT - &&lbl_bci_DEFAULT,
    
    1714
    +            &&lbl_bci_HPC_TICK - &&lbl_bci_DEFAULT,
    
    1715 1715
                 &&lbl_bci_OP_ADD_64 - &&lbl_bci_DEFAULT,
    
    1716 1716
                 &&lbl_bci_OP_SUB_64 - &&lbl_bci_DEFAULT,
    
    1717 1717
                 &&lbl_bci_OP_AND_64 - &&lbl_bci_DEFAULT,
    
    ... ... @@ -2078,6 +2078,18 @@ run_BCO:
    2078 2078
                 NEXT_INSTRUCTION;
    
    2079 2079
             }
    
    2080 2080
     
    
    2081
    +        INSTRUCTION(bci_HPC_TICK): {
    
    2082
    +            W_ arg1_ticks_array, arg2_tick_index;
    
    2083
    +            arg1_ticks_array = BCO_GET_LARGE_ARG;
    
    2084
    +            arg2_tick_index  = BCO_READ_NEXT_32;
    
    2085
    +            IF_DEBUG(hpc,
    
    2086
    +                     debugBelch("\tHPC Tick %lu %lu %lu\n", BCO_LIT(arg1_ticks_array), arg1_ticks_array, arg2_tick_index);
    
    2087
    +                );
    
    2088
    +
    
    2089
    +            ((StgWord64*)BCO_LIT(arg1_ticks_array))[arg2_tick_index]++;
    
    2090
    +            NEXT_INSTRUCTION;
    
    2091
    +        }
    
    2092
    +
    
    2081 2093
             INSTRUCTION(bci_STKCHECK): {
    
    2082 2094
                 // Explicit stack check at the beginning of a function
    
    2083 2095
                 // *only* (stack checks in case alternatives are
    

  • rts/include/rts/Bytecodes.h
    ... ... @@ -118,6 +118,7 @@
    118 118
     #define bci_PRIMCALL                    87
    
    119 119
     
    
    120 120
     #define bci_BCO_NAME                    88
    
    121
    +#define bci_HPC_TICK                    89
    
    121 122
     
    
    122 123
     #define bci_OP_ADD_64                   90
    
    123 124
     #define bci_OP_SUB_64                   91
    

  • testsuite/tests/hpc/ghc_ghci/BytecodeMain.hs
    1
    +module Main where
    
    2
    +
    
    3
    +inc :: Int -> Int
    
    4
    +inc x = x + 1
    
    5
    +
    
    6
    +double :: Int -> Int
    
    7
    +double x = x * 2
    
    8
    +
    
    9
    +main :: IO ()
    
    10
    +main = print (double (inc 1011))

  • testsuite/tests/hpc/ghc_ghci/Makefile
    ... ... @@ -7,3 +7,9 @@ hpc_ghc_ghci:
    7 7
     	'$(TEST_HC)' $(TEST_HC_OPTS) -fhpc -c A.hs
    
    8 8
     	echo b | '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) B.hs
    
    9 9
     
    
    10
    +hpc_ghc_ghci_bytecode:
    
    11
    +	rm -f ./*.tix
    
    12
    +	printf "main\n:quit\n" | '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) -fhpc -fbyte-code-and-object-code -fprefer-byte-code BytecodeMain.hs
    
    13
    +	@[ -f .hpc/Main.mix ] || (echo "ERROR: Expected .hpc/Main.mix file not found"; exit 1)
    
    14
    +	@set -- ./*.tix; [ -f "$$1" ] || (echo "ERROR: Expected .tix file not found"; exit 1); '$(HPC)' report "$$1" Main > hpc-report.txt
    
    15
    +	@grep -F "100% expressions used" hpc-report.txt >/dev/null || (echo "ERROR: Expected full expression coverage in hpc report"; cat hpc-report.txt; exit 1)

  • testsuite/tests/hpc/ghc_ghci/hpc_ghc_ghci_bytecode.stdout
    1
    +2024

  • testsuite/tests/hpc/ghc_ghci/test.T
    ... ... @@ -3,3 +3,8 @@ test('hpc_ghc_ghci',
    3 3
          [extra_files(['A.hs', 'B.hs']),
    
    4 4
           only_ways(['normal']), when(compiler_profiled(), skip), req_interp],
    
    5 5
          run_command, ['$MAKE -s --no-print-directory hpc_ghc_ghci'])
    
    6
    +
    
    7
    +test('hpc_ghc_ghci_bytecode',
    
    8
    +     [extra_files(['BytecodeMain.hs']),
    
    9
    +      only_ways(['normal']), when(compiler_profiled(), skip), req_interp],
    
    10
    +     run_command, ['$MAKE -s --no-print-directory hpc_ghc_ghci_bytecode'])