mlx-profiler
Operation-level profiler for Apple Silicon / MLX. The missing torch.profiler equivalent for the MLX ecosystem.
What it gives you
- Op-level timing — every
matmul,softmax,rms_norm, layer call, etc., measured individually - FLOPs estimation — multiply-add counts for matmuls, convolutions
- Arithmetic intensity — FLOPs/byte ratio per op (roofline model X-axis)
- Memory bandwidth estimate — tensor traffic through each operation
- Device attribution — GPU / CPU / Neural Engine breakdown
- Terminal report — human-readable ANSI table
- Interactive HTML dashboard — flame timeline, roofline scatter, searchable op table, category donut
- Trace persistence — save/load JSON, render HTML from CLI
Install
pip install mlx-profiler # without MLX (manual recording only)
pip install "mlx-profiler[mlx]" # with MLX for automatic interception
Quick start
import mlx.core as mx
import mlx.nn as nn
import mlx_profiler as mp
model = MyTransformer()
x = mx.random.normal([1, 512])
with mp.profile("my_model") as prof:
out = model(x)
mx.eval(out)
prof.report() # terminal output
prof.html("report.html") # interactive dashboard
prof.save("trace.json") # save for later
CLI
# Generate a demo trace + report
mlx-profiler demo
# View a saved trace in the terminal
mlx-profiler view trace.json
# Render HTML from a saved trace
mlx-profiler html trace.json -o report.html
Manual op recording (no MLX required)
from mlx_profiler.trace import Trace
from mlx_profiler.profiler import op_timer
import mlx_profiler as mp
trace = Trace("my_trace")
with op_timer(trace, "matmul",
input_shapes=[[512, 4096], [4096, 4096]],
output_shapes=[[512, 4096]],
dtype="float16"):
result = my_matmul(a, b)
mp.print_report(trace)
What's measured
| Op | FLOPs formula | Notes |
|---|---|---|
matmul / linear |
2·M·K·N | multiply-add counted as 2 ops |
conv2d |
2·Ho·Wo·Co·Ci·Kh·Kw | per batch element |
| All ops | input + output tensor bytes | memory bandwidth estimate |
Design notes
Why wall-clock, not Metal GPU timers?
Metal's MTLCommandBuffer.GPUStartTime gives you true on-chip execution time but requires you to instrument command buffers — not feasible when wrapping MLX's lazy evaluation model. Wall-clock with a forced mx.eval() boundary gives you "latency as the model experiences it", which is the number that matters for interactive applications. A future metal_backend module can add real GPU timers via Metal's performance counter API once the graph is materialized.
Lazy evaluation and timing
MLX uses lazy evaluation — operations aren't executed until mx.eval() is called. The profiler inserts mx.eval() calls at layer boundaries to force materialization and get accurate per-layer timing. This means profiling adds overhead; real-world timings will be slightly slower than unproduced runs.
Roadmap
- Metal GPU timestamp counters (true on-chip time)
- Neural Engine vs GPU attribution via
os_signpost - Continuous batching aware profiling
- Multi-pass aggregation (average over N forward passes)
- FlashAttention kernel detection
- TurboQuant / quantized op analysis
- Comparison mode: profile A vs profile B
License
MIT
Metadata
Release files for mlx-profiler 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| mlx_profiler-0.2.0.tar.gz | 17.8 kB | Without provenance | Details for mlx_profiler-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| mlx_profiler-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for mlx_profiler-0.2.0-py3-none-any.whl |
Total release size: 35.2 kB
Release files / mlx_profiler-0.2.0.tar.gz
| Download URL | mlx_profiler-0.2.0.tar.gz |
|---|---|
| Size | 17.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
167c0821ac031c60e3042c71b64a699a81df65701dd20b8f6da99e40a97716ac
|
|
BLAKE2b-256 checksum How to use checksums |
a947127ba394da64156894adf8ea08b7b3c5f46c8dd7f9b6562aceecb0a22f97
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Release files / mlx_profiler-0.2.0-py3-none-any.whl
| Download URL | mlx_profiler-0.2.0-py3-none-any.whl |
|---|---|
| Size | 17.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ad8462677ade7225342a4ebc85bc8e76501f11a7806fd7c7958888f14aa85d08
|
|
BLAKE2b-256 checksum How to use checksums |
1657ca67a9a8944f6c4afe847d976b7e8ba5c40a89bb1aa3e10f9efa7aad3c07
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Security for mlx-profiler 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.