-
Notifications
You must be signed in to change notification settings - Fork 65
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
base: master
Are you sure you want to change the base?
Conversation
00c31c8
to
a7a9fed
Compare
deriving (Functor, Foldable, Traversable) | ||
|
||
makeVersions :: LogAction IO (WithSeverity Log) -> FilePath -> IO BuildToolVersions | ||
makeVersions l wdir = mapConcurrently (\v -> v l wdir) $ BuildToolVersions getCabalVersion getStackVersion |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh HLS seems to do it's own separate version checks: https://github.com/haskell/haskell-language-server/blob/cd42bcfdae18b3e377375f495f9739027f3300fc/src/Ide/Version.hs#L62
deriving (Functor, Foldable, Traversable) | ||
|
||
makeVersions :: LogAction IO (WithSeverity Log) -> FilePath -> IO BuildToolVersions | ||
makeVersions l wdir = mapConcurrently (\v -> v l wdir) $ BuildToolVersions getCabalVersion getStackVersion |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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
cabalPathOutput = case res of | ||
CradleSuccess out -> out | ||
_ -> Nothing |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh HLS seems to do it's own separate version checks: https://github.com/haskell/haskell-language-server/blob/cd42bcfdae18b3e377375f495f9739027f3300fc/src/Ide/Version.hs#L62
a7a9fed
to
cc3ac98
Compare
cc3ac98
to
3025d2d
Compare
-- 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) |
There was a problem hiding this comment.
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.
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
After
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.