jeremyjh / dialyxir

Mix tasks to simplify use of Dialyzer in Elixir projects.
Apache License 2.0
1.7k stars 140 forks source link

Improve performance of algorithm to determine project deps #518

Closed dhedlund closed 1 year ago

dhedlund commented 1 year ago

Introduces smarter tracking of deps as they are loaded. These changes help to avoid traversing the same dep sub-trees multiple times. For larger projects, including umbrella projects, the same dep can be traversed millions of times.

One of our larger projects is an umbrella project with 20 umbrella apps and a little over 200 deps in our mix.lock file. With Elixir 1.15, the time it takes for dialyzer to complete increased 3x due to this issue, from 15 minutes in our CI to over 45 minutes. In order to get dialyxir working on Elixir 1.15, I also had to follow the advice in https://github.com/jeremyjh/dialyxir/issues/508 to add the dialyzer dep to each app in the umbrella. I'm not sure if that caused the increase in deps being returned, or if it's due to the new logic around optional apps.

The following table represents the time it takes to run the Dialyxir.Project.include_deps/0 function against that project on my local (faster than CI machine), and how many apps the function returns:

Elixir / OTP Version Branch Execution Time Num Apps Returned
elixir1.14.4-otp-25 / erlang 25.3.1 master 33.6s 16,845,380
elixir1.14.4-otp-25 / erlang 25.3.1 deps-tree-perf-improvements 0.02s 224
elixir 1.15.5-otp-26 / erlang 26.0.2 master 15m 51.8s 44,159,867
elixir 1.15.5-otp-26 / erlang 26.0.2 deps-tree-perf-improvements 0.19s 224
jeremyjh commented 1 year ago

Thanks!