diff options
author | Ben Gamari <ben@smart-cactus.org> | 2019-12-27 12:38:27 -0500 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2019-12-27 15:00:54 -0500 |
commit | 0398c938ff3c9ca5c125d9f414d4561bbcb55a36 (patch) | |
tree | b8539df9d10b382a6efdbbd1510a9141ce884c2e | |
parent | 334290b6681796dd141c964b88c541da13ce03c7 (diff) | |
download | haskell-wip/local-symbols.tar.gz |
codeGen: Produce local symbols for module-internal functionswip/local-symbols
It turns out that some important native debugging/profiling tools (e.g.
perf) rely only on symbol tables for function name resolution (as
opposed to using DWARF DIEs). However, previously GHC would emit
temporary symbols (e.g. `.La42b`) to identify module-internal
entities. Such symbols are dropped during linking and therefore not
visible to runtime tools (in addition to having rather un-helpful unique
names). For instance, `perf report` would often end up attributing all
cost to the libc `frame_dummy` symbol since Haskell code was no covered
by any proper symbol (see #17605).
We now rather follow the model of C compilers and emit
descriptively-named local symbols for module internal things. Since this
will increase object file size this behavior can be disabled with the
`-fno-expose-all-symbols` flag.
With this `perf record` can finally be used against Haskell executables.
Even more, with `-g3` `perf annotate` provides inline source code.
-rw-r--r-- | compiler/basicTypes/Name.hs | 5 | ||||
-rw-r--r-- | compiler/cmm/CLabel.hs | 8 | ||||
-rw-r--r-- | compiler/main/DynFlags.hs | 5 | ||||
-rw-r--r-- | docs/users_guide/phases.rst | 14 |
4 files changed, 26 insertions, 6 deletions
diff --git a/compiler/basicTypes/Name.hs b/compiler/basicTypes/Name.hs index 2cbd50ed6f..9798617f72 100644 --- a/compiler/basicTypes/Name.hs +++ b/compiler/basicTypes/Name.hs @@ -567,7 +567,10 @@ pprExternal sty uniq mod occ is_wired is_builtin pprInternal :: PprStyle -> Unique -> OccName -> SDoc pprInternal sty uniq occ - | codeStyle sty = pprUniqueAlways uniq + | codeStyle sty = sdocWithDynFlags $ \dflags -> + if gopt Opt_ExposeAllSymbols dflags + then char '_' <> ppr_z_occ_name occ <> ppr_underscore_unique uniq + else pprUniqueAlways uniq | debugStyle sty = ppr_occ_name occ <> braces (hsep [pprNameSpaceBrief (occNameSpace occ), pprUnique uniq]) | dumpStyle sty = ppr_occ_name occ <> ppr_underscore_unique uniq diff --git a/compiler/cmm/CLabel.hs b/compiler/cmm/CLabel.hs index 9452b5f6c8..1a9e14c8f6 100644 --- a/compiler/cmm/CLabel.hs +++ b/compiler/cmm/CLabel.hs @@ -1302,8 +1302,8 @@ pprCLbl (RtsLabel (RtsSlowFastTickyCtr pat)) pprCLbl (ForeignLabel str _ _ _) = ftext str -pprCLbl (IdLabel name _cafs flavor) = - internalNamePrefix name <> ppr name <> ppIdFlavor flavor +pprCLbl (IdLabel name _cafs flavor) + = internalNamePrefix name <> ppr name <> ppIdFlavor flavor pprCLbl (CC_Label cc) = ppr cc pprCLbl (CCS_Label ccs) = ppr ccs @@ -1347,8 +1347,8 @@ instance Outputable ForeignLabelSource where ForeignLabelInExternalPackage -> parens $ text "external package" internalNamePrefix :: Name -> SDoc -internalNamePrefix name = getPprStyle $ \ sty -> - if asmStyle sty && isRandomGenerated then +internalNamePrefix name = sdocWithDynFlags $ \dflags -> getPprStyle $ \ sty -> + if asmStyle sty && isRandomGenerated && not (gopt Opt_ExposeAllSymbols dflags) then sdocWithPlatform $ \platform -> ptext (asmTempLabelPrefix platform) else diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs index 94cee4a7cd..65e5f7766f 100644 --- a/compiler/main/DynFlags.hs +++ b/compiler/main/DynFlags.hs @@ -656,6 +656,7 @@ data GeneralFlag -- forwards all -L flags to the collect2 command without using a -- response file and as such breaking apart. | Opt_SingleLibFolder + | Opt_ExposeAllSymbols | Opt_KeepCAFs | Opt_KeepGoing | Opt_ByteCode @@ -4220,6 +4221,7 @@ fFlagsDeps = [ flagSpec "error-spans" Opt_ErrorSpans, flagSpec "excess-precision" Opt_ExcessPrecision, flagSpec "expose-all-unfoldings" Opt_ExposeAllUnfoldings, + flagSpec "expose-all-symbols" Opt_ExposeAllSymbols, flagSpec "external-dynamic-refs" Opt_ExternalDynamicRefs, flagSpec "external-interpreter" Opt_ExternalInterpreter, flagSpec "flat-cache" Opt_FlatCache, @@ -4589,7 +4591,8 @@ defaultFlags settings Opt_RPath, Opt_SharedImplib, Opt_SimplPreInlining, - Opt_VersionMacros + Opt_VersionMacros, + Opt_ExposeAllSymbols ] ++ [f | (ns,f) <- optLevelFlags, 0 `elem` ns] diff --git a/docs/users_guide/phases.rst b/docs/users_guide/phases.rst index d0afe80a23..705d16c500 100644 --- a/docs/users_guide/phases.rst +++ b/docs/users_guide/phases.rst @@ -652,6 +652,20 @@ Options affecting code generation and ``-dynhisuf`` are the counterparts of ``-o``, ``-osuf``, and ``-hisuf`` respectively, but applying to the dynamic compilation. +.. ghc-flag:: -fexpose-all-symbols + :shortdesc: Produce symbols for all functions, including internal functions. + :type: dynamic + :category: codegen + :default: on + + By default, GHC emits verbose symbol tables which include local symbols for + module-internal functions. These can be useful for tools like :ref:`perf + <https://perf.wiki.kernel.org/>` but increase object file sizes. + + :ghc-flag:`-fno-expose-all-symbols` suppresses all non-global symbol table + entries, resulting in smaller object file sizes at the expense of + debuggability. + .. _options-linker: Options affecting linking |