Skip to content

Commit 62e1d71

Browse files
committed
Avoid central bottleneck when loading apps if we know their source
1 parent d6ed6d1 commit 62e1d71

File tree

1 file changed

+27
-14
lines changed

1 file changed

+27
-14
lines changed

lib/mix/lib/mix/tasks/compile.all.ex

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ defmodule Mix.Tasks.Compile.All do
1414
Mix.Project.get!()
1515
config = Mix.Project.config()
1616
validate_compile_env? = "--no-validate-compile-env" not in args
17+
lib_path = Path.join(Mix.Project.build_path(config), "lib")
1718

1819
# Make sure Mix.Dep is cached to avoid loading dependencies
1920
# during compilation. It is likely this will be invoked anyway,
2021
# as both Elixir and app compilers rely on it.
2122
Mix.Dep.cached()
2223

2324
unless "--no-app-loading" in args do
24-
load_apps(config, validate_compile_env?)
25+
load_apps(config, lib_path, validate_compile_env?)
2526
end
2627

2728
result =
@@ -39,8 +40,9 @@ defmodule Mix.Tasks.Compile.All do
3940
end)
4041
end
4142

43+
app = config[:app]
4244
_ = Code.prepend_path(Mix.Project.compile_path())
43-
load_app(config[:app], validate_compile_env?)
45+
load_app(app, %{app => true}, lib_path, validate_compile_env?)
4446
result
4547
end
4648

@@ -93,19 +95,20 @@ defmodule Mix.Tasks.Compile.All do
9395

9496
## App loading helpers
9597

96-
defp load_apps(config, validate_compile_env?) do
98+
defp load_apps(config, lib_path, validate_compile_env?) do
9799
{runtime, optional} = Mix.Tasks.Compile.App.project_apps(config)
98100
parent = self()
99101
opts = [ordered: false, timeout: :infinity]
102+
deps = for dep <- Mix.Dep.cached(), into: %{}, do: {dep.app, true}
100103

101104
stream_apps(runtime ++ optional)
102-
|> Task.async_stream(&load_app(&1, parent, validate_compile_env?), opts)
105+
|> Task.async_stream(&load_app(&1, parent, deps, lib_path, validate_compile_env?), opts)
103106
|> Stream.run()
104107
end
105108

106-
defp load_app(app, parent, validate_compile_env?) do
109+
defp load_app(app, parent, deps, lib_path, validate_compile_env?) do
107110
children =
108-
case load_app(app, validate_compile_env?) do
111+
case load_app(app, deps, lib_path, validate_compile_env?) do
109112
:ok ->
110113
Application.spec(app, :applications) ++ Application.spec(app, :included_applications)
111114

@@ -143,14 +146,12 @@ defmodule Mix.Tasks.Compile.All do
143146
end
144147
end
145148

146-
defp load_app(app, validate_compile_env?) do
149+
defp load_app(app, deps, lib_path, validate_compile_env?) do
147150
if Application.spec(app, :vsn) do
148151
:ok
149152
else
150-
name = Atom.to_charlist(app) ++ '.app'
151-
152-
with [_ | _] = path <- :code.where_is_file(name),
153-
{:ok, {:application, _, properties} = application_data} <- consult_app_file(path),
153+
with {:ok, bin} <- read_app(app, deps, lib_path),
154+
{:ok, {:application, _, properties} = application_data} <- consult_app_file(bin),
154155
:ok <- :application.load(application_data) do
155156
if compile_env = validate_compile_env? && properties[:compile_env] do
156157
Config.Provider.validate_compile_env(compile_env, false)
@@ -163,10 +164,22 @@ defmodule Mix.Tasks.Compile.All do
163164
end
164165
end
165166

166-
defp consult_app_file(path) do
167+
# Optimize the ones coming from deps by avoiding code/erl_prim_loader
168+
defp read_app(app, deps, lib_path) when is_map_key(deps, app) do
169+
File.read("#{lib_path}/#{app}/ebin/#{app}.app")
170+
end
171+
172+
defp read_app(app, _deps, _lib_path) do
173+
name = Atom.to_charlist(app) ++ '.app'
174+
175+
with [_ | _] = path <- :code.where_is_file(name),
176+
{:ok, bin, _full_name} <- :erl_prim_loader.get_file(path),
177+
do: {:ok, bin}
178+
end
179+
180+
defp consult_app_file(bin) do
167181
# The path could be located in an .ez archive, so we use the prim loader.
168-
with {:ok, bin, _full_name} <- :erl_prim_loader.get_file(path),
169-
{:ok, tokens, _} <- :erl_scan.string(String.to_charlist(bin)) do
182+
with {:ok, tokens, _} <- :erl_scan.string(String.to_charlist(bin)) do
170183
:erl_parse.parse_term(tokens)
171184
end
172185
end

0 commit comments

Comments
 (0)