Skip to content

Explicitly model more dependencies on cradle startup #463

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

alexfmpe
Copy link
Contributor

@alexfmpe alexfmpe commented Apr 25, 2025

This is a first batch of changes towards explicitly modeling the data dependencies so it's easier to reason about, find saving opportunities and offload cognitive load to the compiler.

Before

$ time cabal run hie-bios -- debug hie-bios.cabal
real	0m0.710s

$ cabal test all
All 43 tests passed (56.80s)

After

$ time cabal run hie-bios -- debug hie-bios.cabal
real	0m0.635s

$ cabal test all
All 43 tests passed (55.25s)

When working on #458 I often had trouble reasoning about and keeping track of the actual flow due to the MonadFix IO used for lazy reading of program versions.
In particular, the first ghc version check triggers a cabal version check, so trying to read the ghc version from cabal path not only doesn't save any time (since we're preparing a ghc call for it), as it will also cause an infinite cycle if we try to read the ghc version lookup in here. The real fun starts when this is triggered by touching something else that's unwittingly involved in the cycle.

@alexfmpe alexfmpe force-pushed the cabal-path-correctness branch from 00c31c8 to a7a9fed Compare April 26, 2025 00:17
deriving (Functor, Foldable, Traversable)

makeVersions :: LogAction IO (WithSeverity Log) -> FilePath -> IO BuildToolVersions
makeVersions l wdir = mapConcurrently (\v -> v l wdir) $ BuildToolVersions getCabalVersion getStackVersion
Copy link
Collaborator

Choose a reason for hiding this comment

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

why do we use mapConcurrently here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Welp, forgot to click submit on my own review back when opening the PR.

why do we use mapConcurrently here?

To allow running these in parallel when compiled with an executable using -threaded. See also my other comment on this line.
There's not much difference between sum and max when only one tool is installed as the other will fail near-instantly, and they take basically the same time when both are present.
The downside is that we do an extra version check we wouldn't do with the old lazy approach when all the following are true

  • -threaded is absent
  • both tools are installed
  • stack-only or cabal-only cradle

I do think we can again avoid unneeded calls by first looking at all the cradle types and seeing what we will actually need to load instead of loading all unconditionally but my first priority was cutting the fragile mdo knot without incurring slowdowns so I'm doing baby steps.

That said, stack's version doesn't seem to be used anywhere so I'm not sure why we even read it.
Code compiles after simply removing the field definition and the getStackVersion call so it seems to have no effect besides in the exported API which a comment says is for test's sake.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

deriving (Functor, Foldable, Traversable)

makeVersions :: LogAction IO (WithSeverity Log) -> FilePath -> IO BuildToolVersions
makeVersions l wdir = mapConcurrently (\v -> v l wdir) $ BuildToolVersions getCabalVersion getStackVersion
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These both take around 40ms -+ 10ms for me, so it doesn't seem that either has to wait much for the other, which would slow down stack only or cabal only scenarios.
Theoretically it speeds up the case where both are needed.
That said, stackVersion doesn't seem to be used anywhere?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it is safe to just remove it since it is not even used. Easy to add them back if we need them in the future

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I feel like it should be re-used by HLS instead of having separate impls.
Maybe it was at some point?

, isCabalMultipleCompSupported
, ProgramVersions
, BuildToolVersions
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Breaking change. Can't seem to avoid it while cutting the knot - at most the old name can be kept.

@@ -296,15 +279,15 @@ resolvedCradlesToCradle logger buildCustomCradle root cs = mdo
notNoneType _ = True


resolveCradleAction :: Show a => LogAction IO (WithSeverity Log) -> (b -> CradleAction a) -> ResolvedCradles b -> FilePath -> ResolvedCradle b -> CradleAction a
resolveCradleAction l buildCustomCradle cs root cradle = addLoadStyleLogToCradleAction $
resolveCradleAction :: Show a => LogAction IO (WithSeverity Log) -> (b -> CradleAction a) -> ResolvedCradles b -> FilePath -> ResolvedCradle b -> IO (CradleAction a)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this one can be made pure again, but it needs some other changes first

Comment on lines +543 to +597
cabalPathOutput = case res of
CradleSuccess out -> out
_ -> Nothing
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is pretty awkward. Maybe callCabalPathForCompilerPath should be IO instead of CradleResultT ?

deriving (Functor, Foldable, Traversable)

makeVersions :: LogAction IO (WithSeverity Log) -> FilePath -> IO BuildToolVersions
makeVersions l wdir = mapConcurrently (\v -> v l wdir) $ BuildToolVersions getCabalVersion getStackVersion
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Welp, forgot to click submit on my own review back when opening the PR.

why do we use mapConcurrently here?

To allow running these in parallel when compiled with an executable using -threaded. See also my other comment on this line.
There's not much difference between sum and max when only one tool is installed as the other will fail near-instantly, and they take basically the same time when both are present.
The downside is that we do an extra version check we wouldn't do with the old lazy approach when all the following are true

  • -threaded is absent
  • both tools are installed
  • stack-only or cabal-only cradle

I do think we can again avoid unneeded calls by first looking at all the cradle types and seeing what we will actually need to load instead of loading all unconditionally but my first priority was cutting the fragile mdo knot without incurring slowdowns so I'm doing baby steps.

That said, stack's version doesn't seem to be used anywhere so I'm not sure why we even read it.
Code compiles after simply removing the field definition and the getStackVersion call so it seems to have no effect besides in the exported API which a comment says is for test's sake.

deriving (Functor, Foldable, Traversable)

makeVersions :: LogAction IO (WithSeverity Log) -> FilePath -> IO BuildToolVersions
makeVersions l wdir = mapConcurrently (\v -> v l wdir) $ BuildToolVersions getCabalVersion getStackVersion
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@alexfmpe alexfmpe force-pushed the cabal-path-correctness branch from a7a9fed to cc3ac98 Compare June 4, 2025 14:47
@alexfmpe alexfmpe force-pushed the cabal-path-correctness branch from cc3ac98 to 3025d2d Compare June 4, 2025 15:28
-- We trust the assertion for a bios program, as we have no way of
-- checking its version
| LoadWithContext _ <- loadStyle ->
if ghc >= makeVersion [9,4]
if isCabalMultipleCompSupported Nothing (Just ghc)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can just do pure $ bool LoadFile loadStyle $ isCabalMultipleCompSupported Nothing ghc_version for the whole thing if we don't care about the specific log below.
Alternatively, if we always want it on every check, we can also have a util that does that consistently.

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.

2 participants