llama.cppでデュアルのIntel Arc GPUを使っていて、マルチGPU推論中にシステムRAMが上限まで張り付く(モデルはVRAMに収まっているのに)場合、この投稿ではその理由と直し方を説明します。
私はllama.cppのSYCLバックエンドで、ローカルLLM推論のためにデュアルArc Pro B70(各32GB、合計64GBのVRAM)を動かしています。毎回、両方のGPUにモデルを分割しようとすると、私の64GBのシステムRAMが100%まで上がり、OOM killerがシステムをクラッシュさせるかログイン画面に落とされるまで、デスクトップのプロセスを次々に殺し始めました。これはあらゆるモデルサイズで起きました。15 GiBのQ4_K_Mモデルが、システムRAMを46 GiB食っていました。意味がわかりません。
調べてみると、これは設定の問題でも、VRAMの問題でもなく、モデルサイズとも関係ありません。llama.cppのSYCLバックエンドにある特定のAPI呼び出しが、Intelのxeカーネルドライバにおいて間違ったメモリ経路を引き起こしているのです。
実際に起きていること
SYCLバックエンドで sycl::malloc_device() を呼ぶたびに、xeカーネルドライバがDMA-buf/TTMステージング経由で、GPU確保領域の1:1ミラーをシステムRAM上に作成します。これは推論中ではなく、確保(allocation)時に発生します。GPU上に確保されるすべてのテンソル、すべてのKVキャッシュバッファ、すべての計算用スクラッチバッファが、システムRAMを同量ずつ消費していきます。
私は、的を絞ったテストでこれを確認しました:
| Allocation Method | 4 GiB on GPU | System RAM Impact |
|---|---|---|
sycl::malloc_device() | 4 GiB VRAM | +4,112 MiB system RAM |
zeMemAllocDevice() | 4 GiB VRAM | +8 MiB system RAM |
同じVRAM確保、同じGPU、同じドライバです。呼び出すAPIによって、システムRAM使用量が500倍も違います。
xeドライバには、デバイスメモリ用の内部カーネル経路が2つあります:
- DMA-buf/TTM - VRAMをシステムRAMにミラーします。これが
sycl::malloc_device()が引き起こす経路です。 - SVM/P2P - 直接PCIe BARアクセスで、ほぼシステムRAMを使いません。Level Zeroの
zeMemAllocDevice()が使う経路です。
SYCLカーネルは zeMemAllocDevice のポインタをゼロの問題なく読み取れます。完全な相互運用で、互換性の問題はありません。違いは裏側でどちらのカーネル経路がトリガーされるかだけです。
見覚えのある症状
- 2つのGPUにまたがってモデルをロードすると、モデルがVRAMに収まっているのにシステムRAMが100%まで上がる
- OOM killerがデスクトップのプロセス(pipewire, nautilus, wireplumber)を潰し始める
- システムが応答不能になったり、ログイン画面に落とされたりする
- スワップを追加すると「助かる」が、推論があまりに遅くなる
- 誰かに「デュアルGPUなら128GB RAMが必要だ」と言われた
- シングルGPUは問題なく動くが、デュアルGPUだとクラッシュする
対処方法
llama.cppのSYCLバックエンド全体で sycl::malloc_device() を zeMemAllocDevice() に置き換えてください。私は、自動フォールバック付きの集中管理(centralized)ヘルパ関数を書きました:
static void * ggml_sycl_malloc_device(size_t size, sycl::queue &q) { void *ptr = nullptr; try { auto ze_ctx = sycl::get_native<sycl::backend::ext_oneapi_level_zero>(q.get_context()); auto ze_dev = sycl::get_native<sycl::backend::ext_oneapi_level_zero>(q.get_device()); ze_device_mem_alloc_desc_t alloc_desc = {ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC}; ze_result_t r = zeMemAllocDevice(ze_ctx, &alloc_desc, size, 64, ze_dev, &ptr); if (r == ZE_RESULT_SUCCESS && ptr) return ptr; } catch (...) {} return sycl::malloc_device(size, q); // fallback } この修正は4つのファイルに及び、3つの確保(allocation)箇所と3つの解放(free)箇所を置き換え、ze_loaderにリンクします。何らかの理由でLevel Zeroの相互運用が利用できない場合でも、元の sycl::malloc_device の挙動に自動的にフォールバックします。
修正前と修正後
Q4_K_M(15.6 GiBモデル)、48Kコンテキスト、デュアルGPU:
| Metric | Before | After |
|---|---|---|
| Peak system RAM | 60,034 MiB (100%), OOM crash | ~6.7 GiB (10%), flat |
| Prompt processing | crash | 782 t/s |
| pp512 speed | 348 t/s | 359 t/s |
| tg128 speed | 17.92 t/s | 17.92 t/s |
Q8_0(26.6 GiBモデル)、32Kコンテキスト、デュアルGPU:
| Metric | Before | After |
|---|---|---|
| Peak system RAM | 100%, OOM crash | flat, no issue |
| Prompt processing | crash | 915 t/s |
システムRAMは、デュアルGPUテスト中ずっと約10%のままです。OOMなし、クラッシュなし、性能低下なし。出力はシングルGPUとデュアルGPUの間でバイト単位で完全に同一です(seed=42で検証済み)。
動かしてみたがダメだったこと
本当の原因を見つける前に、これらには何時間も費やしました。どれも問題を解決しません:
- IOMMUを無効化(GRUBで
iommu=off) - 効果なし - 直接SYCLのデバイス間memcpy(ホストのバウンスバッファを置き換え) - 転送は速くなるが、同じRAM使用量
- NEOのデバッグキー(
UseKmdMigration=0など) - 効果なし - cgroupメモリ制限 - TTMの確保はカーネル側で行われるため、プロセスのcgroupには課金されない
- PCIeルートポートのACSを無効化 - 効果なし
- Level Zero IPCハンドル(
zeMemGetIpcHandle) - これらもシステムRAMを消費する
唯一の解決策は、確保関数そのものを置き換えることです。
なぜNvidiaとAMDにはこの問題がないのか
CUDAとROCmには、カーネルの汎用DMA-buf経路を通らない独自のピアツーピアメモリ管理があります。Intelのxeドライバにはカーネル7.0以降で動作するP2P/SVM経路がありますが、sycl::malloc_device() はそれを使わず、古いDMA-bufエクスポート経路をトリガーしてしまいます。Intel自身のマルチGPU推論スタック(llm-scaler。vLLMを使う)では、Level ZeroのAPIを直接使うことでこの問題を回避しています。
システム情報
- 2x Intel Arc Pro B70(各32 GB、Battlemage/Xe2)
- AMD Ryzen 5 9600X、64 GB DDR5-4800
- Ubuntu 26.04、kernel 7.0.0-12-generic、xeドライバ、compute-runtime 26.09
- llama.cpp SYCLバックエンド(commit 69c28f1)
- AMD Radeon iGPUでディスプレイ表示、両方のB70は計算専用
- モデル:Qwen3.5-27B(Q4_K_M, Q5_K_M, Q6_K, Q8_0でテスト)
次にやること
私はこれをllama.cppへのPRとして提出する予定です。もしこの問題に遭遇していて、ローカルで直したいなら、完全なパッチとテストプログラムを共有する用意があります。
これは、llama.cppに限らずSYCLベースの推論エンジンでIntelのマルチGPUを使っている人に広く影響しているはずです。根本原因は、llama.cpp固有ではなく、SYCLの確保関数がxeドライバとどう相互作用するかにあります。
また、解決策を見つける前に初期の調査結果をX上に投稿しました。リアルタイムの調査を見たい場合はそちらをご覧ください。
[link] [comments]


