Hannes Siebenhandl pushed to branch wip/fendor/hpc-bc-support at Glasgow Haskell Compiler / GHC
Commits:
-
6832ae44
by fendor at 2026-04-02T10:04:24+02:00
20 changed files:
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/Serialize.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Driver/CodeOutput.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/HsToCore/Coverage.hs
- compiler/GHC/Iface/Tidy.hs
- compiler/GHC/Linker/ByteCode.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/Types/HpcInfo.hs
- compiler/GHC/Unit/Module/ModGuts.hs
- + libraries/ghci/GHCi/Coverage.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/Run.hs
- libraries/ghci/ghci.cabal.in
- rts/Hpc.c
- rts/Interpreter.c
Changes:
| ... | ... | @@ -71,6 +71,7 @@ import GHC.Float (castFloatToWord32, castDoubleToWord64) |
| 71 | 71 | |
| 72 | 72 | import qualified Data.List as List ( any )
|
| 73 | 73 | import GHC.Exts
|
| 74 | +import qualified GHC.Data.Strict as Strict
|
|
| 74 | 75 | |
| 75 | 76 | |
| 76 | 77 | -- -----------------------------------------------------------------------------
|
| ... | ... | @@ -110,8 +111,9 @@ assembleBCOs |
| 110 | 111 | -> [(Name, ByteString)]
|
| 111 | 112 | -> Maybe InternalModBreaks
|
| 112 | 113 | -> [SptEntry]
|
| 114 | + -> Strict.Maybe ByteCodeHpcInfo
|
|
| 113 | 115 | -> IO CompiledByteCode
|
| 114 | -assembleBCOs profile proto_bcos tycons top_strs modbreaks spt_entries = do
|
|
| 116 | +assembleBCOs profile proto_bcos tycons top_strs modbreaks spt_entries use_hpc = do
|
|
| 115 | 117 | -- TODO: the profile should be bundled with the interpreter: the rts ways are
|
| 116 | 118 | -- fixed for an interpreter
|
| 117 | 119 | let itbls = mkITbls profile tycons
|
| ... | ... | @@ -122,6 +124,7 @@ assembleBCOs profile proto_bcos tycons top_strs modbreaks spt_entries = do |
| 122 | 124 | , bc_strs = top_strs
|
| 123 | 125 | , bc_breaks = modbreaks
|
| 124 | 126 | , bc_spt_entries = spt_entries
|
| 127 | + , bc_hpc_info = use_hpc
|
|
| 125 | 128 | }
|
| 126 | 129 | |
| 127 | 130 | -- Note [Allocating string literals]
|
| ... | ... | @@ -295,13 +295,15 @@ instance Binary CompiledByteCode where |
| 295 | 295 | replicateM bc_strs_len $ (,) <$> getViaBinName bh <*> get bh
|
| 296 | 296 | bc_breaks <- get bh
|
| 297 | 297 | bc_spt_entries <- get bh
|
| 298 | + bc_hpc_info <- get bh
|
|
| 298 | 299 | return $
|
| 299 | 300 | CompiledByteCode
|
| 300 | 301 | { bc_bcos,
|
| 301 | 302 | bc_itbls,
|
| 302 | 303 | bc_strs,
|
| 303 | 304 | bc_breaks,
|
| 304 | - bc_spt_entries
|
|
| 305 | + bc_spt_entries,
|
|
| 306 | + bc_hpc_info
|
|
| 305 | 307 | }
|
| 306 | 308 | |
| 307 | 309 | put_ bh CompiledByteCode {..} = do
|
| ... | ... | @@ -314,6 +316,26 @@ instance Binary CompiledByteCode where |
| 314 | 316 | for_ bc_strs $ \(nm, str) -> putViaBinName bh nm *> put_ bh str
|
| 315 | 317 | put_ bh bc_breaks
|
| 316 | 318 | put_ bh bc_spt_entries
|
| 319 | + put_ bh bc_hpc_info
|
|
| 320 | + |
|
| 321 | +instance Binary ByteCodeHpcInfo where
|
|
| 322 | + put_ bh ByteCodeHpcInfo{bchi_tick_count,bchi_hash,bchi_tickboxes,bchi_module_name} = do
|
|
| 323 | + put_ bh bchi_tick_count
|
|
| 324 | + put_ bh bchi_hash
|
|
| 325 | + put_ bh bchi_tickboxes
|
|
| 326 | + put_ bh bchi_module_name
|
|
| 327 | + |
|
| 328 | + get bh = do
|
|
| 329 | + bchi_tick_count <- get bh
|
|
| 330 | + bchi_hash <- get bh
|
|
| 331 | + bchi_tickboxes <- get bh
|
|
| 332 | + bchi_module_name <- get bh
|
|
| 333 | + pure ByteCodeHpcInfo
|
|
| 334 | + { bchi_tick_count
|
|
| 335 | + , bchi_hash
|
|
| 336 | + , bchi_tickboxes
|
|
| 337 | + , bchi_module_name
|
|
| 338 | + }
|
|
| 317 | 339 | |
| 318 | 340 | instance Binary UnlinkedBCO where
|
| 319 | 341 | get bh =
|
| ... | ... | @@ -22,6 +22,9 @@ module GHC.ByteCode.Types |
| 22 | 22 | -- * Mod Breaks
|
| 23 | 23 | , ModBreaks (..), BreakpointId(..), BreakTickIndex
|
| 24 | 24 | |
| 25 | + -- * Hpc Info
|
|
| 26 | + , ByteCodeHpcInfo(..)
|
|
| 27 | + |
|
| 25 | 28 | -- * Internal Mod Breaks
|
| 26 | 29 | , InternalModBreaks(..), CgBreakInfo(..), seqInternalModBreaks
|
| 27 | 30 | -- ** Internal breakpoint identifier
|
| ... | ... | @@ -32,6 +35,7 @@ import GHC.Prelude |
| 32 | 35 | |
| 33 | 36 | import GHC.Data.FastString
|
| 34 | 37 | import GHC.Data.FlatBag
|
| 38 | +import qualified GHC.Data.Strict as Strict
|
|
| 35 | 39 | import GHC.Types.Name
|
| 36 | 40 | import GHC.Types.Name.Env
|
| 37 | 41 | import GHC.Utils.Binary
|
| ... | ... | @@ -76,6 +80,14 @@ data CompiledByteCode = CompiledByteCode |
| 76 | 80 | -- ^ Static pointer table entries which should be loaded along with the
|
| 77 | 81 | -- BCOs. See Note [Grand plan for static forms] in
|
| 78 | 82 | -- "GHC.Iface.Tidy.StaticPtrTable".
|
| 83 | + , bc_hpc_info :: !(Strict.Maybe ByteCodeHpcInfo) -- ^ TODO: @fendor
|
|
| 84 | + }
|
|
| 85 | + |
|
| 86 | +data ByteCodeHpcInfo = ByteCodeHpcInfo
|
|
| 87 | + { bchi_tick_count :: {-# UNPACK #-} !Int
|
|
| 88 | + , bchi_hash :: {-# UNPACK #-} !Int
|
|
| 89 | + , bchi_tickboxes :: !ByteString
|
|
| 90 | + , bchi_module_name :: !ByteString
|
|
| 79 | 91 | }
|
| 80 | 92 | |
| 81 | 93 | -- | A libffi ffi_cif function prototype.
|
| ... | ... | @@ -278,13 +278,12 @@ outputForeignStubs logger tmpfs dflags unit_state mod location stubs |
| 278 | 278 | |
| 279 | 279 | ForeignStubs (CHeader h_code) cstub -> do
|
| 280 | 280 | let
|
| 281 | - stub_c_output_d = pprCode (getCStub cstub $$ pprCStubInitFiniDecls platform cstub)
|
|
| 281 | + stub_c_output_d = pprCode (getCStub cstub)
|
|
| 282 | 282 | stub_c_output_w = showSDoc dflags stub_c_output_d
|
| 283 | 283 | |
| 284 | 284 | -- Header file protos for "foreign export"ed functions.
|
| 285 | 285 | stub_h_output_d = pprCode h_code
|
| 286 | 286 | stub_h_output_w = showSDoc dflags stub_h_output_d
|
| 287 | - platform = targetPlatform dflags
|
|
| 288 | 287 | |
| 289 | 288 | putDumpFileMaybe logger Opt_D_dump_foreign
|
| 290 | 289 | "Foreign export header file"
|
| ... | ... | @@ -344,29 +343,6 @@ outputForeignStubs logger tmpfs dflags unit_state mod location stubs |
| 344 | 343 | cplusplus_hdr = "#if defined(__cplusplus)\nextern \"C\" {\n#endif\n"
|
| 345 | 344 | cplusplus_ftr = "#if defined(__cplusplus)\n}\n#endif\n"
|
| 346 | 345 | |
| 347 | -pprCStubInitFiniDecls :: Platform -> CStub -> SDoc
|
|
| 348 | -pprCStubInitFiniDecls platform cstub =
|
|
| 349 | - vcat (zipWith (pprInitOrFiniDecl "ini" ".init_array") [0 :: Int ..] (getInitializers cstub))
|
|
| 350 | - $$ vcat (zipWith (pprInitOrFiniDecl "fini" ".fini_array") [0 :: Int ..] (getFinalizers cstub))
|
|
| 351 | - where
|
|
| 352 | - pprInitOrFiniDecl :: String -> String -> Int -> CLabel -> SDoc
|
|
| 353 | - pprInitOrFiniDecl suf section_name n lbl =
|
|
| 354 | - vcat
|
|
| 355 | - [ hsep [text "extern void", pprCLabel platform lbl, text "(void);"]
|
|
| 356 | - , hsep [ text "static void (*"
|
|
| 357 | - <> text "__ghc_" <> text suf <> text "_"
|
|
| 358 | - <> int n
|
|
| 359 | - <> text ")(void)"
|
|
| 360 | - , text "__attribute__((used, section("
|
|
| 361 | - <> doubleQuotes (text section_name)
|
|
| 362 | - <> text ")))"
|
|
| 363 | - , equals
|
|
| 364 | - , pprCLabel platform lbl
|
|
| 365 | - <> semi
|
|
| 366 | - ]
|
|
| 367 | - ]
|
|
| 368 | - |
|
| 369 | - |
|
| 370 | 346 | -- It is more than likely that the stubs file will
|
| 371 | 347 | -- turn out to be empty, in which case no file should be created.
|
| 372 | 348 | outputForeignStubs_help :: FilePath -> String -> String -> String -> IO Bool
|
| ... | ... | @@ -151,6 +151,7 @@ import GHC.Hs.Dump |
| 151 | 151 | import GHC.Hs.Stats ( ppSourceStats )
|
| 152 | 152 | |
| 153 | 153 | import GHC.HsToCore
|
| 154 | +import GHC.HsToCore.Coverage ( hpcTickBoxes )
|
|
| 154 | 155 | |
| 155 | 156 | import GHC.StgToByteCode ( byteCodeGen )
|
| 156 | 157 | import GHC.StgToJS ( stgToJS )
|
| ... | ... | @@ -237,6 +238,7 @@ import GHC.Types.Var.Set |
| 237 | 238 | import GHC.Types.Error
|
| 238 | 239 | import GHC.Types.Fixity.Env
|
| 239 | 240 | import GHC.Types.CostCentre
|
| 241 | +import GHC.Types.HpcInfo (HpcInfo (..))
|
|
| 240 | 242 | import GHC.Types.IPE
|
| 241 | 243 | import GHC.Types.SourceFile
|
| 242 | 244 | import GHC.Types.SrcLoc
|
| ... | ... | @@ -299,6 +301,9 @@ import qualified GHC.Unit.Home.Graph as HUG |
| 299 | 301 | import GHC.Unit.Home.PackageTable
|
| 300 | 302 | |
| 301 | 303 | import GHC.ByteCode.Serialize
|
| 304 | +import GHC.Driver.Ppr (showSDoc)
|
|
| 305 | +import qualified Data.ByteString.Char8 as BS8
|
|
| 306 | +import qualified GHC.Data.Strict as Strict
|
|
| 302 | 307 | |
| 303 | 308 | {- **********************************************************************
|
| 304 | 309 | %* *
|
| ... | ... | @@ -1186,7 +1191,7 @@ compileWholeCoreBindings hsc_env type_env wcb = do |
| 1186 | 1191 | gen_bytecode core_binds stubs foreign_files = do
|
| 1187 | 1192 | let cgi_guts = CgInteractiveGuts wcb_module core_binds
|
| 1188 | 1193 | (typeEnvTyCons type_env) stubs foreign_files
|
| 1189 | - Nothing []
|
|
| 1194 | + Nothing [] NoHpcInfo
|
|
| 1190 | 1195 | trace_if logger (text "Generating ByteCode for" <+> ppr wcb_module)
|
| 1191 | 1196 | mkModuleByteCode hsc_env wcb_module wcb_mod_location cgi_guts
|
| 1192 | 1197 | |
| ... | ... | @@ -2136,11 +2141,12 @@ data CgInteractiveGuts = CgInteractiveGuts { cgi_module :: Module |
| 2136 | 2141 | , cgi_foreign_files :: [(ForeignSrcLang, FilePath)]
|
| 2137 | 2142 | , cgi_modBreaks :: Maybe ModBreaks
|
| 2138 | 2143 | , cgi_spt_entries :: [SptEntry]
|
| 2144 | + , cgi_hpc_info :: HpcInfo
|
|
| 2139 | 2145 | }
|
| 2140 | 2146 | |
| 2141 | 2147 | mkCgInteractiveGuts :: CgGuts -> CgInteractiveGuts
|
| 2142 | -mkCgInteractiveGuts CgGuts{cg_module, cg_binds, cg_tycons, cg_foreign, cg_foreign_files, cg_modBreaks, cg_spt_entries}
|
|
| 2143 | - = CgInteractiveGuts cg_module cg_binds cg_tycons cg_foreign cg_foreign_files cg_modBreaks cg_spt_entries
|
|
| 2148 | +mkCgInteractiveGuts CgGuts{cg_module, cg_binds, cg_tycons, cg_foreign, cg_foreign_files, cg_modBreaks, cg_spt_entries, cg_hpc_info}
|
|
| 2149 | + = CgInteractiveGuts cg_module cg_binds cg_tycons cg_foreign cg_foreign_files cg_modBreaks cg_spt_entries cg_hpc_info
|
|
| 2144 | 2150 | |
| 2145 | 2151 | hscInteractive :: HscEnv
|
| 2146 | 2152 | -> CgInteractiveGuts
|
| ... | ... | @@ -2163,13 +2169,15 @@ hscGenerateByteCode :: HscEnv -> CgInteractiveGuts -> ModLocation -> IO Compiled |
| 2163 | 2169 | hscGenerateByteCode hsc_env cgguts location = do
|
| 2164 | 2170 | let dflags = hsc_dflags hsc_env
|
| 2165 | 2171 | let logger = hsc_logger hsc_env
|
| 2172 | + let platform = targetPlatform dflags
|
|
| 2166 | 2173 | let CgInteractiveGuts{ -- This is the last use of the ModGuts in a compilation.
|
| 2167 | 2174 | -- From now on, we just use the bits we need.
|
| 2168 | 2175 | cgi_module = this_mod,
|
| 2169 | 2176 | cgi_binds = core_binds,
|
| 2170 | 2177 | cgi_tycons = tycons,
|
| 2171 | 2178 | cgi_modBreaks = mod_breaks,
|
| 2172 | - cgi_spt_entries = spt_entries } = cgguts
|
|
| 2179 | + cgi_spt_entries = spt_entries,
|
|
| 2180 | + cgi_hpc_info = hpc_info } = cgguts
|
|
| 2173 | 2181 | |
| 2174 | 2182 | -------------------
|
| 2175 | 2183 | -- ADD IMPLICIT BINDINGS
|
| ... | ... | @@ -2194,8 +2202,22 @@ hscGenerateByteCode hsc_env cgguts location = do |
| 2194 | 2202 | |
| 2195 | 2203 | let (stg_binds,_stg_deps) = unzip stg_binds_with_deps
|
| 2196 | 2204 | |
| 2205 | + -------------------
|
|
| 2206 | + -- Setup HPC info
|
|
| 2207 | + let
|
|
| 2208 | + -- Strict to not retain a reference to the 'CgInteractiveGuts' of 'cgguts'
|
|
| 2209 | + !bytecodeHpcInfo = case hpc_info of
|
|
| 2210 | + NoHpcInfo -> Strict.Nothing
|
|
| 2211 | + HpcInfo{hpcInfoTickCount, hpcInfoHash} ->
|
|
| 2212 | + Strict.Just ByteCodeHpcInfo
|
|
| 2213 | + { bchi_tick_count = hpcInfoTickCount
|
|
| 2214 | + , bchi_hash = hpcInfoHash
|
|
| 2215 | + , bchi_tickboxes = BS8.pack . (++ "\0") . showSDoc dflags $ hpcTickBoxes platform this_mod
|
|
| 2216 | + , bchi_module_name = BS8.pack . (++ "\0") . showSDoc dflags $ ppr this_mod
|
|
| 2217 | + }
|
|
| 2218 | + |
|
| 2197 | 2219 | ----------------- Generate byte code ------------------
|
| 2198 | - byteCodeGen hsc_env this_mod stg_binds tycons mod_breaks spt_entries
|
|
| 2220 | + byteCodeGen hsc_env this_mod stg_binds tycons mod_breaks spt_entries bytecodeHpcInfo
|
|
| 2199 | 2221 | |
| 2200 | 2222 | -- | Generate a byte code object linkable and write it to a file if `-fwrite-byte-code` is enabled.
|
| 2201 | 2223 | generateAndWriteByteCode :: HscEnv -> CgInteractiveGuts -> ModLocation -> IO ModuleByteCode
|
| ... | ... | @@ -2844,6 +2866,7 @@ hscCompileCoreExpr' hsc_env srcspan ds_expr = do |
| 2844 | 2866 | []
|
| 2845 | 2867 | Nothing -- modbreaks
|
| 2846 | 2868 | [] -- spt entries
|
| 2869 | + Strict.Nothing -- no hpc info
|
|
| 2847 | 2870 | |
| 2848 | 2871 | {- load it -}
|
| 2849 | 2872 | bco_time <- getCurrentTime
|
| ... | ... | @@ -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) |
| ... | ... | @@ -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
|
| ... | ... | @@ -67,4 +67,4 @@ mkInterpreterLib hsc_env files = |
| 67 | 67 | return $ Just (InterpreterSharedObject foreign_stub_lib_path foreign_stub_lib_dir foreign_stub_lib_name)
|
| 68 | 68 | Nothing -> pure Nothing
|
| 69 | 69 | False -> do
|
| 70 | - pure $ Just (InterpreterStaticObjects files) |
|
| \ No newline at end of file | ||
| 70 | + pure $ Just (InterpreterStaticObjects files) |
| ... | ... | @@ -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 | -- ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -988,10 +992,9 @@ dynLinkBCOs interp pls keep_spec bcos = |
| 988 | 992 | let (bcos_loaded', new_bcos) = rmDupLinkables (bcos_loaded pls) bcos
|
| 989 | 993 | pls1 = pls { bcos_loaded = bcos_loaded' }
|
| 990 | 994 | |
| 991 | - cbcs :: [CompiledByteCode]
|
|
| 992 | - cbcs = concatMap linkableBCOs new_bcos
|
|
| 995 | + mbcs = concatMap linkableBCOs new_bcos
|
|
| 993 | 996 | in do
|
| 994 | - bco_state <- dynLinkCompiledByteCode interp (pkgs_loaded pls) (bco_loader_state pls) traverseHomePackageBytecodeState keep_spec cbcs
|
|
| 997 | + bco_state <- dynLinkCompiledByteCode interp (pkgs_loaded pls) (bco_loader_state pls) traverseHomePackageBytecodeState keep_spec mbcs
|
|
| 995 | 998 | return $! pls1 { bco_loader_state = bco_state }
|
| 996 | 999 | |
| 997 | 1000 | dynLinkCompiledByteCode :: Interp
|
| ... | ... | @@ -1001,22 +1004,22 @@ dynLinkCompiledByteCode :: Interp |
| 1001 | 1004 | -> KeepModuleLinkableDefinitions
|
| 1002 | 1005 | -> [CompiledByteCode]
|
| 1003 | 1006 | -> IO BytecodeLoaderState
|
| 1004 | -dynLinkCompiledByteCode interp pkgs_loaded whole_bytecode_state traverse_bytecode_state keep_spec cbcs = do
|
|
| 1007 | +dynLinkCompiledByteCode interp pkgs_loaded whole_bytecode_state traverse_bytecode_state keep_spec mbcs = do
|
|
| 1005 | 1008 | st1 <- traverse_bytecode_state whole_bytecode_state $ \bytecode_state -> do
|
| 1006 | 1009 | let
|
| 1007 | 1010 | le1 = bco_linker_env bytecode_state
|
| 1008 | 1011 | lb1 = bco_linked_breaks bytecode_state
|
| 1009 | - ie2 <- linkITbls interp (itbl_env le1) (concatMap bc_itbls cbcs)
|
|
| 1010 | - ae2 <- foldlM (\env cbc -> allocateTopStrings interp (bc_strs cbc) env) (addr_env le1) cbcs
|
|
| 1011 | - be2 <- allocateBreakArrays interp (breakarray_env lb1) (catMaybes $ map bc_breaks cbcs)
|
|
| 1012 | - ce2 <- allocateCCS interp (ccs_env lb1) (catMaybes $ map bc_breaks cbcs)
|
|
| 1012 | + ie2 <- linkITbls interp (itbl_env le1) (concatMap bc_itbls mbcs)
|
|
| 1013 | + ae2 <- foldlM (\env cbc -> allocateTopStrings interp (bc_strs cbc) env) (addr_env le1) mbcs
|
|
| 1014 | + be2 <- allocateBreakArrays interp (breakarray_env lb1) (catMaybes $ map bc_breaks mbcs)
|
|
| 1015 | + ce2 <- allocateCCS interp (ccs_env lb1) (catMaybes $ map bc_breaks mbcs)
|
|
| 1013 | 1016 | let le2 = le1 { itbl_env = ie2, addr_env = ae2 }
|
| 1014 | 1017 | let lb2 = lb1 { breakarray_env = be2, ccs_env = ce2 }
|
| 1015 | 1018 | return $! bytecode_state { bco_linker_env = le2, bco_linked_breaks = lb2 }
|
| 1016 | 1019 | |
| 1017 | 1020 | -- NB: Important to pass the whole bytecode loader state to linkSomeBCOs so that you can find Names in local
|
| 1018 | 1021 | -- and external packages.
|
| 1019 | - names_and_refs <- linkSomeBCOs interp pkgs_loaded st1 cbcs
|
|
| 1022 | + names_and_refs <- linkSomeBCOs interp pkgs_loaded st1 mbcs
|
|
| 1020 | 1023 | |
| 1021 | 1024 | -- We only want to add the external ones to the ClosureEnv
|
| 1022 | 1025 | let (to_add, to_drop) = partition (keepDefinitions keep_spec . fst) names_and_refs
|
| ... | ... | @@ -1029,7 +1032,9 @@ dynLinkCompiledByteCode interp pkgs_loaded whole_bytecode_state traverse_bytecod |
| 1029 | 1032 | traverse_bytecode_state st1 $ \bytecode_state -> do
|
| 1030 | 1033 | let ce2 = extendClosureEnv (closure_env (bco_linker_env bytecode_state)) new_binds
|
| 1031 | 1034 | -- Add SPT entries
|
| 1032 | - mapM_ (linkSptEntry interp ce2) (concatMap bc_spt_entries cbcs)
|
|
| 1035 | + mapM_ (linkSptEntry interp ce2) (concatMap bc_spt_entries mbcs)
|
|
| 1036 | + -- Load HPC modules
|
|
| 1037 | + mapM_ (linkHpcEntry interp . bc_hpc_info) mbcs
|
|
| 1033 | 1038 | return $! bytecode_state { bco_linker_env = (bco_linker_env bytecode_state) { closure_env = ce2 } }
|
| 1034 | 1039 | |
| 1035 | 1040 | -- | Register SPT entries for this module in the interpreter
|
| ... | ... | @@ -1042,8 +1047,14 @@ linkSptEntry interp ce (SptEntry name fpr) = do |
| 1042 | 1047 | Nothing -> pprPanic "linkSptEntry" (ppr name)
|
| 1043 | 1048 | Just (_, hval) -> addSptEntry interp fpr hval
|
| 1044 | 1049 | |
| 1045 | - |
|
| 1046 | - |
|
| 1050 | +linkHpcEntry :: Interp -> Strict.Maybe ByteCodeHpcInfo -> IO ()
|
|
| 1051 | +linkHpcEntry _interp Strict.Nothing = pure ()
|
|
| 1052 | +linkHpcEntry interp (Strict.Just info) = do
|
|
| 1053 | + addHpcModule interp
|
|
| 1054 | + (bchi_module_name info)
|
|
| 1055 | + (bchi_tick_count info)
|
|
| 1056 | + (bchi_hash info)
|
|
| 1057 | + (bchi_tickboxes info)
|
|
| 1047 | 1058 | |
| 1048 | 1059 | -- Link a bunch of BCOs and return references to their values
|
| 1049 | 1060 | linkSomeBCOs :: Interp
|
| ... | ... | @@ -204,36 +204,37 @@ data BytecodeLoaderState = BytecodeLoaderState |
| 204 | 204 | -- ^ Information about bytecode objects from the home package we have loaded into the interpreter.
|
| 205 | 205 | , externalPackage_loaded :: BytecodeState
|
| 206 | 206 | -- ^ Information about bytecode objects from external packages we have loaded into the interpreter.
|
| 207 | + , hpcInitialised :: !Bool
|
|
| 207 | 208 | }
|
| 208 | 209 | |
| 209 | 210 | |
| 210 | 211 | -- | Find a name loaded from bytecode
|
| 211 | 212 | lookupNameBytecodeState :: BytecodeLoaderState -> Name -> Maybe (Name, ForeignHValue)
|
| 212 | -lookupNameBytecodeState (BytecodeLoaderState home_package external_package) name = do
|
|
| 213 | +lookupNameBytecodeState (BytecodeLoaderState home_package external_package _) name = do
|
|
| 213 | 214 | lookupNameEnv (closure_env (bco_linker_env home_package)) name
|
| 214 | 215 | <|> lookupNameEnv (closure_env (bco_linker_env external_package)) name
|
| 215 | 216 | |
| 216 | 217 | -- | Look up a break array in the bytecode loader state.
|
| 217 | 218 | lookupBreakArrayBytecodeState :: BytecodeLoaderState -> Module -> Maybe (ForeignRef BreakArray)
|
| 218 | -lookupBreakArrayBytecodeState (BytecodeLoaderState home_package external_package) break_mod = do
|
|
| 219 | +lookupBreakArrayBytecodeState (BytecodeLoaderState home_package external_package _) break_mod = do
|
|
| 219 | 220 | lookupModuleEnv (breakarray_env (bco_linked_breaks home_package)) break_mod
|
| 220 | 221 | <|> lookupModuleEnv (breakarray_env (bco_linked_breaks external_package)) break_mod
|
| 221 | 222 | |
| 222 | 223 | -- | Look up an info table in the bytecode loader state.
|
| 223 | 224 | lookupInfoTableBytecodeState :: BytecodeLoaderState -> Name -> Maybe (Name, ItblPtr)
|
| 224 | -lookupInfoTableBytecodeState (BytecodeLoaderState home_package external_package) info_mod = do
|
|
| 225 | +lookupInfoTableBytecodeState (BytecodeLoaderState home_package external_package _) info_mod = do
|
|
| 225 | 226 | lookupNameEnv (itbl_env (bco_linker_env home_package)) info_mod
|
| 226 | 227 | <|> lookupNameEnv (itbl_env (bco_linker_env external_package)) info_mod
|
| 227 | 228 | |
| 228 | 229 | -- | Look up an address in the bytecode loader state.
|
| 229 | 230 | lookupAddressBytecodeState :: BytecodeLoaderState -> Name -> Maybe (Name, AddrPtr)
|
| 230 | -lookupAddressBytecodeState (BytecodeLoaderState home_package external_package) addr_mod = do
|
|
| 231 | +lookupAddressBytecodeState (BytecodeLoaderState home_package external_package _) addr_mod = do
|
|
| 231 | 232 | lookupNameEnv (addr_env (bco_linker_env home_package)) addr_mod
|
| 232 | 233 | <|> lookupNameEnv (addr_env (bco_linker_env external_package)) addr_mod
|
| 233 | 234 | |
| 234 | 235 | -- | Look up a cost centre stack in the bytecode loader state.
|
| 235 | 236 | lookupCCSBytecodeState :: BytecodeLoaderState -> Module -> Maybe (Array BreakTickIndex (RemotePtr CostCentre))
|
| 236 | -lookupCCSBytecodeState (BytecodeLoaderState home_package external_package) ccs_mod = do
|
|
| 237 | +lookupCCSBytecodeState (BytecodeLoaderState home_package external_package _) ccs_mod = do
|
|
| 237 | 238 | lookupModuleEnv (ccs_env (bco_linked_breaks home_package)) ccs_mod
|
| 238 | 239 | <|> lookupModuleEnv (ccs_env (bco_linked_breaks external_package)) ccs_mod
|
| 239 | 240 | |
| ... | ... | @@ -241,6 +242,7 @@ emptyBytecodeLoaderState :: BytecodeLoaderState |
| 241 | 242 | emptyBytecodeLoaderState = BytecodeLoaderState
|
| 242 | 243 | { homePackage_loaded = emptyBytecodeState
|
| 243 | 244 | , externalPackage_loaded = emptyBytecodeState
|
| 245 | + , hpcInitialised = False
|
|
| 244 | 246 | }
|
| 245 | 247 | |
| 246 | 248 | emptyBytecodeState :: BytecodeState
|
| ... | ... | @@ -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 -> ByteString -> Int -> Int -> ByteString -> 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)
|
| ... | ... | @@ -74,7 +74,6 @@ import Data.List ( genericReplicate, intersperse |
| 74 | 74 | import Foreign hiding (shiftL, shiftR)
|
| 75 | 75 | import Control.Monad
|
| 76 | 76 | import Data.Char
|
| 77 | -import Data.Word
|
|
| 78 | 77 | |
| 79 | 78 | import GHC.Unit.Module
|
| 80 | 79 | |
| ... | ... | @@ -98,6 +97,7 @@ import Control.Monad.IO.Class |
| 98 | 97 | import Control.Monad.Trans.Reader (ReaderT(..))
|
| 99 | 98 | import Control.Monad.Trans.State (StateT(..))
|
| 100 | 99 | import Data.Bifunctor (Bifunctor(..))
|
| 100 | +import qualified GHC.Data.Strict as Strict
|
|
| 101 | 101 | |
| 102 | 102 | -- -----------------------------------------------------------------------------
|
| 103 | 103 | -- Generating byte code for a complete module
|
| ... | ... | @@ -108,8 +108,9 @@ byteCodeGen :: HscEnv |
| 108 | 108 | -> [TyCon]
|
| 109 | 109 | -> Maybe ModBreaks
|
| 110 | 110 | -> [SptEntry]
|
| 111 | + -> Strict.Maybe ByteCodeHpcInfo
|
|
| 111 | 112 | -> IO CompiledByteCode
|
| 112 | -byteCodeGen hsc_env this_mod binds tycs mb_modBreaks spt_entries
|
|
| 113 | +byteCodeGen hsc_env this_mod binds tycs mb_modBreaks spt_entries hpc_info
|
|
| 113 | 114 | = withTiming logger
|
| 114 | 115 | (text "GHC.StgToByteCode"<+>brackets (ppr this_mod))
|
| 115 | 116 | (const ()) $ do
|
| ... | ... | @@ -135,7 +136,7 @@ byteCodeGen hsc_env this_mod binds tycs mb_modBreaks spt_entries |
| 135 | 136 | let mod_breaks = case mb_modBreaks of
|
| 136 | 137 | Nothing -> Nothing
|
| 137 | 138 | Just mb -> Just $ mkInternalModBreaks this_mod breakInfo mb
|
| 138 | - cbc <- assembleBCOs profile proto_bcos tycs strings mod_breaks spt_entries
|
|
| 139 | + cbc <- assembleBCOs profile proto_bcos tycs strings mod_breaks spt_entries hpc_info
|
|
| 139 | 140 | |
| 140 | 141 | -- Squash space leaks in the CompiledByteCode. This is really
|
| 141 | 142 | -- important, because when loading a set of modules into GHCi
|
| ... | ... | @@ -18,4 +18,3 @@ data HpcInfo |
| 18 | 18 | |
| 19 | 19 | emptyHpcInfo :: HpcInfo
|
| 20 | 20 | emptyHpcInfo = NoHpcInfo |
| 21 | - |
| ... | ... | @@ -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 | } |
| 1 | +{-# LANGUAGE TupleSections #-}
|
|
| 2 | +{-# LANGUAGE ForeignFunctionInterface #-}
|
|
| 3 | +{-# LANGUAGE LambdaCase #-}
|
|
| 4 | + |
|
| 5 | +module GHCi.Coverage ( hpcAddModule ) where
|
|
| 6 | + |
|
| 7 | +import Prelude -- See note [Why do we import Prelude here?]
|
|
| 8 | +import Data.Word
|
|
| 9 | +import Foreign
|
|
| 10 | +import GHC.Fingerprint
|
|
| 11 | +import GHCi.RemoteTypes
|
|
| 12 | +import Data.ByteString
|
|
| 13 | +import GHC.Foreign (CString)
|
|
| 14 | +import qualified Data.ByteString.Unsafe as B
|
|
| 15 | +import qualified Data.ByteString.Char8 as BS8
|
|
| 16 | +import GHCi.ObjLink (lookupSymbol)
|
|
| 17 | +import Debug.Trace
|
|
| 18 | + |
|
| 19 | +hpcAddModule :: ByteString -> Int -> Int -> ByteString -> IO ()
|
|
| 20 | +hpcAddModule modl ticks hash tickboxes = do
|
|
| 21 | + B.unsafeUseAsCString modl $ \modlLiteral -> do
|
|
| 22 | + lookupSymbol (BS8.unpack tickboxes) >>= \ case
|
|
| 23 | + Nothing -> pure ()
|
|
| 24 | + Just tickBoxRef -> do
|
|
| 25 | + hpc_register_module modlLiteral (fromIntegral ticks) (fromIntegral hash) (castPtr tickBoxRef)
|
|
| 26 | + hpc_startup
|
|
| 27 | + |
|
| 28 | +foreign import ccall "hs_hpc_module"
|
|
| 29 | + hpc_register_module :: CString -> Word32 -> Word32 -> Ptr Word64 -> IO ()
|
|
| 30 | + |
|
| 31 | +foreign import ccall "startupHpc"
|
|
| 32 | + hpc_startup :: IO () |
| ... | ... | @@ -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 :: ByteString -> Int -> Int -> ByteString -> Message ()
|
|
| 114 | 116 | |
| 115 | 117 | -- | Malloc some data and return a 'RemotePtr' to it
|
| 116 | 118 | MallocData :: ByteString -> Message (RemotePtr ())
|
| ... | ... | @@ -602,6 +604,7 @@ getMessage = do |
| 602 | 604 | 38 -> Msg <$> (ResumeSeq <$> get)
|
| 603 | 605 | 39 -> Msg <$> (LookupSymbolInDLL <$> get <*> get)
|
| 604 | 606 | 40 -> Msg <$> (WhereFrom <$> get)
|
| 607 | + 41 -> Msg <$> (AddHpcModule <$> get <*> get <*> get <*> get)
|
|
| 605 | 608 | _ -> error $ "Unknown Message code " ++ (show b)
|
| 606 | 609 | |
| 607 | 610 | putMessage :: Message a -> Put
|
| ... | ... | @@ -648,6 +651,7 @@ putMessage m = case m of |
| 648 | 651 | ResumeSeq a -> putWord8 38 >> put a
|
| 649 | 652 | LookupSymbolInDLL dll str -> putWord8 39 >> put dll >> put str
|
| 650 | 653 | WhereFrom a -> putWord8 40 >> put a
|
| 654 | + AddHpcModule lbl ticks hash tickboxes -> putWord8 41 >> put lbl >> put ticks >> put hash >> put tickboxes
|
|
| 651 | 655 | |
| 652 | 656 | {-
|
| 653 | 657 | Note [Parallelize CreateBCOs serialization]
|
| ... | ... | @@ -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
|
| ... | ... | @@ -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
|
| ... | ... | @@ -323,8 +323,6 @@ hs_hpc_module(char *modName, |
| 323 | 323 | }
|
| 324 | 324 | tmpModule->from_file = false;
|
| 325 | 325 | }
|
| 326 | - |
|
| 327 | - startupHpc();
|
|
| 328 | 326 | }
|
| 329 | 327 | |
| 330 | 328 | static void
|
| ... | ... | @@ -1740,7 +1740,6 @@ run_BCO: |
| 1740 | 1740 | &&lbl_bci_PRIMCALL - &&lbl_bci_DEFAULT,
|
| 1741 | 1741 | &&lbl_bci_BCO_NAME - &&lbl_bci_DEFAULT,
|
| 1742 | 1742 | &&lbl_bci_HPC_TICK - &&lbl_bci_DEFAULT,
|
| 1743 | - &&lbl_bci_DEFAULT - &&lbl_bci_DEFAULT,
|
|
| 1744 | 1743 | &&lbl_bci_OP_ADD_64 - &&lbl_bci_DEFAULT,
|
| 1745 | 1744 | &&lbl_bci_OP_SUB_64 - &&lbl_bci_DEFAULT,
|
| 1746 | 1745 | &&lbl_bci_OP_AND_64 - &&lbl_bci_DEFAULT,
|
| ... | ... | @@ -2111,6 +2110,9 @@ run_BCO: |
| 2111 | 2110 | W_ arg1_ticks_array, arg2_tick_index;
|
| 2112 | 2111 | arg1_ticks_array = BCO_GET_LARGE_ARG;
|
| 2113 | 2112 | arg2_tick_index = BCO_READ_NEXT_32;
|
| 2113 | + IF_DEBUG(hpc,
|
|
| 2114 | + debugBelch("\tHPC Tick %lu %lu %lu\n", BCO_LIT(arg1_ticks_array), arg1_ticks_array, arg2_tick_index);
|
|
| 2115 | + );
|
|
| 2114 | 2116 | |
| 2115 | 2117 | ((StgWord64*)BCO_LIT(arg1_ticks_array))[arg2_tick_index]++;
|
| 2116 | 2118 | NEXT_INSTRUCTION;
|