Python CLI tool to profile CoreML model compute device assignments (CPU/GPU/ANE) and latency.
Uses PyObjC to call CoreML framework APIs (both public and private/reverse-engineered).
Managed by uv. Entry point: coreml-cli = "coreml_cli.cli:app".
uv run coreml-cli <model>— benchmark: latency, compile time, device % across all compute unit configsuv run coreml-cli <model> --fallback— ANE optimization: show CPU fallback ops grouped by rejection reasonuv run coreml-cli <model> --fallback --json— structured fallback analysis for agent parsinguv run coreml-cli <model> --json— full benchmark as JSONuv run coreml-cli <model> --ops— include per-operation breakdownuv run coreml-cli <model> --detailed— private API data per op (implies --ops)uv run coreml-cli <model> --debug— progress logs to stderruv sync— install/update dependencies
cli.py— Typer CLI, wiring, merge logiccompute_plan.py— Public MLComputePlan API (device assignment + cost per op)private_profiler.py— Private MLE5Engine API (backend support, estimated runtimes)fallback.py— Analyze CPU fallback ops, group by ANE rejection reasonlatency.py— Prediction timing via PyObjC MLModel (5 warmup + N iterations)metadata.py— Model metadata from metadata.json + MLModel descriptionmodel_loader.py— Discover .mlmodelc/.mlpackage, compile via coremltoolsoutput.py— Table (default), fallback table, and JSON formatters
CoreML enum values differ from older macOS. NEVER hardcode enum ints.
Use framework constants: CoreML.MLComputeUnitsAll, CoreML.MLFeatureTypeMultiArray, etc.
Example: MLComputeUnitsCPUOnly=0 on macOS 26 vs 1 on older versions.
MLComputePlanhas no sync class method — use asyncloadContentsOfURL_configuration_completionHandler_with threading.Eventop.outputs()returns NSArray of MLModelStructureProgramNamedValueType, not a dict — useoutputs[0].name()MLMultiArray.dataPointer()returnsobjc.varlist, not int — usesetObject_atIndexedSubscript_to fill valuessegmentationAnalyticsAndReturnError_returns single value (not tuple) — don't unpackSelectedBackendfrom private API has embedded quotes like'"bnns"'— strip themMLModelConfiguration.setExperimentalMLProgramEncryptedCacheUsage_(0)bypasses the E5 on-disk compilation cache (used for cold compile measurement). The ANECompilerService daemon also caches in memory — for true first-launch timing, restart it:sudo killall ANECompilerService
- Agent-first: table output default,
--jsonfor structured. No rich/colorama. - stdout = data only, stderr = debug logs (gated by
--debug) - Suppress CoreML system logs via
OS_ACTIVITY_DT_MODE=disableunless debugging - Operations list excluded by default (too verbose) — opt-in via
--ops - Errors raise exceptions, don't print-and-continue
test_models/160ms/ — downloaded from HuggingFace FluidInference/parakeet-realtime-eou-120m-coreml
Contains: decoder.mlmodelc, joint_decision.mlmodelc, streaming_encoder.mlmodelc