# Tesla M60 4 GPUでのllama.cpp環境構築・運用ガイド

2026年10月15日時点の実稼働環境を基にした再構築資料です。モデルとソースを固定し、tensor分割・Q8 KV・262,144トークン上限で運用します。実測生成速度は約14.9 tokens/sです。

このフォルダーのソース差分とサービス定義を併せて利用してください。途中の試験設定ではなく、最終的に採用した構成を記載しています。

## 1. 実機構成

| 項目 | 確認した構成 |
|---|---|
| GPU | Tesla M60のGPU 4基。M60は1ボード2 GPUのため、GPU数とボード数を区別する |
| GPUアーキテクチャ | Maxwell、Compute Capability 5.2（sm_52） |
| VRAM | 物理8 GB/GPU、ECC有効。nvidia-smiでは7,680 MiB/GPU |
| GPU電力上限 | 150 W/GPU |
| GPU接続 | PCIe Gen3 x16。GPU 0–1、2–3はPIX、ペア間はPXB。NVLinkなし |
| CPU | Intel Xeon E5-2670 v3。コンテナーから利用できる論理CPUは8個 |
| メインメモリ | コンテナー割り当て16 GiB、Swapなし |
| 実行環境 | Proxmox上のLXC。ゲストはDebian 13（trixie）、確認時13.7 |
| ホスト共有カーネル | 7.0.14-16-pve |
| NVIDIAドライバ | 580.173.02 |
| CUDA Toolkit | 12.9、nvcc 12.9.86 |
| C/C++コンパイラー | GCC/G++ 13.3.0 |
| CMake | 3.31.6 |
| llama.cppベース | `b29c606e28a01b1bc8c1351026a0fa6e616bf6c4`（0.4.1系） |

LXCはホストのカーネルとGPUドライバを共有します。ホスト側でGPUを認識させ、コンテナーへ `/dev/nvidia0`〜`/dev/nvidia3`、`/dev/nvidiactl`、`/dev/nvidia-uvm` を公開し、対応するNVIDIAユーザー空間ライブラリを利用可能にします。デバイスのmajor番号や公開方法はホストに合わせて設定します。実機では `/dev/nvidia-caps` も見えています。

コンテナー内で4 GPUに対する `nvidia-smi` が成功し、CUDAアプリが実行できることを先に確認します。LXC内に別のカーネルドライバを導入する手順とは分けてください。ベアメタルでもllama.cppの設定は参考になりますが、同じ速度を保証するものではありません。

## 2. モデル

| 項目 | 使用ファイル |
|---|---|
| ファイル名 | `Qwen3.8-27B-Q4_K_M.gguf` |
| 配置先 | `/mnt/models/Qwen3.8-27B-Q4_K_M.gguf` |
| 正確なサイズ | 18,973,870,432 bytes（約17.67 GiB） |
| GGUF | version 3、851 tensors |
| メタデータ上のモデル名 | `Qwen3.8-27B` |
| メタデータ上のarchitecture | `qwen35` |
| メタデータ上のcontext_length | 262,144 |
| 重み量子化 | Q4_K_M、general.file_type=15 |
| ライセンスメタデータ | Apache-2.0 |

モデル本体は同梱していません。ダウンロード元は今回の調査では特定していないため、同名の別GGUFと混同しないよう、添付の `model.sha256` と `model-metadata.json` で識別します。モデルのarchitectureが`qwen35`なのは、実ファイルに記録されている値です。

重みのQ4_K_Mと、後述するKVキャッシュのQ8_0は別の設定です。

## 3. ソースとパッチ

公式リポジトリを上記コミットに固定し、同梱の `llama-cpp-b29c606-m60.patch` を適用します。この差分は稼働機の追跡対象ファイルの変更をまとめたもので、APIキーやSSH鍵、モデル本体は含みません。適用先は必ず未変更の指定コミットにしてください。

パッチの由来は [shinbunbun/llama-cpp-p100-patches](https://github.com/shinbunbun/llama-cpp-p100-patches) です。適用したと申告されている番号は次のとおりです。

`02 / 04 / 10 / 11 / 13 / 14 / 16 / 17 / 18 / 21 / 22 / 23 / 24 / 25 / 26 / 27`

番号だけではパッチのリビジョンや移植差分を固定できません。再現時はこの番号を現在の公開版から選び直すのではなく、**添付した実機の合成差分**を使います。19ファイル、2,378行追加・78行削除の変更です。稼働機上で逆適用のチェックが通ることを確認しています。`.orig`バックアップはビルドに不要なため含めていません。

主な変更対象は量子化行列ベクトル演算、CUDAカーネルの融合・コピー・インデックス処理、サンプラー、スケジューラー、gated delta-net関連処理です。P100向けという名称でも、FP16演算性能などM60には当てはまらない最適化があります。公開パッチ一式への置き換えは、この構成の再現にはなりません。

## 4. ビルド

CUDA Toolkit 12.9、GCC/G++ 13、CMake、Git、Ninjaを用意します。実機のNinjaは1.12.1です。`libcurl4-openssl-dev` と `libssl-dev` も導入されています。CUDA 13ではMaxwell向けコード生成が削除されているため、この構成はCUDA 12.xでビルドします。

主要なビルド設定は次のとおりです。指定コミットのソースを `/opt/llama.cpp-m60` に用意してから実行します。

```sh
git checkout b29c606e28a01b1bc8c1351026a0fa6e616bf6c4
git apply --check /path/to/m60-repro/llama-cpp-b29c606-m60.patch
git apply /path/to/m60-repro/llama-cpp-b29c606-m60.patch

cmake -S . -B build -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_C_COMPILER=/usr/bin/gcc-13 \
  -DCMAKE_CXX_COMPILER=/usr/bin/g++-13 \
  -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc \
  -DCMAKE_CUDA_HOST_COMPILER=/usr/bin/g++-13 \
  -DCMAKE_CUDA_ARCHITECTURES=52 \
  -DGGML_CUDA=ON -DGGML_CUDA_FA=ON \
  -DGGML_CUDA_GRAPHS=ON -DGGML_CUDA_NCCL=ON \
  -DBUILD_SHARED_LIBS=ON -DGGML_NATIVE=ON \
  -DGGML_OPENMP=ON -DLLAMA_OPENSSL=ON
cmake --build build --config Release -j 2
```

`/usr/local/cuda` は実機では `/usr/local/cuda-12.9` を指しています。CPUが異なる環境へバイナリをコピーするより、使用先でソースからビルドしてください。
ビルドの並列数は搭載RAMに合わせて調整します。上の例は16 GiB環境を考慮して2並列にしています。

Flash AttentionのKV型は、実機の既定設定 `q4_0-q4_0;q8_0-q8_0;f16-f16;bf16-bf16` を利用しています。`GGML_CUDA_FA_ALL_QUANTS=OFF` で、今回必要なQ8_0/Q8_0は含まれています。

次の2点は「設定がON」と「実際に使われる」を区別します。

- **CUDA Graph**：ビルドではONですが、この版の実装はVolta未満で無効化するため、M60では使われません。
- **NCCL**：実機ではビルド設定がONでも、NCCLのヘッダー・ライブラリはNOTFOUNDです。実行時はmeta backendのフォールバック通信を利用しています。今回の測定値はNCCLを使用した結果ではありません。再現時にもNCCLを新たに導入することは必須ではありません。

## 5. 採用パラメータ

| パラメータ | 値 | 採用理由・意味 |
|---|---|---|
| `CUDA_VISIBLE_DEVICES` | `0,1,2,3` | M60の4 GPUを利用 |
| `LLAMA_DEC_SLOTS` | `0` | #22のdecode graph slotsを無効化。tensor分割での連続要求時クラッシュを回避 |
| `GGML_CUDA_P2P` | **未設定** | この環境では有効化すると入力処理が停滞した |
| `--split-mode` | `tensor` | 各層を4 GPUに分割して同時に計算する |
| `--gpu-layers` | `999` | 全層GPU搭載を要求。実機では65/65層を搭載 |
| `--fit` | `off` | 自動調整を使わず、測定済みの配置・コンテキストを固定 |
| `--ctx-size` | `262144` | 最大コンテキスト上限 |
| `--cache-type-k` / `--cache-type-v` | `q8_0` / `q8_0` | KVのVRAM使用量を削減し、262k上限を確保 |
| `--flash-attn` | `on` | tensor分割と量子化Vキャッシュで必要 |
| `--parallel` | `1` | 単一系列の応答速度を重視。複数同時要求の性能は未測定 |
| `--threads` | `1` | 生成側CPUスレッド。8との比較で速度差が小さかった |
| `--threads-batch` | `8` | 入力処理側のCPUスレッド数 |
| `--batch-size` / `--ubatch-size` | `512` / `128` | 論理バッチとGPU処理用マイクロバッチ |
| `--host` / `--port` | `0.0.0.0` / `8080` | ネットワーク経由でAPIを提供 |
| API認証 | 無効 | 利用者が認証済みのネットワーク内で運用する前提 |

`GGML_CUDA_P2P` は値を`0`にするのではなく、環境変数を設定しません。この版は環境変数の存在で有効化する経路があるためです。

`LLAMA_DEC_SLOTS=0` はCUDA Graphの設定とは別です。既存パッチを削除せず、その機能だけを実行時に無効化しています。

## 6. 起動とsystemd

添付の `llama-server-m60.service` は、稼働機の元unitと2つのdrop-inを、現在有効な内容にまとめた再構築用の定義です。新規環境では `/etc/systemd/system/llama-server-m60.service` に配置し、systemdへ再読み込みして有効化・起動します。

稼働機には履歴上の元unitと `20-m60-performance.conf`、`30-no-api-auth.conf` が残っています。新規構築では添付の統合unitを使えば、古いlayer設定やAPIキー用EnvironmentFileを再作成する必要はありません。既存環境へ導入する場合は、残ったdrop-inが設定を上書きしないよう内容を確認してください。

モデルが別の場所にある場合は、unit内のモデルパス・`RequiresMountsFor`・`ReadOnlyPaths`を合わせます。CUDAやビルド先を変更する場合は、`WorkingDirectory` と `LD_LIBRARY_PATH`、実行ファイルのパスを合わせます。

手動起動で要点だけ確認する場合は、次の形です。

```sh
unset GGML_CUDA_P2P LLAMA_API_KEY LLAMA_API_KEY_FILE
export CUDA_VISIBLE_DEVICES=0,1,2,3
export LLAMA_DEC_SLOTS=0
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:/opt/llama.cpp-m60/build/bin

/opt/llama.cpp-m60/build/bin/llama-server \
  --model /mnt/models/Qwen3.8-27B-Q4_K_M.gguf \
  --host 0.0.0.0 --port 8080 \
  --split-mode tensor --fit off --gpu-layers 999 \
  --ctx-size 262144 --parallel 1 \
  --threads 1 --threads-batch 8 \
  --batch-size 512 --ubatch-size 128 \
  --cache-type-k q8_0 --cache-type-v q8_0 --flash-attn on
```

APIは `http://<サーバーのIP>:8080/v1` を接続先にします。稼働機は `http://192.168.22.232:8080/v1` です。認証ヘッダーは不要で、`/v1/models` と `/v1/chat/completions` のキーなしアクセスを確認済みです。クライアントがAPIキー入力を必須にしている場合、そのクライアントの仕様に応じて値を設定しても、サーバー側ではキー照合しません。

## 7. 動作確認の目安

起動時に、4 GPUが認識されること、Compute Capabilityが5.2であること、65/65層のGPU搭載が成功することを確認します。入力embeddingの `CPU_Mapped` バッファが約682 MiB残ること自体は、通常の層がCPUへ落ちたことを意味しません。

APIは次の順に確認すると、単発起動だけでなく今回発生した再利用時の問題も確認できます。

1. `/health` が正常を返す。
2. 認証ヘッダーなしで `/v1/models` が取得できる。
3. `/v1/chat/completions` で短い回答が生成できる。
4. **同じサーバープロセスへ複数回**リクエストして、2回目以降も成功する。
5. 数千トークンの入力でも生成が続き、VRAM不足やGPUエラーが出ない。

サンプリング設定は生成内容に影響するため、速度比較には同じ入力、生成トークン数、temperature、キャッシュ利用条件を使います。今回の測定はtemperature=0、seed=1234、prompt cache再利用なしで行いました。生成速度は応答の `timings.predicted_per_second` を使用しています。

## 8. 実測値

モデル・重み量子化は同じまま、分割方式とKVなどを変更した比較です。

| 構成 | 生成速度 | 備考 |
|---|---:|---|
| layer・262k・Q8 KV・threads=8 | 4.19〜4.29 t/s | 初回の基準測定。別の再測定では3.08〜3.57 t/sのばらつきあり |
| tensor・131k・F16 KV | 15.24〜15.25 t/s | 486トークン入力、128トークン生成、3回 |
| **tensor・262k・Q8 KV（現在）** | **14.89〜14.91 t/s** | 486トークン入力、128トークン生成、2回 |
| 現在設定・3,776トークン入力 | 14.50 t/s | 入力処理70.67 t/s、128トークン生成 |

現在設定のVRAM使用量は、測定時に各GPU約6,899 MiBでした。短い入力でのQ8 KVの速度低下は、131k/F16構成に対して約2%です。

262,144は確保したコンテキストの**上限**です。実際に262,144トークンを投入する試験、全面的な品質評価、perplexity評価、複数同時要求の試験は行っていません。簡単な計算・指定文字列コピー・連続要求の確認は通っています。

## 9. 採用しなかった設定と制約

| 設定・現象 | この環境での結果と対応 |
|---|---|
| tensor＋#22のdecode graph slots | 2回目の要求でmeta backendのassertion。`LLAMA_DEC_SLOTS=0`で回避 |
| `GGML_CUDA_P2P=1` | 入力処理が停滞。無効にして運用 |
| tensor・262k・F16 KV | KV用4,096 MiB/GPUの確保でVRAM不足。Q8 KVへ変更 |
| GPU使用率が各20〜25%のlayer分割 | 単一系列ではGPUが順番に動く。使用率が低いだけでは演算余力を意味しない |
| NCCL未導入の警告 | 今回の測定構成でも出る。警告だけでGPU不使用と判断しない |

**tensorとQ8 KVの併用は、この版ですでに利用できます。** 公式のmulti-GPU資料には未対応という古い記述が残っていましたが、実装は [PR #23792](https://github.com/ggml-org/llama.cpp/pull/23792) で対応済みです。これを有効にするためのバージョン更新や追加パッチは不要でした。#22との相性問題は、このQ8 KV対応とは別です。

参考: [llama.cpp](https://github.com/ggml-org/llama.cpp)、[shinbunbunのパッチ集](https://github.com/shinbunbun/llama-cpp-p100-patches)、[Q8 KVとtensorの対応PR](https://github.com/ggml-org/llama.cpp/pull/23792)、[M60製品仕様](https://images.nvidia.com/content/pdf/tesla/tesla-m60-product-brief.pdf)。
