Skip to content

M18: observability & fallback telemetry - #35

Merged
ausimian merged 1 commit into
mainfrom
m18-telemetry
Apr 18, 2026
Merged

M18: observability & fallback telemetry#35
ausimian merged 1 commit into
mainfrom
m18-telemetry

Conversation

@ausimian

Copy link
Copy Markdown
Owner

Summary

  • Adds :telemetry spans at the evaluation boundary ([:emily, :eval, *], [:emily, :to_binary, *]) and at every Nx.BinaryBackend fallback ([:emily, :fallback, *]).
  • New Emily.Telemetry module enumerates every event and exposes memory_stats/0 for allocator polling.
  • Opt-in one-shot Logger.warning per {op, input_shapes} when a fallback fires. Off by default — the telemetry event fires regardless, the log is a dev-time convenience. Enable with config :emily, :warn_on_fallback, true.

Motivation

Whisper-before-M8 spent 90% of forward-pass time on a BinaryBackend round-trip with no signal. The same class of bug will keep happening as ops rotate on/off via_binary; M18 makes it observable.

Design notes

  • "Each Native dispatch" from PLAN.md is implemented as the evaluation boundary, not per-op graph-construction instrumentation. MLX is lazy, graph-construction NIFs are <10µs and do no work, and wrapping 300+ Backend call sites would add noise without producing a useful histogram. Documented in both the plan and the PLAN.md Shipped block.
  • Warning default false chosen after observing that the test suite intentionally exercises many fallback paths (backend_fallbacks_test.exs, window property tests, cumulative fallbacks). Default-on would mean CI logs and every dev's first Nx.to_binary call spray warnings unsolicited. Default-off lets library consumers stay quiet and opt in when chasing a perf regression.
  • Op-name plumbing: via_binary/3/4, via_binary_tuple/3/4, apply_scatter/7/8. All ~7 call sites updated.
  • Dedup state: named :public ETS table owned by Emily.Application, created before the supervisor starts. No GenServer on the hot path.

Test plan

  • mix precommit green (1 doctest, 76 properties, 406 tests, 0 failures)
  • test/emily/telemetry_test.exs: fallback event metadata, 100-call dedup assertion, default-silent behaviour, to_binary span metadata, memory_stats/0 emission
  • CI log output: no unsolicited warnings with default config

Follow-ups (out of M18 scope)

  • Compile-time debug assertions (bounds-check gather/scatter, NaN/Inf detection) — tracked separately in #32. Related to M18 in spirit (both surface silent failures) but distinct in mechanism (opt-in compile flags vs. always-on telemetry) and failure mode (correctness vs. observability).

Makes silent `via_binary` round-trips and long-running memory drift
observable. The canonical motivator is Whisper-before-M8, which spent
90% of forward-pass time on a BinaryBackend round-trip with no signal.

- Emily.Telemetry: new module; moduledoc enumerates every event,
  memory_stats/0 samples the MLX allocator, maybe_warn_fallback/2
  handles the opt-in dev warning.
- Span events via :telemetry.span/3 at [:emily, :eval, *],
  [:emily, :to_binary, *] (with shape/dtype/byte_size metadata), and
  [:emily, :fallback, *] (with op/input_shapes/input_dtypes).
- One-shot Logger.warning per {op, input_shapes} pair, off by default.
  Enable with `config :emily, :warn_on_fallback, true` — typically in
  config/dev.exs when chasing perf regressions. The telemetry event
  fires regardless.
- via_binary/3 → /4 + tuple variant take an op-name atom; all call
  sites + apply_scatter threaded through.
- Dedup state lives in a :public :named_table ETS set owned by
  Emily.Application, created before the supervisor starts.

"Each Native dispatch" from PLAN.md is implemented as the evaluation
boundary (eval / to_binary), not per-op graph-construction
instrumentation: MLX is lazy, graph-construction NIFs are <10µs and
do no work, and wrapping 300+ sites would add noise for no histogram
anyone wants. If per-op events are ever needed, the right answer is
a centralised dispatch helper, not per-callback decoration.

Tests cover fallback metadata, 100-call dedup, default-silent
behaviour, to_binary span metadata, and memory_stats/0 emission.
@ausimian
ausimian merged commit fa43331 into main Apr 18, 2026
1 check passed
@ausimian
ausimian deleted the m18-telemetry branch April 18, 2026 04:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant