第456回ではUbuntu 16.
NVIDIAのDocker
第458回で紹介しているようにDockerはカーネルのコンテナ技術などを利用して、
カーネルが共通であるということは、
つまりDockerコンテナの中でCUDAのようなデバイスファイルの操作を行いたい場合、
- Control Groupを用いてコンテナからGPUのデバイスファイルへの読み書きの権限を与える
( --device
オプション) - Linuxのcapabilities(7)を用いて非特権ユーザーにも一部の特権操作を行えるようにする
( --cap-add
オプション)
CUDAを動かしたいだけであれば、/dev/
」nvidia-uvm
のようにCUDAの利用によって動的にロードされうるモジュールも存在するため、
NVIDIA DockerはCUDA入りのDockerイメージを構築・
CUDAをDocker上で使う最大のメリットは、
このようにメリットの多いNVIDIA Dockerですが、
NVIDIA Dockerのインストール
あらかじめ第458回に従って、
NVIDIA Dockerもこれまでと同様に、
- リリース版のDebファイルをダウンロードしてインストールする
- リリース版のソースコードをダウンロードしてビルド&インストールする
- Gitリポジトリの最新版ををcloneしてビルド&インストールする
Ubuntuの場合は、
$ wget -P /tmp https://github.com/NVIDIA/nvidia-docker/releases/download/v1.0.1/nvidia-docker_1.0.1-1_amd64.deb $ sudo apt install /tmp/nvidia-docker*.deb && rm /tmp/nvidia-docker*.deb $ ps -fe | grep nvidia nvidia-+ 1259 1 3 20:06 ? 00:00:00 /usr/bin/nvidia-docker-plugin -s /var/lib/nvidia-docker root 1293 2 0 20:06 ? 00:00:00 [irq/132-nvidia] root 1294 2 0 20:06 ? 00:00:00 [nvidia] shibata 1653 22617 0 20:06 pts/2 00:00:00 grep --color=auto nvidia $ systemctl is-enabled nvidia-docker enabled
これでインストールは完了です。ちなみに前述のとおり、
CUDAコンテナの起動
次はCUDAコンテナを起動してみましょう。まずはNVIDIA Dockerが正しく動くかどうかの確認がてら、
$ nvidia-docker search nvidia/cuda NAME DESCRIPTION STARS OFFICIAL AUTOMATED nvidia/cuda CUDA and cuDNN images from gitlab.com/nvid... 94 (以下略)
いくつも候補が出てくると思いますが先頭にあるnvidia/
まずはlatestタグのコンテナでnvidia-smi
コマンドを使ってみましょう。
$ nvidia-docker run --rm nvidia/cuda nvidia-smi Using default tag: latest latest: Pulling from nvidia/cuda d54efb8db41d: Pull complete f8b845f45a87: Pull complete e8db7bf7c39f: Pull complete 9654c40e9079: Pull complete 6d9ef359eaaa: Pull complete cdfa70f89c10: Pull complete 3208f69d3a8f: Pull complete eac0f0483475: Pull complete 4580f9c5bac3: Pull complete 6ee6617c19de: Pull complete Digest: sha256:2b7443eb37da8c403756fb7d183e0611f97f648ed8c3e346fdf9484433ca32b8 Status: Downloaded newer image for nvidia/cuda:latest Fri Mar 4 08:26:58 2017 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 375.39 Driver Version: 375.39 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | |===============================+======================+======================| | 0 GeForce GTX 105... Off | 0000:01:00.0 Off | N/A | | 0% 33C P8 35W / 72W | 0MiB / 4038MiB | 0% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | No running processes found | +-----------------------------------------------------------------------------+
コンテナの中からでもGPUデバイスにアクセスできていることがわかりますね。
普通のDockerとNVIDIA Dockerの違い
nvidia-docker
コマンドとdocker
コマンドを比べてみると、
$ nvidia-docker images REPOSITORY TAG IMAGE ID CREATED SIZE nvidia/cuda latest 1cce8839a2c5 36 hours ago 1.62 GB $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE nvidia/cuda latest 1cce8839a2c5 36 hours ago 1.62 GB
ではdocker
コマンドからnvidia-smi
を実行するとどうなるのでしょうか。
$ docker run --rm nvidia/cuda nvidia-smi container_linux.go:247: starting container process caused "exec: \"nvidia-smi\": executable file not found in $PATH" docker: Error response from daemon: oci runtime error: container_linux.go:247: starting container process caused "exec: \"nvidia-smi\": executable file not found in $PATH".
nvidia-smi
が見つからなかったようです。nvidia-docker
のほうでコマンドの位置を確認してみましょう。
$ nvidia-docker run --rm nvidia/cuda which nvidia-smi /usr/local/nvidia/bin/nvidia-smi $ docker run --rm nvidia/cuda ls /usr/local/nvidia ls: cannot access '/usr/local/nvidia': No such file or directory
nvidia-docker
コマンド経由だと/usr/
以下に存在するにもかかわらず、docker
コマンド経由だとディレクトリ自体が存在しないようです。つまり
実はDockerには/usr/
はこのVolumeとしてマウントされた領域です。実際にコンテナの中でmount
コマンドを実行してみると、
$ nvidia-docker run --rm nvidia/cuda mount | grep nvidia /dev/sda2 on /usr/local/nvidia type btrfs (ro,relatime,ssd,space_cache,subvolid=257,subvol=/@/var/lib/nvidia-docker/volumes/nvidia_driver/375.39)
どうやらホストの/var/
」/usr/
」docker
のvolume
サブコマンドを使うと確認できます。ちなみにこのVolumeはnvidia-docker-plugin
が作成しています。
$ docker volume ls DRIVER VOLUME NAME nvidia-docker nvidia_driver_375.39 $ docker volume inspect nvidia_driver_375.39 [ { "Driver": "nvidia-docker", "Labels": null, "Mountpoint": "/var/lib/nvidia-docker/volumes/nvidia_driver/375.39", "Name": "nvidia_driver_375.39", "Options": {}, "Scope": "local" } ] $ ls /var/lib/nvidia-docker/volumes/nvidia_driver/375.39/ bin lib lib64 $ ls /var/lib/nvidia-docker/volumes/nvidia_driver/375.39/bin/ nvidia-cuda-mps-control nvidia-cuda-mps-server nvidia-debugdump nvidia-persistenced nvidia-smi
NVIDIAのカーネルドライバーはたんなるカーネルモジュールだけでなく、
もしこれらのライブラリをコンテナイメージの中に同梱してしまうと、
なおデバイスファイルについても、nvidia-docker
経由でのみアクセスできます。
$ nvidia-docker run --rm nvidia/cuda sh -c 'ls -l /dev/nvidia*' crw-rw-rw- 1 root root 241, 0 Mar 3 09:54 /dev/nvidia-uvm crw-rw-rw- 1 root root 241, 1 Mar 3 09:54 /dev/nvidia-uvm-tools crw-rw-rw- 1 root root 195, 0 Mar 3 09:54 /dev/nvidia0 crw-rw-rw- 1 root root 195, 255 Mar 3 09:54 /dev/nvidiactl $ docker run --rm nvidia/cuda sh -c 'ls -l /dev/nvidia*' ls: cannot access '/dev/nvidia*': No such file or directory
サンプルの実行
最後のデモとして、
最初に必要なパッケージのインストールとNVIDIA Dockerのコードのチェックアウトです。
$ sudo apt install git $ git clone https://github.com/NVIDIA/nvidia-docker.git $ cd nvidia-docker/
前回と同じくdeviceQuery
プログラムから試してみましょう。
$ docker build -t sample:deviceQuery samples/ubuntu-16.04/deviceQuery (中略) Successfully built f771d146a5a1 $ docker images sample:deviceQuery REPOSITORY TAG IMAGE ID CREATED SIZE sample deviceQuery f771d146a5a1 2 minutes ago 1.93 GB $ nvidia-docker run --rm sample:deviceQuery ./deviceQuery Starting... CUDA Device Query (Runtime API) version (CUDART static linking) Detected 1 CUDA Capable device(s) Device 0: "GeForce GTX 1050 Ti" CUDA Driver Version / Runtime Version 8.0 / 8.0 CUDA Capability Major/Minor version number: 6.1 Total amount of global memory: 4039 MBytes (4235001856 bytes) ( 6) Multiprocessors, (128) CUDA Cores/MP: 768 CUDA Cores GPU Max Clock rate: 1392 MHz (1.39 GHz) Memory Clock rate: 3504 Mhz Memory Bus Width: 128-bit L2 Cache Size: 1048576 bytes Maximum Texture Dimension Size (x,y,z) 1D=(131072), 2D=(131072, 65536), 3D=(16384, 16384, 16384) Maximum Layered 1D Texture Size, (num) layers 1D=(32768), 2048 layers Maximum Layered 2D Texture Size, (num) layers 2D=(32768, 32768), 2048 layers Total amount of constant memory: 65536 bytes Total amount of shared memory per block: 49152 bytes Total number of registers available per block: 65536 Warp size: 32 Maximum number of threads per multiprocessor: 2048 Maximum number of threads per block: 1024 Max dimension size of a thread block (x,y,z): (1024, 1024, 64) Max dimension size of a grid size (x,y,z): (2147483647, 65535, 65535) Maximum memory pitch: 2147483647 bytes Texture alignment: 512 bytes Concurrent copy and kernel execution: Yes with 2 copy engine(s) Run time limit on kernels: No Integrated GPU sharing Host Memory: No Support host page-locked memory mapping: Yes Alignment requirement for Surfaces: Yes Device has ECC support: Disabled Device supports Unified Addressing (UVA): Yes Device PCI Domain ID / Bus ID / location ID: 0 / 1 / 0 Compute Mode: < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) > deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 8.0, CUDA Runtime Version = 8.0, NumDevs = 1, Device0 = GeForce GTX 1050 Ti Result = PASS
次にnbody
も試してみましょう。サンプルのDockerfileは/usr/
の個々のサンプルディレクトリをWORKDIR
に設定した上でmake
し、CMD
フィールドでサンプルを実行しています。よって./サンプルプログラム オプション
」
$ docker build -t sample:nbody samples/ubuntu-16.04/nbody (中略) Successfully built 32144285f8f4 $ docker images sample:nbody REPOSITORY TAG IMAGE ID CREATED SIZE sample nbody 32144285f8f4 About a minute ago 1.93 GB $ nvidia-docker run --rm sample:nbody (中略) 6144 bodies, total time for 10 iterations: 6.136 ms = 61.522 billion interactions per second = 1230.441 single-precision GFLOP/s at 20 flops per interaction $ nvidia-docker run --rm sample:nbody ./nbody -benchmark -numbodies=8192 (中略) number of bodies = 8192 8192 bodies, total time for 10 iterations: 12.298 ms = 54.568 billion interactions per second = 1091.357 single-precision GFLOP/s at 20 flops per interaction $ nvidia-docker run --rm sample:nbody ./nbody -benchmark -numbodies=65536 (中略) number of bodies = 65536 65536 bodies, total time for 10 iterations: 636.416 ms = 67.487 billion interactions per second = 1349.736 single-precision GFLOP/s at 20 flops per interaction $ nvidia-docker run --rm sample:nbody ./nbody -benchmark -numbodies=8192 -cpu (中略) > Simulation with CPU number of bodies = 8192 8192 bodies, total time for 10 iterations: 27903.188 ms = 0.024 billion interactions per second = 0.481 single-precision GFLOP/s at 20 flops per interaction
コンテナ上であっても、
仮想マシンでのGPGPU
コンテナではなくKVMのような仮想マシン上でもGPGPUは利用可能です。
たとえばIOMMU
たとえばIntelのGVT-gのように、
PCIデバイスとして考えた場合、
そもそもCUDA 8.
以上のようにいろいろな制約があることから、