Description
Elixir and Erlang/OTP versions
Erlang/OTP 27 [erts-15.2] [source] [64-bit] [smp:32:32] [ds:32:32:10] [async-threads:1] [jit:ns]
Elixir 1.18.1 (compiled with Erlang/OTP 27)
Operating system
Linux
Current behavior
I have an application which has a lot of its own files and a fair number of dependencies. When running mix deps.compile
for the first time (so no _build
directory exists at this point), mix spends a lot of time compiling applications, one after the other, in a serial fashion.
The problem with this approach is that I have a 16-core, 32-logical-core processor, and System.schedulers_online()
returns 32, so mix should really always be trying to schedule 32 compilation units between applications with satisfied dependencies, which it does not appear to be doing.
Since most dependency applications are just a handful of files, this results in just a few cores being used most of the time. The logging and utilization suggests that all of the files within each application get compiled in parallel; then the result of all compilations is awaited before generating the next application.
An example of a deps list in a new mix project that doesn't make the best use of the CPU during compilation follows:
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:phoenix, "~> 1.7"},
{:phoenix_pubsub, "~> 2.1"},
{:phoenix_ecto, "~> 4.4"},
{:ecto_sql, "~> 3.9"},
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 3.3"},
{:phoenix_view, "~> 2.0"},
{:phoenix_live_reload, "~> 1.4", only: :dev},
{:gettext, "~> 0.22"},
{:jason, "~> 1.4"},
{:bandit, "~> 1.2"},
{:phoenix_pubsub_redis, "~> 3.0"},
{:ecto_network, "~> 1.3"},
{:bcrypt_elixir, "~> 3.0"},
{:pot, "~> 1.0"},
{:secure_compare, "~> 0.1"},
{:nimble_parsec, "~> 1.2"},
{:qrcode, "~> 0.1"},
{:redix, "~> 1.2"},
{:remote_ip, "~> 1.1"},
{:briefly, "~> 0.4"},
{:req, "~> 0.5"},
{:exq, "~> 0.17"},
{:ex_aws, "~> 2.0"},
{:ex_aws_s3, "~> 2.0"},
{:sweet_xml, "~> 0.7"},
{:inet_cidr, "~> 1.0"},
{:swoosh, "~> 1.17"},
{:mua, "~> 0.2.0"},
{:mail, "~> 0.3.0"},
{:ex_doc, "~> 0.30"},
{:sobelow, "~> 0.11"},
{:mix_audit, "~> 2.1"},
{:dialyxir, "~> 1.2"}
]
end
Example
$ time mix deps.compile
[...]
real 0m30.369s
user 1m56.178s
sys 0m30.771s
-> 3.83x speedup over serial compilation
Expected behavior
My application contains 640+ elixir compilation units. After cleaning and running mix compile
, mix will max out the CPU immediately and consistently schedule work for all 32 logical cores until there are no new compilation tasks to complete.
Example:
$ time mix compile
[...]
Generated philomena app
real 0m13.939s
user 1m40.286s
sys 0m22.636s
-> 7.19x speedup over serial compilation
This would also be the desired behavior when compiling application dependencies.
Activity