diff --git a/ChangeLog.md b/ChangeLog.md index f9a370e9cb..bc51a4cc17 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -10,6 +10,12 @@ Major changes: Behavior changes: +* From GHC 9.4.1, the strategy for the automatic insertion of cost-centres for + profiling recommended by the GHC User's Guide is `-fprof-late`. Stack's + `build --profile` command now adopts that recommendation (rather than + `-fprof-auto`, still applicable to earlier GHC versions). Existing profiling + builds will be rebuilt. + Other enhancements: * Consider Cabal 3.18 to be a tested library and remove warnings. diff --git a/doc/commands/build_command.md b/doc/commands/build_command.md index 2f9d7d5244..3d0fc23eb9 100644 --- a/doc/commands/build_command.md +++ b/doc/commands/build_command.md @@ -979,20 +979,24 @@ expressions, and generate a profiling report in tests or benchmarks. GHC provides various strategies for the automatic insertion of cost-centres into the compiled program. The flag enables the strategy recommended in the GHC -User's Guide (GHC flag `-fprof-auto`) and gives every Constant Applicative Form -(CAF, a top-level thunk) its own cost-centre stack) (GHC flag `-fprof-cafs`). +User's Guide and gives every Constant Applicative Form (CAF, a top-level thunk) +its own cost-centre stack) (GHC flag `-fprof-cafs`). -!!! note +The recommended strategy: - From GHC 9.4.1, the stategy recommended in the GHC User's Guide has been - `-fprof-late`. Stack has not yet been updated to reflect that. +* **for GHC 9.4.1 and later**, is enabled by GHC flag `-fprof-late`. This + strategy annotates, after GHC's optimizer has run and unfoldings have been + created, all top-level bindings (only) with `SCC` (Set Cost Centre). If a + function is inlined into a use site its costs will be counted against the + caller’s cost-centre; and -The recommended strategy annotates, before GHC's optimizer has run, all bindings (top-level or nested, whether exported or not), other than those marked -`INLINE`, with `SCC` (Set Cost Centre). +* **otherwise**, is enabled by GHC flag `-fprof-auto`. This strategy annotates, + before GHC's optimizer has run, all bindings (top-level or nested, whether + exported or not), other than those marked `INLINE`, with `SCC`. -The GHC flags set by the flag can be reversed with GHC flags `-fno-prof-auto` or -`-fno-prof-cafs` and other GHC flags applied. See the -[`--ghc-options`](#-ghc-options-option) option. +The GHC flags set by the flag can be reversed with GHC flags `-fno-prof-late` or +`-fno-prof-auto` (as applicable) or `-fno-prof-cafs` and other GHC flags +applied. See the [`--ghc-options`](#-ghc-options-option) option. The flag affects the location of the local project installation directory. See the [`stack path --local-install-root`](path_command.md) command. diff --git a/src/Stack/Build/Source.hs b/src/Stack/Build/Source.hs index 61bdce6e4e..b2cae54b9d 100644 --- a/src/Stack/Build/Source.hs +++ b/src/Stack/Build/Source.hs @@ -113,7 +113,6 @@ loadSourceMap targets boptsCli sma = do bconfig <- view buildConfigL let errsPackages = mapMaybe checkPackage packagesWithCliFlags compiler = sma.compiler - ghcVersion = getGhcVersion compiler buildOpts = bconfig.config.build infoTableProfSupported = ghcVersion >= mkVersion [9, 2, 1] infoTableProfUnsupportedWarning = @@ -146,6 +145,7 @@ loadSourceMap targets boptsCli sma = do , globalPkgs } where + ghcVersion = getGhcVersion sma.compiler cliFlags = boptsCli.flags targetsAndSmaDeps = targets.deps <> sma.deps packagesWithCliFlags = mapMaybe maybeProjectWithCliFlags $ Map.toList cliFlags @@ -212,6 +212,7 @@ loadSourceMap targets boptsCli sma = do ghcOptions = generalGhcOptions bconfig boptsCli + ghcVersion isTarget isProjectPackage isInfoTableProf @@ -276,7 +277,7 @@ hashSourceMapData boptsCli sm = do isInfoTableProf = ghcVersion >= mkVersion [9, 2, 1] && bc.config.build.infoTableProf bootGhcOpts = - map display (generalGhcOptions bc boptsCli False False isInfoTableProf) + map display (generalGhcOptions bc boptsCli ghcVersion False False isInfoTableProf) hashedContent = toLazyByteString $ compilerPath <> compilerInfo @@ -337,11 +338,12 @@ generalCabalConfigOpts bconfig boptsCli name isTarget isLocal = concat generalGhcOptions :: BuildConfig -> BuildOptsCLI + -> Version -> Bool -> Bool -> Bool -> [Text] -generalGhcOptions bconfig boptsCli isTarget isLocal isInfoTableProf = concat +generalGhcOptions bconfig boptsCli ghcVersion isTarget isLocal isInfoTableProf = concat [ Map.findWithDefault [] AGOEverything config.ghcOptionsByCat , if isLocal then Map.findWithDefault [] AGOLocals config.ghcOptionsByCat @@ -351,7 +353,7 @@ generalGhcOptions bconfig boptsCli isTarget isLocal isInfoTableProf = concat else [] , concat [["-fhpc"] | isLocal && bopts.testOpts.coverage] , if bopts.libProfile || bopts.exeProfile - then ["-fprof-auto", "-fprof-cafs"] + then [recommendedProfStrategy, "-fprof-cafs"] else [] , [ "-g" | not $ bopts.libStrip || bopts.exeStrip ] , if isInfoTableProf @@ -364,6 +366,12 @@ generalGhcOptions bconfig boptsCli isTarget isLocal isInfoTableProf = concat where bopts = config.build config = view configL bconfig + -- The strategy for the automatic insertion of cost centres for profiling, as + -- recommended by the GHC User's Guide: + recommendedProfStrategy :: Text + recommendedProfStrategy + | ghcVersion >= mkVersion [9, 4, 1] = "-fprof-late" + | otherwise = "-fprof-auto" includeExtraOptions = case config.applyGhcOptions of AGOTargets -> isTarget diff --git a/src/Stack/ConfigureOpts.hs b/src/Stack/ConfigureOpts.hs index 6a31ed3740..8d7708d757 100644 --- a/src/Stack/ConfigureOpts.hs +++ b/src/Stack/ConfigureOpts.hs @@ -127,6 +127,12 @@ configureOptsNonPathRelated econfig bco deps isLocal package = concat | bopts.libProfile || bopts.exeProfile ] , ["--enable-profiling" | bopts.exeProfile && isLocal] + -- The default --profiling-detail is exported-functions (equivalent to GHC's + -- -fprof-auto-exported) and toplevel-functions (equivalent to GHC's + -- -fprof-auto-top). Neither adds anything to GHC's -fprof-auto and neither + -- are required for GHC's -fprof-late. So, we turn it off, which applies to + -- both executables and libraries: + , ["--profiling-detail=none"] , ["--enable-split-objs" | bopts.splitObjs] , [ "--disable-library-stripping" | not $ bopts.libStrip || bopts.exeStrip