Another Compiler Refactor: Performance & Cleanup #2282
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is a big PR, more easily reviewed by commit.
Changeset
erl_first_file
entries weren't properly tracked in the DAG.That commit also fixes a few type issues and a latent bug in a bad pattern match that some plugins could have tripped on.
We run the analysis for an extra_src_dir by making a fake app for it, but send in the app alone for analysis.
In the current master, the DAG pruning routine looks at the DAG and files submitted and goes "this right here is a project with 99% of its apps deleted". It then tries to prune the whole DAG except for some test files. The code "works" simply because there's a false-positive check that makes sure the file is on disk before removing it for the DAG.
Of course this is a lot costlier than just checking the graph, And ends up making extra dir runs where ~80% of the time is spent double-checking the false positives for file deletions.
This commit fixes this by merging in all extra_src fake apps and making them run in a single analysis phase, meaning we only pay the cost of the DAG pruning once for the whole project, making it faster than any sparse repo.
There's also a small patch needed for the root-level extra src dirs; turns out that since the context-handling in the
rebar_compiler
uses a map to store content, running single-pass analysis clobbered entries for a given app if they had more than one extra_src_dir in there.I also took the time to clean up the ordering of that file.
Benchmarks
I replicated the troublesome monorepos of larger corporations that we have received reports about. The benchmark mostly focuses on "null" builds, where the app was already built and we just re-compile it a second time. This lets us evaluate the cost of just scanning for changes, without accounting for externalities like hooks or the Erlang compiler.
The problem mentioned was specifically with
rebar3 as test compile
being really dog slow due toextra_src_dirs
Set up an experiment by doing the following, which creates a project with over 300 apps, even if they contain only 2-3 modules each:
Here are my results as run on my small VPS with 2 cores.
rebar3 compile: 7.32s user 1.93s system 165% cpu 5.582 total
rebar3 as test compile: 44.55s user 10.19s system 149% cpu 36.674 total
rebar3 compile: 7.05s user 2.29s system 160% cpu 5.824 total
rebar3 as test compile: 10.47s user 2.10s system 128% cpu 9.819 total
Having ~1 second of jitter either way on all runs was pretty predictable. There is no clear change either way on
rebar3 compile
but withrebar3 as test compile
it's obvious that we're now going around 4x faster on that case. It's not a fixed cost though; it grows worse as you add more apps with more modules.