Modifying a struct definition recompiles fewer files (it no longer requires files that only pattern match or update structs to recompile)
1. Enhancements
Elixir
[Code] Add module_definition: :interpreted option to Code which allows module definitions to be evaluated instead of compiled. In some applications/architectures, this can lead to drastic improvements to compilation times. Note this does not affect the generated .beam file, which will have the same performance/behaviour as before
[Code] Make module purging opt-in and move temporary module deletion to the background to speed up compilation times
[Integer] Add Integer.popcount/1
[Kernel] Move struct validation in patterns and updates to type checker, this means adding and remove struct fields will cause fewer files to be recompiled
[Kernel] Add type inference across clauses. For example, if one clause says x when is_integer(x), then the next clause may no longer be an integer
[Kernel] Detect and warn on redundant clauses
[List] Add List.first!/1 and List.last!/1
Add Software Bill of Materials guide to the Documentation
Mix
[mix compile] Add module_definition: :interpreted option to Code which allows module definitions to be evaluated instead of compiled. In some applications/architectures, this can lead to drastic improvements to compilation times. Note this does not affect the generated .beam file, which will have the same performance/behaviour as before
[mix deps] Parallelize dep lock status checks during deps.loadpaths, improving boot times in projects with many git dependencies
2. Potential breaking changes
Elixir
map.foo() (accessing a map field with parens) and mod.foo (invoking a function without parens) will now raise instead of emitting runtime warnings, aligning themselves with the type system behaviour
3. Bug fixes
IEx
[IEx] Ensure warnings emitted during IEx parsing are properly displayed/printed
[IEx] Ensure pry works across remote nodes
Mix
[mix compile.erlang] Topsort Erlang modules before compilation for proper dependency resolution
All run with Erlang 28.4, using time mix compile --force --profile time
1.19.5-otp-28
[profile] Finished cycle resolution in 0ms
[profile] Finished compilation cycle of 492 modules in 8234ms
[profile] Finished writing modules to disk in 53ms
[profile] Finished after compile callback in 1095ms
[profile] Finished group pass check of 492 modules in 201ms
Executed in 36.69 secs fish external
usr time 41.91 secs 0.42 millis 41.91 secs
sys time 7.75 secs 4.52 millis 7.74 secs
1.20.0-rc.0
Application does not compile
1.20.0-rc.1-otp-28
[profile] Finished cycle resolution in 0ms
[profile] Finished compilation cycle of 492 modules in 8444ms
[profile] Finished writing modules to disk in 50ms
[profile] Finished after compile callback in 1193ms
[profile] Finished group pass check of 492 modules in 212ms
Executed in 38.67 secs fish external
usr time 42.52 secs 0.44 millis 42.51 secs
sys time 8.45 secs 4.03 millis 8.45 secs
1.20.0-rc.2-otp-28
[profile] Finished cycle resolution in 0ms
[profile] Finished compilation cycle of 492 modules in 6833ms
[profile] Finished writing modules to disk in 40ms
[profile] Finished after compile callback in 344ms
[profile] Finished group pass check of 492 modules in 322ms
Executed in 34.96 secs fish external
usr time 26.77 secs 0.29 millis 26.77 secs
sys time 5.98 secs 4.01 millis 5.98 secs
Hey! I ran into a compilation issue with open_api_spex on rc.2 that doesn’t happen on rc.1.
On rc.1 the whole thing compiles fine in ~29s. On rc.2 (and current main at 6fd161d) it just hangs forever on two modules: cast.ex and deprecated_cast.ex. I waited 5+ minutes before giving up and killing it. The compiler prints the “it’s taking more than 10s” message for both and never moves past them.
Both modules have a ton of function clauses (~20+) doing pattern matching on nested structs and maps with overlapping shapes, stuff like:
I used time mix compile --force --profile time to get an idea for what is the cause. One file containing ~35 objects and input opjects for a graphql api jumped from ~220ms to 74s. The file doesn’t contain any macros that would explain the massive increase in compile time. Is there anything I can do get get a better idea on what is causing this?
I didn’t check the out the warnings yet, because I think this is a more glaring issue
Apple M1 Max (10-cores), MIX_OS_DEPS_COMPILE_PARTITION_COUNT not set
Elixir 1.19.5-otp-28 + Erlang 28.4 mix deps.compile --force 284.31s user 54.21s system 231% cpu 2:25.97 total mix compile --force 114.06s user 20.10s system 416% cpu 32.182 total
Elixir 1.20.0-rc.3-otp-28 + Erlang 28.4 mix deps.compile --force 235.06s user 39.24s system 202% cpu 2:15.61 total mix compile --force 87.31s user 15.89s system 377% cpu 27.335 total
[profile] Finished cycle resolution in 0ms
[profile] Finished compilation cycle of 499 modules in 8490ms
[profile] Finished writing modules to disk in 49ms
[profile] Finished after compile callback in 972ms
[profile] Finished group pass check of 499 modules in 203ms
Executed in 10.29 secs fish external
usr time 42.28 secs 0.27 millis 42.28 secs
sys time 7.64 secs 2.13 millis 7.64 secs
1.20.0-rc.2-otp-28
[profile] Finished cycle resolution in 0ms
[profile] Finished compilation cycle of 499 modules in 7269ms
[profile] Finished writing modules to disk in 25ms
[profile] Finished after compile callback in 307ms
[profile] Finished group pass check of 499 modules in 235ms
Executed in 8.46 secs fish external
usr time 25.73 secs 0.32 millis 25.73 secs
sys time 4.49 secs 2.26 millis 4.49 secs
1.20.0-rc.3-otp-28
[profile] Finished cycle resolution in 0ms
[profile] Finished compilation cycle of 499 modules in 7055ms
[profile] Finished writing modules to disk in 28ms
[profile] Finished after compile callback in 250ms
[profile] Finished group pass check of 499 modules in 231ms
Executed in 8.09 secs fish external
usr time 25.52 secs 0.27 millis 25.52 secs
sys time 4.48 secs 1.97 millis 4.48 secs
The times I reported previously also included time to compile the dependencies while these do not, I’m not sure which is more correct/helpful.
Did you use the GraphQL patch mentioned above? That should bring further improvements. On another project we saw compilation time go from 15s to 10s with the GraphQL patch!
Please open up an issue if you can isolate it down! It may be as simple as putting that file in a separate project. And it will be very important for us to push further improvements to the type system.