Skip to content

Latest commit

 

History

History
461 lines (315 loc) · 32.9 KB

File metadata and controls

461 lines (315 loc) · 32.9 KB

MetalGuard

English | 繁體中文 | 日本語

MLX 実行中の Mac をカーネルパニックから守る。

MetalGuard は、Apple Silicon 上の MLX 向け GPU セーフティレイヤーです。MLX モデルを動かすと、Apple の IOGPUFamily GPU ドライバーにあるバグが引き起こされ、プロセスが単に終了するのではなく Mac 全体がカーネルパニックして再起動します。MetalGuard はそのバグを誘発する条件をカーネルに達する前に捕捉します。

pip install metal-guard · 依存ゼロ · macOS / Apple Silicon · MIT

現在のバージョン:v1.1.0 — リリース履歴は CHANGELOG.md を参照してください。


MLX を実行中に Mac がカーネルパニックしましたか?

MLX モデルを動かしていたら Mac が突然再起動した。それはハードウェアの故障でも、あなたのミスでもありません — Apple の GPU ドライバーにある既知のバグです。対処法を最初から最後まで説明します:

1. Terminal を開く。 ⌘ + Space を押して Terminal と入力し、Enter を押します。

2. metal-guard をインストールする — 次の 1 行をコピーして Terminal に貼り付け、Enter を押します:

pip install metal-guard

依存ゼロなので数秒でインストールでき、パッケージ不足エラーになることはありません。

3. 実行する — 次を入力して Enter を押します:

metal-guard

metal-guard は Mac が書き込んだパニックレポートを読み取り、何が起きたかを平易な言葉で説明し、再発防止のためのワンライン保護をインストールするかどうか尋ねます。y と答えてください。

以上です。 次に MLX モデルが Mac をパニックさせようとしたとき、metal-guard は説明を表示してそれを止めます。

pip がない? pip は Python に付属しています。pip install metal-guardcommand not found と表示される場合は、まず python.org から Python をインストールして再試行してください。pipx も使えます:pipx install metal-guard


機能

  • パニックを診断する。 macOS のパニックレポートを読み取り、どの Apple ドライバーバグが原因かを特定し、カーネルログを解読しなくても分かる平易な言葉で説明します。
  • 次のパニックを防ぐ。 可逆的なシェルガードがリスクの高い MLX の実行をクールダウンチェックに通し、パニックを起こすことが知られているモデルはロード前にフラグを立てられます。
  • ダメージを封じ込める。 MLX を隔離されたサブプロセスで実行し、バグを誘発するレースウィンドウを狭め、再起動後にパニックループへ直行することを拒否します。
  • 邪魔をしない。 依存ゼロ、デフォルトは advisory モード、すべてのゲートにオフスイッチがあります。

MetalGuard は ワークアラウンドであり、根本的な修正ではありません — バグは Apple のドライバー内部にあり、修正できるのは Apple だけです。MetalGuard が行うのは、Mac を 「警告なしに再起動する」 状態から 「説明を表示して一時停止する」 状態へと変えることです。


問題

Apple Silicon の Metal GPU ドライバーにはバグがあり、GPU メモリ管理が失敗したとき、プロセスをきれいに終了する代わりに カーネルがマシン全体をパニックさせます

panic(cpu 4 caller 0xfffffe0032a550f8):
  "completeMemory() prepare count underflow" @IOGPUMemory.cpp:492

MLX モデルをシーケンシャルにロード・アンロードするワークフローはすべてこれを踏む可能性があります — ドライバー内部の参照カウントがアンダーフローしてマシンが再起動します。あなたのコードのせいではありません。 ドライバーレベルのバグで、修正の見通しもありません。ml-explore/mlx-lm#883 を参照してください。

ワークロード リスク 理由
単一モデルサーバー(LM Studio) 1 つのモデルのみ、切り替えなし
マルチモデルパイプライン load/unload の遷移ごとに panic の可能性
長時間稼働サーバー(mlx_lm.server KV cache が無制限に膨張、Metal バッファが蓄積
エージェントフレームワーク + tool calling 会話ごとに 50〜100 回の短い generate()
24/7 daemon 重大 日をまたいでメモリドリフト、自然なクリーンアップ地点がない
これらのエラー文字列を検索してここに来ましたか?あなたは正しい場所にいます。

MLX の実行中に Mac が panic / 再起動しており、以下のいずれかを検索した方のために MetalGuard は作られました:

IOGPUMemory.cpp:492 completeMemory() prepare count underflow · IOGPUMemory.cpp:550 kernel panic · kIOGPUCommandBufferCallbackErrorOutOfMemory · mlx::core::gpu::check_errorstd::terminateabort (SIGABRT) · mlx::core::metal::GPUMemoryAllocator / fPendingMemorySet · IOGPUGroupMemory.cpp:219 pending memory set panic · IOGPUGroupMemory::remove_memory_object memory object not found · mlx_lm.generate crashes mid-inference · mlx_lm.server OOM kernel panic / Mac reboot · com.apple.iokit.IOGPUFamily in a panic report · AGX_RELAX_CDM_CTXSTORE_TIMEOUT · GPU watchdog killing MLX on MacBook · M1 / M2 / M3 / M4 (Max / Ultra / Pro) kernel panic · long-context (≥ 65k) prefill triggers reboot · back-to-back MLX model loads cause IOGPU underflow panic.


インストール

metal-guard コマンドだけほしい

pip install metal-guard

これで metal-guardmlx-safe-python のコマンドラインツールが手に入ります。他の Python パッケージと隔離したい場合は pipx を使ってください:pipx install metal-guard

自分のコードでライブラリとして使う

pip install metal-guardmetal_guard Python パッケージもインストールされます:

import metal_guard as mg

verdict = mg.evaluate_panic_cooldown()
print(verdict.exit_code, verdict.reason)

開発 / テストを実行する

git clone https://github.com/Harperbot/metal-guard.git
cd metal-guard
pip install -e ".[test]"
pytest -q

インストールを確認する

$ metal-guard panic-gate
🟢 PROCEED  no recent IOGPU panics
  24h=0 72h=0

$ metal-guard status
metal-guard 1.1.0  🟢 OK
  mode    defensive — defensive mode (default)
  panics  0 in last 72h

インストール後に metal-guard が見つからない場合、pip --user の bin ディレクトリが PATH に含まれていない可能性があります — python3 -m metal_guard_cli panic-gate がフォールバックとして使えます。


metal-guard の使い方

コマンドライン

コマンド 機能
metal-guard 初回ウィザード:最近のパニックをスキャンし説明し、保護を提案する
metal-guard diagnose 最近のカーネルパニックをスキャンして説明する(変更なし)
metal-guard guard install 可逆的なシェルガードをインストールする(下記参照)
metal-guard guard uninstall / status シェルガードを削除 / 状態を報告する
metal-guard panic-gate クールダウン判定 — launchd / CI スクリプト向け
metal-guard status フルステータススナップショット
metal-guard postmortem <dir> panic 後の診断バンドルを収集する

シェルガード

metal-guard guard install はシェルの rc ファイル(~/.zshrc または ~/.bashrc)に区切り付きのブロックを 1 つ追加し、対話シェルの python / python3mlx-safe-python 経由にします。パニッククールダウンが有効な間は MLX の実行が自動的に一時停止され、そうでなければそのまま通過します。完全に可逆です — metal-guard guard uninstall でブロックをきれいに削除できます — また対話ターミナル(Terminal、iTerm、VS Code)のみに適用され、launchd ジョブやスクリプトには影響しません。アンインストールせず無効にするには:export METALGUARD_SHELL_GUARD_DISABLED=1

Python から使う

from metal_guard import metal_guard, require_cadence_clear, CircuitBreaker

# 連続ロードを拒否し、panic クラスター後の新規 worker も拒否する
require_cadence_clear("mlx-community/gemma-4-26b-a4b-it-4bit")
CircuitBreaker().check()

# GPU バウンドなスレッドを登録してクリーンアップが完了を待てるようにする
metal_guard.register_thread(thread)
metal_guard.wait_for_threads()

# 安全なアンロード、OOM 保護付き推論、ロード前のヘッドルームチェック
metal_guard.safe_cleanup()                                  # gc + flush GPU + cooldown
result = metal_guard.oom_protected(generate, model, tokenizer, prompt=p)
metal_guard.ensure_headroom(model_name="my-model-8bit")

ハードウェア対応のデフォルトを 1 行で:

config = MetalGuard.recommended_config()
metal_guard.start_watchdog(warn_pct=config["watchdog_warn_pct"],
                           critical_pct=config["watchdog_critical_pct"])

すべての API は下記のリファレンスに一覧されています。


metal-guard を自分のアプリに組み込む

MLX ベースのアプリ、サーバー、バックエンドを配布している場合、metal-guard を組み込むと、ユーザーは 自分で何もインストール・設定しなくても カーネルパニックから保護されます — 安全ツールを自力で見つけることのないユーザーに届く、最も確実な方法です。

1. 依存として追加する。 metal-guard はサードパーティのランタイム依存を一切持たないため、追加しても依存の衝突やビルドの破壊は起きません:

# pyproject.toml
dependencies = ["metal-guard>=1.1,<2"]

2. パニックしやすい遷移を守る。 上記の API でモデルのロード、アンロード、連続推論を囲みます — 最低でも、ロード前に require_cadence_clear()、アンロード後に metal_guard.safe_cleanup() を呼びます。

3. 大声で壊れず、安全に失敗する。 metal-guard のゲートはパニックでマシンを再起動させる代わりに型付き例外(例:SpawnRefusedMLXLockConflict)を送出します — それを捕捉して、API モデルへのフォールバックなど、優雅に縮退してください。

4.(任意)ユーザーにパニックを説明する。 再起動後、metal_guard.parse_panic_reports() を呼び、CLI と同じ平易な説明をユーザーに表示できます — 原因不明のクラッシュを、理解され処理されたイベントへと変えられます。

metal-guard はセマンティックバージョニングに従います。互換範囲を固定してください。


📋 コミュニティ panic モデルレジストリ — KNOWN_PANIC_MODELS

Apple Silicon Mac でカーネルパニックを引き起こす MLX モデルのコミュニティ共同リスト — ハードウェア文脈、根本原因の仮説、検証済みワークアラウンド付き。

Apple のドライバーバグには修正の見通しがありません。しかし どのモデルがどのワークロードでトリガーされるかはコミュニティが知り得ます — ただし現在は GitHub issue、LM Studio バグ報告、Discord スクリーンショット、誰も公開していない panic-full-*.panic ファイルに散在しています。MetalGuard はその知識のための構造化された置き場を提供します:

from metal_guard import check_known_panic_model, warn_if_known_panic_model

advisory = check_known_panic_model("mlx-community/gemma-4-31b-it-8bit")
if advisory is not None:
    print(advisory["recommendation"])
    # → "metal-guard narrows the race window but does NOT eliminate panic on
    #    this model. Switch backend (Ollama / llama.cpp) or pivot to an MoE variant."

warn_if_known_panic_model(model_id)   # fire-and-forget, per-process dedup

各エントリには panic_signature(一致させる正確な IOGPUMemory.cpp:NNN 行)、reproductions(ハードウェア / RAM / panic までの時間 / ワークロード)、community クロスリファレンス、実行可能な recommendationupstream issue リンクが含まれます。

metal-guard が完全に有効な状態で特定のモデルで panic が発生した? あなたのデータポイントは価値があります — Known Panic Model report を開いてください。レジストリは意図的に保守的です:エントリには確認済みの再現または明確な upstream issue が必要なので、正常なモデルが誤って blacklist されることはありません。

変動するターゲットのスナップショット

レジストリは 既知の panic モデルを記録しています — まだ誰も報告していないモデルは記録できませんし、各エントリはある時点までの観測を反映しています。レジストリにモデルが載っていないことは安全証明ではありません — 単にここで報告されていないというだけです。リストにないローカルモデルを動かしたい場合は、まず自分のハードウェアとワークロードでテストしてください。パニックした場合は 報告してください

panic の状況は逆方向にも変動します。root バグは upstream にあり、upstream は静止していません — 最近の MLX リリースにはすでに mitigation(例:mlx#3348、スレッドローカルな CommandEncoder)がマージされており、将来の MLX または macOS リリースでバグが完全に修正される可能性もあります。その際、レジストリエントリの「バックエンドを切り替えて」というアドバイスは不要になります — metal-guard の check_version_advisories() と observer モード(METALGUARD_MODE=observer、修正済み MLX ランタイムがインストールされたあとに防御層を緩和する)がそれを追跡する手段です。レジストリとこれらのアドバイザリは 時点スナップショットであり、永続的な判断ではない と捉えてください — 実際に動かす MLX と macOS のバージョンに対して再確認してください。


リファレンス

MetalGuard は 防御レイヤー(L1〜L13) として構成されています — 多層防御のオニオン構造:L1〜L8 は実行中のレースウィンドウを狭め、L9 + L11 はカーネルレベルの abort 直前に短絡し、L10 + L12 は panic + 再起動後の回復を扱い、L13 はすべてを JSON スナップショットとして公開します。各レイヤーがいつ追加され、どの事例が動機だったかは CHANGELOG.md を参照してください。

L1 — スレッド追跡

Metal を触るスレッドを登録しておき、mx.clear_cache() を呼ぶ前に GPU 作業の完了を待てるようにします。

API 機能
metal_guard.register_thread(thread) GPU バウンドスレッドをレジストリに追加する
metal_guard.wait_for_threads(timeout=None) -> int 登録済みスレッドが終わるまでブロック;残存数を返す

L2 — 安全なクリーンアップ

「メインスレッドが解放した buffer をワーカースレッドがまだ使っている」という元祖 panic 根因の競合を避ける、順序付きクリーンアップ。

API 機能
metal_guard.flush_gpu() mx.eval(sync) + mx.clear_cache()wait_for_threads() の後でのみ安全
metal_guard.safe_cleanup() 完全シーケンス:wait → gc.collect → flush → cooldown
metal_guard.guarded_cleanup() 終了時に safe_cleanup() を実行するコンテキストマネージャ
kv_cache_clear_on_pressure(available_gb, growth_rate_gb_per_min) KV モニタ向けの既製 on_pressure コールバック

L3 — OOM 回復

生の C++ Metal OOM を、自動クリーンアップと任意のリトライ付きで catch 可能な Python 例外に変換します。

API 機能
metal_guard.oom_protected(fn, *args, max_retries=1, **kwargs) OOM catch → cleanup → retry で実行する
metal_guard.oom_protected_context() コンテキストマネージャ版
metal_guard.is_metal_oom(exc) -> bool 任意の例外を分類する
MetalOOMError MemoryStats 付きの catch 可能な例外

L4 — ロード前メモリチェック

収まらないロードを拒否し、HF model ID からモデルサイズを推定します。

API 機能
metal_guard.can_fit(model_size_gb, overhead_gb=2.0) -> bool 例外を投げないチェック
metal_guard.require_fit(model_size_gb, model_name, overhead_gb=2.0) クリーンアップしてもまだ入らなければ MemoryError を raise
MetalGuard.estimate_model_size_from_name(name) (static) 名前からパラメータ数 + 量子化を解析して GB 推定

L5 — 長時間稼働の安全装置

mlx_lm.server、エージェントフレームワーク、24/7 daemon 向け。

API 機能
metal_guard.memory_stats() -> MemoryStats スナップショット(active / peak / limit / available / pct)
metal_guard.is_pressure_high(threshold_pct=67.0) -> bool 簡易圧力チェック
metal_guard.ensure_headroom(model_name, threshold_pct=67.0) 圧力が高ければクリーンアップ、そうでなければ no-op
metal_guard.start_watchdog(interval_secs, warn_pct, critical_pct, on_critical) エスカレーション応答付きのドリフト watchdog
metal_guard.start_kv_cache_monitor(interval_secs, headroom_gb, growth_rate_warn, on_pressure) KV 成長モニタ、OOM の前に発火
bench_scoped_load(model_id, ...) 連続ベンチマーク用コンテキストマネージャ — 次のロード前にアンロードを保証

L6 — デュアルモードスイッチャー

上流の mitigation を A/B テストするためにコード変更なしで defensive / observer を切り替え可能。

API 機能
current_mode() -> str "defensive"(デフォルト)または "observer"
is_defensive() / is_observer() -> bool 便利な判定述語
describe_mode() -> dict モード名、説明、環境変数

L7 — サブプロセス隔離

新しい multiprocessing 子プロセスで MLX を実行し、カーネルレベルの abort が親プロセスを殺せないようにします。

API 機能
MLXSubprocessRunner(model_id, ...) 永続 worker サブプロセス、クラッシュ時は再生成
call_model_isolated(model_id, prompt, ...) 単発ヘルパー:spawn → generate → シャットダウン
shutdown_all_workers() 終了時に追跡中の全 runner を強制停止
SubprocessCrashError / SubprocessTimeoutError 呼び出し側向けの型付き失敗
SpawnRefused モデルの advisory tier が panic のとき runner 構築時に raise(上書き:METALGUARD_LOCAL_PANIC_MODEL_BLOCK_DISABLED=1

L8 — クロスプロセス相互排他

MLX_LOCK_PATH 下のファイルロックで、bench / server / pipeline が同一マシン上で同時に Metal を初期化しないようにします。

API 機能
acquire_mlx_lock(label, force=False) 保有中なら MLXLockConflict を raise;force=True は保有者に SIGTERM + タイムアウト + cooldown
release_mlx_lock() -> bool このプロセスが保有していれば解放
read_mlx_lock() -> dict | None ノンブロッキング検査;stale + zombie を自動修復
mlx_exclusive_lock(label) コンテキストマネージャ:enter で取得、exit で解放

L9 — Cadence、panic ingest、circuit breaker

前 8 レイヤーの後の最終防衛線 — SIGABRT レイヤーの にあったカーネルパニックへの対応として書かれました:Python が何かを目にする前にマシンはすでに再起動していました。唯一の対策は最初からトリガーを避けることです。

API 機能
CadenceGuard(path=None, *, min_interval_sec=180) 永続化されたモデル別ロードタイムスタンプストア
require_cadence_clear(model_id, *, min_interval_sec=180) アトミックな check + mark;最近のロードがあれば CadenceViolation を raise
parse_panic_reports(directory=None, *, since_ts=None) macOS パニックレポートをスキャン(/Library/Logs/DiagnosticReports/var/db/PanicReporter~/Library/....panic + .ips)して分類
ingest_panics_jsonl(*, report_dir=None, jsonl_path=None) -> int ~/.cache/metal-guard/panics.jsonl に重複排除して追記
CircuitBreaker(*, window_sec=3600, panic_threshold=2, cooldown_sec=3600) panic クラスター後に新規 worker を拒否
detect_panic_signature(text) -> (name, explanation) panic ログを分類:prepare_count_underflow / pending_memory_set / remove_memory_object / ctxstore_timeout / metal_oom

L10 — Panic cooldown gate

カーネルパニック + 再起動後、launchd は約 14 分後に plist を自動 respawn します — そして次の MLX ワークロードがすぐに同じバグを再トリガーする可能性があります。L10 は macOS のパニックレポートを読み取り、階段状の cooldown を適用します(1 panic → 2h;24h 以内に ≥2 または 72h 以内に ≥3 → 明示的な ack が必要な lockout)。

API 機能
evaluate_panic_cooldown() -> CooldownVerdict stdlib のみの評価;verdict.exit_code ∈ {0=進行, 2=cooldown, ≥3=gate 故障}
scan_recent_panics(hours=72.0) -> list[PanicRecord] AND パターン IOGPU panic スキャン
ack_panic_lockout() アクティブな lockout を解除
metal-guard panic-gate / metal-guard ack launchd スクリプト向け CLI ラッパー

環境変数:METALGUARD_PANIC_COOLDOWN_STAGE1_H / _LOCKOUT_24H_N / _LOCKOUT_72H_N / _LOCKOUT_MAX_H / _GATE_DISABLED=1

L11 — Subprocess orphan monitor

パニック前シグナル:SUBPROC_PRE ブレッドクラムに対応する SUBPROC_POST が 90 秒後もない場合、Metal がスタックしている強い示唆です — カーネルより先に worker を kill します。

API 機能
scan_orphan_subproc_pre(threshold_sec=90.0) -> list[OrphanPre] ブレッドクラムテールの FIFO ペアリングによる PRE↔POST スキャン
metal-guard orphan-scan [--threshold-sec N] CLI ラッパー

L12 — Postmortem auto-collect

panic + 再起動後、診断バンドルを 1 つのディレクトリに収集します:panic ファイル(上限あり)、ブレッドクラムログのテール、panics.jsonl 履歴、mx.metal 統計、index.md サマリ — そして L10 がパニックレポートのローテーション後も実行を遅延させるようにセンティネルクールダウンを書き込みます。

API 機能
run_postmortem(output_dir) -> dict フルオーケストレーション;パス + panic 数を返す
metal-guard postmortem <output_dir> CLI ラッパー(kill-switch:METALGUARD_POSTMORTEM_DISABLED=1

L13 — Status snapshot

metal_guard を直接 import すべきでないクロスプロセス消費者(メニューバーアプリ、ダッシュボード、ssh インスペクション)向けのバージョン管理 JSON スナップショット。

API 機能
get_status_snapshot(*, include_panics=True, breadcrumb_lines=20) -> dict メモリ / KV モニタ / panics / lock 保有者 / mode / L10 verdict を集約
write_status_snapshot(out_path=None) ~/.cache/metal-guard/status.json へアトミック書き込み
metal-guard status-write [--once | --interval 30] CLI / daemon ラッパー

ハードウェア認識、アドバイザリ、監査

API 機能
MetalGuard.detect_hardware() -> dict (static) チップ、GPU メモリ、推奨ワーキングセット、tier、IOGPUFamily kext バージョン
MetalGuard.recommended_config() -> dict (classmethod) 検出されたハードウェアに対するすべてのレイヤーの安全デフォルト
check_version_advisories(packages=None) -> list[dict] インストール済みの (mlx, mlx-lm, mlx-vlm, transformers) バージョンが既知のアドバイザリに該当すれば警告
install_upstream_defensive_patches(force=False) -> dict[str, bool] Idempotent、バージョンゲート付きの upstream 回帰に対する monkey-patch
audit_wired_limit() -> dict 危険な iogpu.wired_limit_mb オーバーライドをフラグ立て(mlx-lm#1047)
read_gpu_driver_version() -> str | None IOGPUFamily kext バージョン(mlx#3186)

R シリーズ予防ヘルパー & フォレンジクス

API 機能
lookup_dims(model_id) / estimate_prefill_peak_alloc_gb(...) / require_prefill_fit(...) GQA 対応 prefill 上限 — 30 GB 単発確保 panic の前に拒否
recommend_chunk_size(...) / describe_prefill_plan(...) アドバイザリ的な prefill チャンク分割
KVGrowthTracker(...) リクエスト別累積 KV ガード — グローバルモニタが見逃す暴走リクエストを捕捉
detect_process_mode() -> ProcessMode "server" / "embedded" / "notebook" / "cli" / "subprocess_worker"
format_panic_for_apple_feedback(forensics, ...) Apple Feedback Assistant にそのまま貼り付けられるレポート
metal_guard.breadcrumb(msg) fsync 済みのブレッドクラムログに書き込む

デフォルトパス

L9 のすべての成果物は ~/.cache/metal-guard/ 配下です:cadence.json(CadenceGuard)、panics.jsonl(panic アーカイブ)、breaker.json(CircuitBreaker)、status.json(L13 スナップショット)。ブレッドクラムログのデフォルトは logs/metal_breadcrumb.logMetalGuard(breadcrumb_path=...) で上書き可能。

アーキテクチャ

┌─────────────────────────────────────────────────┐
│            Your Application Code                │
│  Agent loop / Server / Pipeline / Daemon        │
└──────────────────┬──────────────────────────────┘
┌──────────────────▼──────────────────────────────┐
│              MetalGuard                         │
│  L9  Cadence + CircuitBreaker  refuse bad loads │
│  L8  Process lock              cross-process    │
│  L7  Subprocess isolation      panic-isolated   │
│  L5  Watchdogs                 drift alerts     │
│  L3  OOM recovery              catch + retry    │
│  L2  Safe cleanup              gc + flush       │
│  L1  Thread registry           wait before free │
│  L10–L13  cooldown / postmortem / status        │
└──────────────────┬──────────────────────────────┘
┌──────────────────▼──────────────────────────────┐
│           MLX + Metal Driver                    │
│  ⚠️  Driver bug: panics instead of OOM          │
└─────────────────────────────────────────────────┘

MetalGuard で足りないとき

すべての防御を有効にしても同じモデルで repeat panic が続く場合、レースウィンドウは userspace レイヤーで狭められる以上に広いです。投資対効果順に 2 つのエスケープハッチ:

  1. バックエンドを切り替える。 Ollamallama.cpp は内部で Metal を使いますが、persistent-worker アーキテクチャなのでサブプロセス teardown の競合を丸ごと回避します。失うのは生スループット;得るのは「マシンを panic させない」こと。
  2. MoE モデルに pivot する。 Mixture-of-Experts 変種(例:mlx-community/gemma-4-26b-a4b-it-4bit)は 1 回の forward あたり active パラメータが小さく、KV トレジェクトリも狭いです。コミュニティの報告は「同じエコシステム内で最も確実な回避策は MoE」で一致しています。

MetalGuard は両方と補完的です — CadenceGuard はモデルをホットスワップする限り依然として有効です。

経験で学んだ SOP の注意点。 torchmlxmlx_lmmlx_vlmsentence_transformerstransformersdiffusersaccelerate のいずれかを import するものは Metal バックエンドを初期化し、同じカーネルバグを踏む可能性があります — 対話的なバージョン確認コマンドでさえも。アクティブなクールダウン中は pip show <pkg> または python -c "import importlib.metadata as m; print(m.version('<pkg>'))"を使い;絶対に python -c "import <ml-package>; print(<ml-package>.__version__)" を実行しないでください。


制限事項 — これはワークアラウンドであり、修正ではありません

root バグは Apple の IOGPUFamily kext(mlx#3186)内部にあり、Python からはパッチできません。MetalGuard が行うのは トリガー率の低減(既知のトリガー経路を回避)、爆発半径の封じ込め(サブプロセス隔離)、再起動後カスケードの防止(CircuitBreaker)です。パニックを排除するものではありません — 特に捕捉できない completion-handler abort(mlx#3390)は Python のシグナルハンドラが発火する前に起きます。あるプロダクションマシンでは L9 導入後 24 時間で約 1.4 panics/day からゼロになりましたが、それはリスク低減であり、排除ではありません。Apple が修正済みの kext を出荷するまで、これが Python サイドのレイヤーで達成できる上限です。

関連する upstream issue

Issue 問題 レイヤー
mlx#3186 IOGPUFamily kernel panic(標準) L1/L2/L8/L9
mlx#3346 fPendingMemorySet 第二シグネチャ detect_panic_signature + L9
mlx#3348 CommandEncoder thread-local(マージ済み) アドバイザリゲートによる observer モード
mlx#3390 捕捉不能な completion-handler abort L7 サブプロセス隔離
mlx-lm#883 KV cache 成長によるカーネルパニック L1 thread + L2 safe cleanup
mlx-lm#854 サーバー OOM クラッシュ L3 oom_protected + L5
mlx-lm#1047 wired_limit と panic の相関 audit_wired_limit

ライセンス

MIT