NVIDIAのGPUリソース分割技術

Kohei Yamaguchi
nttlabs
Published in
Nov 6, 2020

こんにちは、NTT研究所の山口です。

前回の記事でA100のMIGについて触れていますが、MIGを活用する際のモチベーションとして、1つのGPU上で効率的に複数プロセスを実行したり、複数ユーザで利用できるようにしたいという目的が挙げられるかと思います。本記事では1つのGPUリソースを効率的に利用するための技術として、Multi Process Service(MPS), Virtual GPU(vGPU), Multi Instance GPU(MIG)という三つのNVIDIA社の技術についてまとめます。

  • MPS: GPU上で並列処理を効率的に行うことができる
  • vGPU: GPUを仮想化してVMに対してリソースを割り当てることが可能。分割されたGPUは、VM内で個々にGPUとして認識可能であるため複数ユーザに対して提供しやすい
  • MIG: 最新のアーキテクチャであるAmpereでしか利用できないがHWレベルでの仮想化であるためオーバーヘッドが非常に小さい

Multi Process Service (MPS)

MPSは1つのGPU上で効率的に複数のプロセスを実行するための技術です。通常、1GPUに対して複数の処理を実行するとスケジューラによってtime-sliceで実行されるようになるため、GPUのcontext switchが 多発してオーバーヘッドが発生してしまいます。MPSはGPUに対して並列処理を実現するための機能で、特にVolta以降のアーキテクチャのMPSではメモリ領域もisoloateされるため効率的に複数のプロセスを実行することができます。

MPS Design from MPS docs

MPSは以下の三つの機能で構成されます。

  • mps-deamon: mpsのcontrollerの役割。mps-clientのuidを見て、mps-serverを立ち上げたりといった管理をする。
  • mps-server: GPU毎に立ち上がるserver。GPUのschedulerの役割。
  • mps-client: mps-deamonおよびmps-serverとやり取りをするためのもの。1プロセスに対して立ち上がる。

MPSを起動し、実際にGPUを掴もうとするプロセスを立ち上げるとnvidia-smiでは nvidia-cuda-mps-server というプロセスが1GPUに対して紐づくように表示されます。

この例はMPSをONにして、GPU device:0に対して3プロセス並列で実行しているものですが、GPU device:0に対して、1つの nvidia-cuda-mps-serverと3つのPythonプロセスが表示されているのがわかります。

簡単にMPSの挙動を説明すると、あるプロセスがGPUを掴もうとするとそのプロセスに対してmps-clientが立ち上がり、常駐しているmps-deamonとやりとりを行います。この時、mps-deamonはmps-clientに紐づいたuidを確認し、そのuidに対してmps-serverを割り当てることで、mps-serverとmps-clientがやりとりをできるようになります。

このようにMPSはuidに対してmps-serverを立ち上げるため、別のuidのプロセスが同じGPUを掴もうとすると、そのプロセスの実行はPendingの状態となります。先に割り当てられたuidのプロセスが全て終了するとPending中だったプロセスが実行されるようになりますが、以降で述べるような複数ユーザで同時に1GPUを共有するといった使い方はできません。あくまでもGPUで複数のプロセスを効率的に実行するための技術がMPSになります。

Virtual GPU (vGPU)

vGPUは1つのGPUリソースを分割して複数のVMにアタッチするための仮想化技術です。vGPUにはデスクトップ用やDeep Learningの計算など利用用途に応じていくつか種類がありますが、ここではその中の一つであるVirtual Compute Server(vCS)について紹介します。

GPU Instances Configured with NVIDIA vGPU from grid vgpu user guide

vCSをアクティブにするにはvGPUライセンスを購入し、専用のGPUドライバをインストールする必要がありますが、このように1つのGPUを仮想的に分割し(ここではvCS Instanceと呼びます)、VMに対して割り当てることができるので、複数ユーザに必要なGPUリソース分を柔軟に提供することができます。

vCSではリソース分割のInstance Typeがいくつか定義されており、分割単位に応じて仮想的に1GPUを複数のvCS Instanceとして分割します。

C-Series Virtual GPU Types for Tesla V100 PCIe from grid vgpu user guide

たとえば、Tesla V100のvCSの場合は大きく三つのTypeがあり、その中から一つを選択することでvCS Instanceを割り当てます。V100–8Cを選んだ場合、16GBのGPUメモリを8GBの2つのvCS Instanceに分割して割り当てる、ということが可能です。

実際にどのようにしてvCS InstanceをVMに対して割り当てていくのかを見ていきます。まず、vCSのドライバをホストにインストールすると、 /sys/class 以下に mdev_bus が作成されます。vCSはこの mdev_bus 以下によって管理されており、以下のような構成になっています。

/sys/class/mdev_bus/
|-[parent-physical-device]
|-mdev_supported_types
|-[nvidia-vgputype-id]
|-available_instances
|-create
|-description
|-device_api
|-devices
|-name

vCS Instanceの作成や削除といった操作はこの mdev_bus 以下の指定のGPU device IDのディレクトリ配下で行います。

# Create vCS Instance
$ echo "b039b16e-7b65-4c90-95eb-621e953f6146" > /sys/class/mdev_bus/0000:04:00.0/mdev_supported_types/nvidia-300/create

たとえばこの例だとGPU device ID0000:04:00.0 に対してvCS Instanceを作成しています。 mdev_supported_types の下にはvCSがサポートしている Instance Typeが存在しており、nvidia-300というTypeを選択しています(このnvidia-300は前述したV100–8Cのタイプのaliasのようなものです)。それぞれのInstance Typeのディレクトリ以下にはcreateやremoveといったvCSを操作するためのファイルが存在するので、そのファイルに対して任意のUUIDを書き込んでvCS Instanceを作成するといった操作をします。

vCS Instanceを作成したら、あとはVMのGuest OSに対して作成したInstanceを紐づけるだけです。

<hostdev mode='subsystem' type='mdev' model='vfio-pci'>
<source>
<address uuid='b039b16e-7b65-4c90-95eb-621e953f6146'/>
</source>
</hostdev>

このようにVMのGuest OSの定義ファイルに対して、先ほどvCS Instance作成の際に紐づけたUUIDを指定してあげます。そしてGuest OSを起動し、必要なGPUドライバをインストールすると、VMのGuest OSに対してInstance Typeで指定された分のGPUリソースが割り当てられるようになります。

vGPUは必要な量のリソース量で分割したGPUをそれぞれ独立したGPUとしてユーザに提供することが可能になるので、GPUクラスタを運用する際により多くのユーザにGPUを提供することが可能になります。

Multi Instance GPU (MIG)

最後にMIGについてです。この技術は一番新しいAmpereアーキテクチャで導入されたもので、1つのGPUを最大7つのPartitionに分割することができます。vCSとの違いでいうと、MIGではVMが不要であり、MIGが払い出す仮想的なDevice IDを用いてLinux Deviceとして管理することも可能です。

また、vCS同様にGPUリソースを指定したTypeに応じて分割できるため用途に応じてGPUを柔軟に利用することができます。

Example MIG partitioning process from white paper

MIGは nvidia-smi コマンドからInstanceを作成することができ、以下二つのInstanceを作成することでリソースを分離しています。

  • GPU Instance
  • Compute Instance

GPU InstanceはGPUメモリやGPCといったリソースを複数のInstanceに分割したものを指します。Compute InstanceはこのGPU Instanceのリソースをさらに複数インスタンスに分割するもので、GPUメモリを共有しながらGPCやGPU Engineを分割します。MIGが最大7つのPartitionに分割できるというのは、GPU Instanceのことを指しており、以下のような分割パターンであるProfileが定義されています。

GPU Instance Profiles from docs
Valid GPU Instance Combinations from docs

この図からもわかる通り、必要とするリソースや用途に応じてProfileを組み合わせることが可能です。A100の場合、推論処理の性能も向上しているので、たとえば1つのGPUの上で学習処理と推論処理をリソースを分離しながら実行するといった使い方もできます。

MIGの詳しい利用方法について省略しますが、我々のMIG検証の際にご協力いただいた、NTT PCコミュニケーションズ社InnovationLABのブログ記事に詳しく記載されているのでご参考いただければと思います。

まとめ

今回、GPUリソースを効率よく利用するためのMPS/vGPU/MIGといったNVIDIA社の技術について紹介しました。目的に応じてこれらの技術を利用することで、より効率的にGPUリソースを活用できるようになるかと思います。また、我々はまだ試せてはいませんが、これらは組み合わせて使うことも可能のようなので、たとえばvGPUとMIGを組み合わせて利用するとさらに柔軟にGPUリソースを扱えるようになるかもしれません。

おわりに

私たちNTTは、オープンソースコミュニティで共に活動する仲間を募集しています。ぜひ弊社 ソフトウェアイノベーションセンタ紹介ページ及び、採用情報ページをご覧ください。

参考文献

--

--