Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for building profiled dynamic way #9900

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

mpickering
Copy link
Collaborator

@mpickering mpickering commented Apr 17, 2024

Add support for profiled dynamic way

New options for cabal.project and ./Setup interface:

* `profiling-shared`: Enable building profiling dynamic way
* Passing `--enable-profiling` and `--enable-executable-dynamic` builds
  profiled dynamic executables.

Support for using `profiling-shared` is guarded behind a constraint
which ensures you are using `Cabal >= 3.13`.

In the cabal file:

* `ghc-prof-shared-options`, for passing options when building in
  profiling dynamic way

Other miscellenious fixes and improvements

* Some refactoring around ways so that which
  ways we should build for a library, foreign library and executable is
  computed by the `buildWays` function (rather than ad-hoc in three
  different places).

* Improved logic for detecting whether a compiler supports compiling
  a specific way. See functions `profilingVanillaSupported`,
  `dynamicSupported`, `profilingDynamicSupported` etc
  These functions report accurate infomation after ghc-9.10.1.

* Fixed logic for determining whether to build shared libraries. (see
  #10050)
  Now, if you explicitly enable `--*-shared`, then that will always take
  effect. If it's not specified then `--enable-executable-dynamic` will
  turn on shared libraries IF `--enable-profiling` is not enabled.

* Remove assumption that dynamically linked compilers can build dynamic
  libraries (they might be cross compilers.

* Query the build compiler to determine which library way is necessary
  to be built for TH support to work.
  (rather than assume all compilers are dynamically linked)

* An extensive test which checks how options for `./Setup` and
  `cabal-install` are translated into build ways.

Fixes #4816, #10049, #10050

@mpickering
Copy link
Collaborator Author

I require the version to be bumped to 3.13 before this can be finished.

@ulysses4ever
Copy link
Collaborator

@mpickering
Copy link
Collaborator Author

The test fails on 8.6.5 because of this GHC bug (fixed in 2018): e400b9babdcf11669f963aeec20078fe7ccfca0d

@mpickering mpickering force-pushed the wip/prof_dyn branch 2 times, most recently from fd810d4 to d47096e Compare May 29, 2024 12:21
New options for cabal.project and ./Setup interface:

* `profiling-shared`: Enable building profiling dynamic way
* Passing `--enable-profiling` and `--enable-executable-dynamic` builds
  profiled dynamic executables.

Support for using `profiling-shared` is guarded behind a constraint
which ensures you are using `Cabal >= 3.13`.

In the cabal file:

* `ghc-prof-shared-options`, for passing options when building in
  profiling dynamic way

Other miscellenious fixes and improvements

* Some refactoring around ways so that which
  ways we should build for a library, foreign library and executable is
  computed by the `buildWays` function (rather than ad-hoc in three
  different places).

* Improved logic for detecting whether a compiler supports compiling
  a specific way. See functions `profilingVanillaSupported`,
  `dynamicSupported`, `profilingDynamicSupported` etc
  These functions report accurate infomation after ghc-9.10.1.

* Fixed logic for determining whether to build shared libraries. (see
  haskell#10050)
  Now, if you explicitly enable `--*-shared`, then that will always take
  effect. If it's not specified then `--enable-executable-dynamic` will
  turn on shared libraries IF `--enable-profiling` is not enabled.

* Remove assumption that dynamically linked compilers can build dynamic
  libraries (they might be cross compilers.

* Query the build compiler to determine which library way is necessary
  to be built for TH support to work.
  (rather than assume all compilers are dynamically linked)

* An extensive test which checks how options for `./Setup` and
  `cabal-install` are translated into build ways.

Fixes haskell#4816, haskell#10049, haskell#10050
@mpickering mpickering changed the title Draft: Add support for building profiled dynamic way Add support for building profiled dynamic way May 29, 2024
@@ -807,6 +803,20 @@ computeLocalBuildConfig cfg comp programDb = do
, relocatable = fromFlagOrDefault False $ configRelocatable cfg
}

-- Dynamic executable, but no shared vanilla libararies
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- Dynamic executable, but no shared vanilla libararies
-- Dynamic executable, but no shared vanilla libraries

++ "is not being built. Linking will fail if any executables "
++ "depend on the library."

-- Profiled dynamic executable, but no shared profiling libararies
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- Profiled dynamic executable, but no shared profiling libararies
-- Profiled dynamic executable, but no shared profiling libraries

return $ \buildOptions -> apply buildOptions{LBC.withProfLibShared = tryLibProfilingShared}
else -- Case 2: Compiler doesn't support profiling shared so turn them off
do
-- If we wanted to enable profilng shared libraries.. tell the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- If we wanted to enable profilng shared libraries.. tell the
-- If we wanted to enable profiling shared libraries.. tell the

, LBC.withProfLib = profilingVanillaSupportedOrUnknown comp && (tryLibProfilingShared || LBC.withProfLib original_options)
, LBC.withDynExe = if LBC.withProfExe original_options then False else LBC.withDynExe original_options
}
return (tryExeProfiling && not (tryLibProfiling || tryLibProfilingShared), apply2)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move the "when exeProfWithoutLibProf " warning into here, and then refactor to not return this boolean? I find it too complicated right now.

]
whenGHCi $ installOrdinary builtDir targetDir ghciLibName
ProfWay -> do
installOrdinary builtDir targetDir profileLibName
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't this code path include any logic to deal with extraBundledLibs that all other paths include? (I know you didn't change this.)

Comment on lines +236 to +255
forM_ (neededLibWays isIndef) $ \case
StaticWay -> compileIfNeeded vanillaSrcOpts
DynWay -> compileIfNeeded sharedSrcOpts{ghcOptObjSuffix = toFlag "dyn_o"}
ProfWay -> compileIfNeeded profSrcOpts{ghcOptObjSuffix = toFlag "p_o"}
ProfDynWay -> compileIfNeeded profSharedSrcOpts{ghcOptObjSuffix = toFlag "p_dyn_o"}
CFLib flib ->
case neededFLibWay (withDynFLib flib) of
StaticWay -> compileIfNeeded vanillaSrcOpts
DynWay -> compileIfNeeded sharedSrcOpts
ProfWay -> compileIfNeeded profSrcOpts
ProfDynWay -> compileIfNeeded profSharedSrcOpts
-- For the remaining component types (Exec, Test, Bench), we also
-- determine with which options to build the objects (vanilla vs shared vs
-- profiled), but predicate is the same for the three kinds.
_exeLike ->
case neededExeWay of
StaticWay -> compileIfNeeded vanillaSrcOpts
DynWay -> compileIfNeeded sharedSrcOpts
ProfWay -> compileIfNeeded profSrcOpts
ProfDynWay -> compileIfNeeded profSharedSrcOpts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good improvement.👍

Comment on lines +461 to +473
wantedFLibWay is_dyn_flib =
case (is_dyn_flib, withProfExe lbi) of
(True, True) -> ProfDynWay
(False, True) -> ProfWay
(True, False) -> DynWay
(False, False) -> StaticWay

wantedExeWay =
case (withDynExe lbi, withProfExe lbi) of
(True, True) -> ProfDynWay
(True, False) -> DynWay
(False, True) -> ProfWay
(False, False) -> StaticWay
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good that you got rid of the sketchy if isLib then id else take 1 that was there before. 👍

(False, True) -> ProfWay
(False, False) -> StaticWay
in
(wantedLibWays, wantedFLibWay, wantedExeWay)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to the following logic:

      neededWays =
        wantedWays
          <> Set.fromList
            -- TODO: You also don't need to build the GHC way when doing TH if
            -- you are using an external interpreter!!
            [defaultGhcWay | doingTH && defaultGhcWay `Set.notMember` wantedWays]

?


-- TODO: [code cleanup] move this into the Cabal lib. It's currently open
-- coded in Distribution.Simple.Configure, but should be made a proper
-- function of the Compiler or CompilerInfo.
compilerShouldUseSharedLibByDefault =
case compilerFlavor compiler of
GHC -> GHC.isDynamic compiler
GHC -> GHC.compilerBuildWay compiler == DynWay && canBuildSharedLibs
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intended that this is false if compilerBuildWay == ProfDynWay?

@@ -734,7 +735,7 @@ computeLocalBuildConfig cfg comp programDb = do
CompilerId GHC _ ->
-- if ghc is dynamic, then ghci needs a shared
-- library, so we build one by default.
GHC.isDynamic comp
GHC.compilerBuildWay comp == DynWay
Copy link
Collaborator

@sheaf sheaf May 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the logic consistent here? If we have --enable-executable-dynamic --enable-profiling, do we want sharedLibsByDefault to be True?
Conversely, why don't we have GHC.compilerBuildWay comp `elem` [DynWay, ProfDynWay]? What will happen with ProfDyn and ghci? Is that supported?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants