-
Notifications
You must be signed in to change notification settings - Fork 562
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
POC: More aggressive dirty module checking #4339
base: master
Are you sure you want to change the base?
POC: More aggressive dirty module checking #4339
Conversation
Things that depend on things that for sure didn't change aren't rebuilt. Modules whose public api doesn't change still causes direct dependencies to be rebuilt.
…cbor file. The hacky approach of encoding the ExternsFile's and comparing the bytestrings, and destroying SourcePos to make them equal when source files changed, is not the proper way of doing this, mildly put.
# Conflicts: # src/Language/PureScript/Make/BuildPlan.hs
Based it off v0.14.5 now |
Heya! Just swinging by to say that this is really cool! I tried some similar experiments back on
The hope was to try and upstream the concepts once they were proved out to be have net benefits (or at least have such small drawbacks that it was worth it anyway). But then, life happened. In any case, I'm excited to see someone else taking up similar ideas! I see that you also came up the the idea of wiping out the source locations in order to keep the churn lower. That makes me feel like the idea wasn't a bad one 😅. There were two issues that I ran into that threw a couple of wrenches into the general idea of cut-off: re-exports and typeclass instances. I forget all of what the issues were with re-exports, but I want to say that it would've required a change in the externs format to make the direct dependencies actually useful. I believe it was a solveable problem, just non-trivial. I also only kind of remember what the issues were with typeclass instances, but I wrote some stuff down in an issue: joneshf/purs-tools#4. I think one thing that was causing a problem with typeclass instances was that the module where a typeclass instance was defined wasn't in the import list of an extern only at the location of use or something. I can't really remember. All I do remember is that if you had a module I think the other thing with typeclass instances was that in practical terms, it would only really improve stuff if you never changed a typeclass instance. And given how prevalent typeclasses are in the PS ecosystem, a seemingly innocuous change could make it so that recompilation speed was no better than the standard I haven't really been paying attention to PS since |
My plan was to make a poc, try it out at work, hope that someone here came along and either did the thing properly or gave me enough input to do it properly myself, so thanks for stopping by @joneshf :) Current issues:
|
Don't code while having a fever, kids. Also, don't reply to stuff on github. Feeling better now. The best part of all of this to me is that Previous status, as reported in the initial PR description:Dependency chain
Current status:Dependency chain
Modifying custom prelude, renaming ctor in exposed type
Modifying custom prelude, adding new non-exposed data type
Things to test:
And how do we write tests for all of this? |
…stuff. Remove most debug prints. Don't double-read externs.
…erns field into the build cache.
…rns file, to differentiate the two.
… cached externs are likely to be valid when the failing module compiles again.
…we know if we have to recompile because the shape of something changed.
It's now tracking the shape of types through the externs files to figure out of we need to recompile, e.g. because a type alias transitively refers to something that changed. Also handling re-exports, which it didn't before. It's quite far from optimal, and I haven't looked at the type class problem @joneshf mentioned, or even figured out what it is or if it's still a thing. I'm still very much exploring the compiler and learning as I go, with many dead ends, but I'm getting there. I'm also intentionally not planning this out ahead of time, to learn my way around the compiler code base, and to keep this not feeling like work. |
…irty-module-checking # Conflicts: # .github/workflows/ci.yml # purescript.cabal # src/Language/PureScript/Make.hs # src/Language/PureScript/Make/Actions.hs # src/Language/PureScript/Make/BuildPlan.hs
@@ -343,7 +343,7 @@ buildMakeActions outputDir filePathMap foreigns usePrefix = | |||
requiresForeign = not . null . CF.moduleForeign | |||
|
|||
progress :: ProgressMessage -> Make () | |||
progress = liftIO . TIO.hPutStr stderr . (<> "\n") . renderProgressMessage "Compiling " | |||
progress = liftIO . TIO.hPutStr stderr . (<> "\n") . renderProgressMessage "CompilingX5 " |
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.
🤔
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.
Five times faster?
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.
It's how I keep track of which compiler version is running where. purs --version
just reports e.g. 0.15.4 and changing that breaks all of the tooling.
…irty-module-checking
64d330d
to
5454476
Compare
If anyone wants to try it out, there are releases over here: https://github.com/drathier/purescript/releases . I'm using these daily when developing, with the purerl backend. I would say they're alpha quality atm; every once in a while it gets a cache hit when it shouldn't, but it's more helpful than not. |
@drathier I'd love to try this but ideally with 0.15.7. Any chance you could merge master and only if there's no conflicts cut a new release? |
@i-am-the-slime I'll have a release ready soon, I think. This was for trying things out, but the code quality isn't what I'd be happy to merge, so I reimplemented the changes with a more systematic bottom-up approach, fully completing things as I go instead of messing around and fixing stuff that came up. I've cleaned things up over at drathier#5 and based it on a recent master. Tracking changes to type aliases (type synonyms) is tricky as they're all erased by this point, and I'm still invalidating the cache a bit too often. I also haven't implemented re-exports there, but I'm working on it. |
0.15.7 based release available at https://github.com/drathier/purescript/releases/tag/v0.15.7-caching-15
Goals of this release
Non-goals of this release
|
I've been giving it a try today, it seems to work well! Haven't looked at the code yet. This was fun:
|
Current status of this POCWe're still using this for all development, fyi. I'm mostly waiting for the combination of:
Current repo and releasesNew development on this is made on https://github.com/drathier/purserl/releases/tag/v0.15.8-caching-30
|
As I was too recently dealing with this problem, I have reviewed the code for this PR. Here are some thoughts about it:
|
Since you were expressing disillusionment with getting your PRs merged on Discourse, here's what's up:
Entirely up to you, friend.
Was there any point in the history of this PR when it didn't come with comments saying ‘don't review this yet’? I don't think so. I'll review it when you ask for a review, unless someone else beats me to it. Feel free to @ me.
Not going to pre-review this before it's ready for review, but yeah, that's part of a review. Regardless of whether this approach makes it into the compiler, you wouldn't go to this trouble unless you were experiencing a problem, and either we'll work with you on this approach (for as long as you stay engaged, at least) until it's ‘good enough’, or we'll point you in a different direction and have a conversation with you about whether that alternative would address your problem as well. We ❤️ contributors and we want you to succeed! |
NOTE: Read the last comments before looking at code!
Description of the change
Goal:
I wanted to get closer to the compilation performance of the Elm compiler. This is a POC, it's hacky, it seems to work, it's absolutely not ready to be merged in, it's based of an old compiler version (v0.14.3), I'm not even sure it should be merged in, but I hope it shows that this can be done.
The basic idea:
Elm looks at the public api of each module, and if the public api of a module didn't change after recompiling, no downstream dependencies need to be recompiled, because everything they depend on will still be there, but possibly with a different implementation. This only works if you're not doing general cross-module inlining, which neither Elm nor Purescript seems to do.
Thus, modifying a comment on your prelude should result in just a single module being recompiled. Same for modifying a constant, a function body, or adding something new without touching anything already in the file.
Example performance:
Some debug prints when trying it out:
Checklist: