defmodule Mix.Tasks.Firebird.Target.Profile do @moduledoc """ Profile the WASM compilation pipeline for source files. Shows detailed timing for each stage of the compilation pipeline, helping identify bottlenecks. ## Usage # Profile a specific file mix firebird.target.profile lib/wasm_modules/math.ex # Profile with optimizations mix firebird.target.profile lib/math.ex --optimize --tco # Profile WAT-only compilation mix firebird.target.profile lib/math.ex --wat-only # JSON output mix firebird.target.profile lib/math.ex --json ## Example Output ⏱ Compilation Profile File: lib/wasm_modules/math.ex Module: MyMath Status: ✅ Success read 12μs 0.3% parse 156μs 3.8% ir_gen 892μs 21.7% optimize 45μs 1.1% validate 23μs 0.6% type_infer 567μs 13.8% wat_gen 234μs 5.7% wat2wasm 2187μs 53.2% ██████████████████████████ Total: 4116μs """ use Mix.Task @shortdoc "Profile the WASM compilation pipeline" @switches [ optimize: :boolean, tco: :boolean, inline: :boolean, wat_only: :boolean, json: :boolean ] @impl Mix.Task def run(args) do {opts, paths, _} = OptionParser.parse(args, switches: @switches) if Enum.empty?(paths) do Mix.raise("Usage: mix firebird.target.profile [options]") end pipeline_opts = Keyword.take(opts, [:optimize, :tco, :inline, :wat_only]) json_mode = Keyword.get(opts, :json, false) Enum.each(paths, fn path -> unless File.regular?(path) do Mix.raise("File not found: #{path}") end {:ok, profile} = Firebird.Target.Profiler.profile_file(path, pipeline_opts) if json_mode do data = %{ file: profile.file, module: if(profile.module, do: to_string(profile.module)), result: profile.result, total_us: profile.total_us, timings: Enum.map(profile.timings, fn t -> %{ stage: t.stage, elapsed_us: t.elapsed_us, percentage: Float.round(t.percentage, 2) } end), error: if(profile.error, do: inspect(profile.error)), options: Enum.into(profile.options, %{}) } Mix.shell().info(Jason.encode!(data, pretty: true)) else Mix.shell().info(Firebird.Target.Profiler.format(profile)) end end) :ok end end