Runtime call-tracing utility. Wraps :erlang.trace_pattern/3 and
:erlang.trace/3 to capture the set of {module, function, arity}
actually called during a function's execution.
Used by the characterization harness (priv/trace/harness.exs) to
empirically map what Elixir's runtime calls under the hood — the
baseline that complements MobDev.OtpAudit's static analysis.
Why this exists
Static reachability misses dynamic dispatch (apply/3 with a
computed atom, Code.ensure_loaded/1, NIF lazy load via
:erlang.load_nif/2). Tracing catches everything that actually
ran during the trace window — ground truth, no inference.
Combined with static analysis: static ∪ trace gives a high-confidence
reachable set; static ∩ trace is the "definitely called and
statically reachable" core.
Usage
result = MobDev.OtpTrace.capture(fn ->
# any Elixir code — exercise features you want to measure
Enum.map(1..10, &(&1 * 2))
end)
result.mfas # MapSet of {module, function, arity}
result.modules # MapSet of modules called
result.elapsed_us # How long the wrapped fn took (incl. trace overhead)Trace overhead is real (~10x slowdown for tight loops) — only enable for measurement runs, never in production.
Summary
Functions
Run fun with full call tracing enabled on the calling process and
any processes it spawns during execution. Returns a result/0 map.
Types
Functions
Run fun with full call tracing enabled on the calling process and
any processes it spawns during execution. Returns a result/0 map.
Options
:exclude_modules— modules whose calls should NOT be recorded. Defaults to[__MODULE__, MobDev.OtpTrace.Collector, Agent, Task]so we don't pollute the trace with our own machinery.