diff --git a/lib/mix/lib/mix.ex b/lib/mix/lib/mix.ex index 1812d8a9b6..bf17b11565 100644 --- a/lib/mix/lib/mix.ex +++ b/lib/mix/lib/mix.ex @@ -356,6 +356,9 @@ defmodule Mix do * `MIX_PATH` - appends extra code paths + * `MIX_PROFILE` - a list of comma-separated Mix tasks to profile the time spent on + functions by the process running the task + * `MIX_QUIET` - does not print information messages to the terminal * `MIX_REBAR3` - path to rebar3 command that overrides the one Mix installs diff --git a/lib/mix/lib/mix/cli.ex b/lib/mix/lib/mix/cli.ex index 6847645420..10b4eb2f41 100644 --- a/lib/mix/lib/mix/cli.ex +++ b/lib/mix/lib/mix/cli.ex @@ -10,6 +10,10 @@ defmodule Mix.CLI do if env_variable_activated?("MIX_QUIET"), do: Mix.shell(Mix.Shell.Quiet) if env_variable_activated?("MIX_DEBUG"), do: Mix.debug(true) + if profile = System.get_env("MIX_PROFILE", "") do + Mix.State.put(:profile, String.split(profile, ",")) + end + case check_for_shortcuts(args) do :help -> Mix.shell().info("Mix is a build tool for Elixir") diff --git a/lib/mix/lib/mix/task.ex b/lib/mix/lib/mix/task.ex index 8b901436be..b5a4b81c5b 100644 --- a/lib/mix/lib/mix/task.ex +++ b/lib/mix/lib/mix/task.ex @@ -492,14 +492,21 @@ defmodule Mix.Task do end defp with_debug(task, args, proj, fun) do - if Mix.debug?() do - shell = Mix.shell() - shell.info(["-> Running mix ", task_to_string(task, args), project_to_string(proj)]) - {time, res} = :timer.tc(fun) - shell.info(["<- Ran mix ", task, " in ", Integer.to_string(div(time, 1000)), "ms"]) - res - else - fun.() + cond do + Mix.debug?() -> + shell = Mix.shell() + shell.info(["-> Running mix ", task_to_string(task, args), project_to_string(proj)]) + {time, res} = :timer.tc(fun) + shell.info(["<- Ran mix ", task, " in ", Integer.to_string(div(time, 1000)), "ms"]) + res + + task in Mix.State.get(:profile, []) -> + shell = Mix.shell() + shell.info(["-> Profiling mix ", task_to_string(task, args), project_to_string(proj)]) + Mix.Tasks.Profile.Eprof.profile(fun, warmup: false, set_on_spawn: false) + + true -> + fun.() end end diff --git a/lib/mix/lib/mix/tasks/profile.eprof.ex b/lib/mix/lib/mix/tasks/profile.eprof.ex index 36cc259840..792b74e13e 100644 --- a/lib/mix/lib/mix/tasks/profile.eprof.ex +++ b/lib/mix/lib/mix/tasks/profile.eprof.ex @@ -181,6 +181,8 @@ defmodule Mix.Tasks.Profile.Eprof do * `:calls` - filters out any results with a call count lower than this * `:time` - filters out any results that took lower than specified (in µs) * `:sort` - sort the results by `:time` or `:calls` (default: `:time`) + * `:warmup` - if the code should be warmed up before profiling (default: `true`) + * `:set_on_spawn` - if newly spawned processes should be measured (default: `true`) """ @spec profile((-> result), keyword()) :: result when result: any() @@ -198,7 +200,8 @@ defmodule Mix.Tasks.Profile.Eprof do end :eprof.start() - {:ok, return_value} = :eprof.profile([], fun, Keyword.get(opts, :matching, {:_, :_, :_})) + matching = Keyword.get(opts, :matching, {:_, :_, :_}) + {:ok, return_value} = :eprof.profile([], fun, matching, Keyword.take(opts, [:set_on_spawn])) results = Enum.map(:eprof.dump(), fn {pid, call_results} ->