GPU とサービング指標 — DCGM が語ること、語らないこと
一言でいうと
GPUメトリクスで最もよく間違える判定は、「このカードはアイドルだ」です。使用率は0なのに、メモリ13.7 GiBを確保しているカードを、どちらに数えるべきか。答えは、メトリクス1つではなく、使用率・メモリ・電力をウィンドウ全体であわせて見ることです。
なぜ必要なのか
GPUは高価で、なかなか増やせません。そのため、「何枚必要か」を判定する場面がよくありますが、このとき、ダッシュボードの使用率だけを見ると、必ず間違えます。このクラスターの実測が、その例です。
計算は本当にしていません。ところが、その13.7 GiBは、他のワークロードが使えません。カードがアイドルでも、場所は空いていません。この状態を「アイドルのGPU」として数えると、容量計画が間違い、「使っているGPU」として数えると、無駄を見つけられません。両方を書く必要があります。
どう動くのか
dcgm-exporterは、DCGMライブラリのフィールドを、そのままメトリクスとして出力します。よく使うものは次のとおりです。
| メトリクス | 種類 | 単位・意味 |
|---|---|---|
DCGM_FI_DEV_GPU_UTIL |
gauge | GPU使用率(%) |
DCGM_FI_DEV_FB_USED・FB_FREE |
gauge | フレームバッファーの使用・空き(MiB) |
DCGM_FI_DEV_POWER_USAGE |
gauge | 電力(W) |
DCGM_FI_DEV_TOTAL_ENERGY_CONSUMPTION |
counter | 累積エネルギー(mJ) |
DCGM_FI_DEV_SM_CLOCK |
gauge | SMクロック(MHz) |
DCGM_FI_PROF_SM_ACTIVE |
gauge | ワープが載っていた時間の割合(デフォルトは無効) |
エネルギーがカウンターだという点が興味深いところです。rate(...[30m]) / 1000で微分するとワットが出て、同じ時刻のPOWER_USAGEゲージと比べると、ほぼ同じ値になります(実測: 54.7 W対55.3 W)。同じものを、カウンターでもゲージでも測れることを、目で確認できる貴重な場面です。
GPU_UTILについて、DCGMの公式のフィールドの説明は、「GPU Utilization.」の一行だけです。何をどう測るのかをもっと知りたければ、プロファイリングのメトリクスを見る必要があります。公式ドキュメントは、PROF_SM_ACTIVEを「少なくとも1つのワープがSMに載っていた時間の割合を、すべてのSMについて平均した値」と定義し、「ここでactiveは、必ずしも計算中を意味しない。メモリのリクエストを待っているワープもactiveとして数える」と付け加えています。カーネル1つがGPUの5分の1しか使っていなくても、使用率が100%に見えることがある理由が、ここにあります。ただし、このexporterのデフォルトの設定では、PROF_*は無効になっており、データセンター級(Volta以上)という制限もあります。
帰属(attribution)ラベルは保証されません。dcgm-exporterは、kubeletに問い合わせてexported_namespace・exported_pod・exported_containerを付けてくれますが、ノードの構成によっては、このラベルがまるごと空になることがあります。このクラスターでも、4枚のうち1枚がそうです。帰属のないGPUは、「誰が使っているのかわからないリソース」であり、コストの配分と回収の判定が、そこで止まります。
現場での姿: サービングメトリクス
推論サーバーは、GPUメトリクスだけでは判定できません。キューが溜まって、最初のトークンが遅れているあいだも、GPU使用率は100%に見えるからです。そのため、vLLMは、サービング側のメトリクスを別に出力します。
| メトリクス | 種類 | 意味 |
|---|---|---|
vllm:num_requests_running・vllm:num_requests_waiting |
gauge | 実行中・待機中のリクエスト数 |
vllm:time_to_first_token_seconds |
histogram | 最初のトークンまでにかかった時間 |
vllm:inter_token_latency_seconds |
histogram | トークン間の間隔 |
vllm:prompt_tokens_total・vllm:generation_tokens_total |
counter | 処理したトークン数 |
vllm:kv_cache_usage_perc |
gauge | KVキャッシュの占有(1が100%) |
vllm:request_success_total |
counter | 完了したリクエスト数、finished_reasonラベル |
v1エンジンで、名前がいくつか変わったことも、知っておくとよいでしょう。gpu_cache_usage_percはkv_cache_usage_percになり、ラベルがmodel_name1つから、model_name・engineの2つに増えました。ソースでは、カウンターが接尾辞なしで宣言され、クライアントライブラリが_totalを付けます。そのため、ソースをgrepして、名前を書き写すと、間違えます。
次のラボのサービングメトリクスは、実測ではありません。このクラスターのvLLMのデプロイは、現在レプリカ0で停止していて、メトリクスが1つもありません。ないものをあるふりをしないために、形式だけを似せた合成サンプルを使い、すべての時系列にsource="synthetic"ラベルを付けてあります。GPU・コンテナ・ノードのメトリクスはすべて実測で、vllm:の系列だけがサンプルです。
次のラボですること
GPU4枚の3時間分の実測で、「アイドルのカード」を判定し、帰属ラベルが抜けているカードを探し、累積エネルギーのカウンターから平均電力を導き出してゲージと比べ、最後に、合成サンプルの最初のトークンまでの遅延のp95を、ヒストグラムから求めます。最後には、何が実測で、何がサンプルなのかを区別して、レポートに書きます。