elm-lang / elm-make

A build tool for Elm projects
BSD 3-Clause "New" or "Revised" License
175 stars 45 forks source link

Stop unnecessary compilation when interface is not changed #176

Closed jinjor closed 6 years ago

jinjor commented 6 years ago

Currently, all modules in dependency graph are always compiled even if no interface has been changed. For example, if we have three files with following dependencies, modifying C.elm causes compiling B, A and Main.

Main -> A -> B -> C

Is it possible for elm-make to stop compilation if C's interface has not been changed? In my project, there are some modules that is referred by many other modules. I have to wait for 20+ modules being compiled even if no interface had been actually changed.

More optimization could be done if value-level dependencies for each module is cached. So we can skip unnecessary compilation until the depending module has "breaking change".

process-bot commented 6 years ago

Thanks for the issue! Make sure it satisfies this checklist. My human colleagues will appreciate it!

Here is what to expect next, and if anyone wants to comment, keep these things in mind.

zwilias commented 6 years ago

This does, in fact, sound plausible, and could make a rather huge difference for re-compilation.

For most development workflows, where compile-on-save is relevant, this would cut down recompilation times to seconds or even less, rather than minutes. Since the interface equality check should only happen for files that already had an elmi file cached, this shouldn't influence clean compile times.

As a potential datapoint, I implemented a hacky, dirty, suboptimal version of this. Even with that suboptimal version:

image

julianjelfs commented 6 years ago

This may be controversial, but is there any chance of making this sort of change in a fork so that those who are really struggling have an option of using their own version of elm-make in the short term?

evancz commented 6 years ago

I believe this is possible, but it would be quite a difficult change. I cannot do it for 0.19 but probably after. I don't like to track feature requests in issues, so I'll put it on my personal list of ideas.

For folks worried about perf, I would be curious to see how the perf work in 0.19 improves things before you get too committed to thinking this is definitely the answer for you. For example, I suspect some folks are unaware of the perf problem with the exhaustiveness checker on tuple patterns. Seeing 7s compiles on 12 files is crazy, and almost certainly is a result of this bug. That perf issue is fixed in 0.19 which will likely save you a lot of time if you are hitting that case.

Point is, this can help, but there are other factors to take into consideration as well.

evancz commented 6 years ago

@zwilias, can you write up more information about your project and share it with me on Slack?

I am curious for each file:

  1. How many lines of code?
  2. Do it have any case (x, y) of ... expressions? Big case expressions in general?
  3. If you compile the file alone, how long does it take?

I appreciate that it'll be a bit of work to get all that, but I think it could be really valuable to diagnosing the times you are seeing. Based on my knowledge, hitting some corner case is the only thing that can explain the screenshot above.

As a broader note, if folks can isolate performance problems with concrete evidence, it is easier to make improvements in your project and in the compiler.

jinjor commented 6 years ago

@evancz I tried (1) and (3) on one of my project (13k LOC).

https://gist.github.com/jinjor/e71b1e224552524b38760ab6783bdf74

This shows how long does it take to compile only one module for each file (Success! Compiled 1 module.). Is this information helpful for you?

evancz commented 6 years ago

That is an extremely helpful gist, thank you for sharing!

I can use it for more refined profiling, and I know someone at NRI wanted something like this. I put it in a spreadsheet to try to see if #-of-lines or #-of-imports correlates much, but it wasn't too clear. I think this could be paired with the SCC information in the compiler to give really helpful info!

In any case, I think this can be a good starting point for all of us to make more targeted improvements.