第521回ではUbuntu 18.
コンテナから見えるデバイス
LXDで作成したコンテナからアクセスできるデバイスは、
container$ ls /dev/ console full log net pts stderr tty core fuse lxd null random stdin urandom fd initctl mqueue ptmx shm stdout zero
しかしながらコンテナの中からもホスト上に見えているデバイスにアクセスできると嬉しい場合は多々あります。LXD 2.
設定が簡単になったデバイスの中で特に便利なのが、
GPUをコンテナの中からアクセスできるようにする
LinuxにおいてユーザーランドからGPUにアクセスする際は、/dev/
」
LXDコンテナにホストのGPUデバイスを見せるには、
$ lxc config device add container mygpu gpu デバイス mygpu が container に追加されました
「container
」mygpu
」
デバイスは実行中のコンテナの中でもすぐに見えるようになります。
$ lxc exec container -- ls -l /dev/dri total 0 crw-rw---- 1 root root 226, 0 Aug 11 07:33 card0 crw-rw---- 1 root root 226, 128 Aug 11 07:33 renderD128
GPUデバイスの権限を変更する
デバイス追加時は、
$ ls -l /dev/dri/ total 0 drwxr-xr-x 2 root root 120 Aug 11 06:17 by-path crw-rw---- 1 root video 226, 0 Aug 11 06:17 card0 crw-rw---- 1 root video 226, 128 Aug 11 06:17 renderD128
一般的なユーザーはvideoグループに所属しているため
これを回避する方法はいくつかありますが、
一旦デバイスを削除する $ lxc config device remove container mygpu デバイス mygpu が container から削除されました グループIDを指定して追加する $ lxc config device add cuda mygpu gpu \ gid=`getent group video | cut -d: -f3` デバイス mygpu が container に追加されました $ lxc exec cuda -- ls -l /dev/dri total 0 crw-rw---- 1 root video 226, 0 Aug 11 06:18 card0 crw-rw---- 1 root video 226, 128 Aug 11 06:18 renderD128
無事にvideoグループに所属するようになりました。
デバイス追加時はgid=グループID
」getent
コマンドでvideoグループのIDを抽出し、uid=
」
追加するGPUデバイスを指定する
複数のグラフィックカードを繋いでいたり、/dev/
以下には複数のGPUデバイスファイルが作成されます。このうち一部のGPUのみをLXDコンテナに展開したい場合は、id
オプションを指定します。
たとえばこのマシンは2つのGPUが認識されています。
$ ls -l /dev/dri/ total 0 drwxr-xr-x 2 root root 120 Aug 11 06:17 by-path crw-rw---- 1 root video 226, 0 Aug 11 06:17 card0 crw-rw---- 1 root video 226, 1 Aug 11 06:17 card1 crw-rw---- 1 root video 226, 128 Aug 11 06:17 renderD128 crw-rw---- 1 root video 226, 129 Aug 11 06:17 renderD129
by-path
のほうを見ると、
$ ls -l /dev/dri/by-path/ total 0 lrwxrwxrwx 1 root root 8 Aug 11 06:17 pci-0000:00:02.0-card -> ../card1 lrwxrwxrwx 1 root root 13 Aug 11 06:17 pci-0000:00:02.0-render -> ../renderD129 lrwxrwxrwx 1 root root 8 Aug 11 06:17 pci-0000:01:00.0-card -> ../card0 lrwxrwxrwx 1 root root 13 Aug 11 06:17 pci-0000:01:00.0-render -> ../renderD128
lspci
コマンドで個々のアドレスのデバイスを見てみましょう。
$ lspci -s 0000:00:02.0 00:02.0 VGA compatible controller: Intel Corporation HD Graphics 530 (rev 06) $ lspci -s 0000:01:00.0 01:00.0 VGA compatible controller: NVIDIA Corporation GP107 [GeForce GTX 1050 Ti] (rev a1)
このことから、
NVIDIAのGPU
$ lxc config device add cuda mygpu gpu id=0
ちなみにCUDAなどの利用を目的とする場合、/dev/
以下のグループIDの変更は不要です。
コンテナの中からVAAPIを利用する
コンテナの中からGPUデバイスにアクセスできるようになれば、vainfo
コマンドをインストールしてみましょう。
$ sudo apt install vainfo
試しにGPUがコンテナから見えない状態でコマンドを実行してみます。
$ vainfo error: can't connect to X server! error: failed to initialize display
上記のようにエラーとなりました。次にIntelの内蔵GPUをコンテナに追加した状態で実行してみます。
$ ls -l /dev/dri/ total 0 crw-rw---- 1 root video 226, 1 Aug 12 08:20 card1 crw-rw---- 1 root video 226, 1 Aug 12 08:20 controlD65 crw-rw---- 1 root video 226, 129 Aug 12 08:20 renderD129 $ vainfo error: can't connect to X server! error: failed to initialize display
あれ、vainfo
コマンドが暗黙的に/dev/
」/dev/
」
明示的にデバイスファイルを指定するには、--display
」--device
」
$ vainfo --display drm --device /dev/dri/card1 libva info: VA-API version 1.1.0 libva info: va_getDriverName() returns 0 libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so libva info: Found init function __vaDriverInit_1_1 libva info: va_openDriver() returns 0 vainfo: VA-API version: 1.1 (libva 2.1.0) vainfo: Driver version: Intel i965 driver for Intel(R) Skylake - 2.1.0 vainfo: Supported profile and entrypoints VAProfileMPEG2Simple : VAEntrypointVLD VAProfileMPEG2Simple : VAEntrypointEncSlice VAProfileMPEG2Main : VAEntrypointVLD VAProfileMPEG2Main : VAEntrypointEncSlice VAProfileH264ConstrainedBaseline: VAEntrypointVLD VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice VAProfileH264ConstrainedBaseline: VAEntrypointEncSliceLP VAProfileH264ConstrainedBaseline: VAEntrypointFEI VAProfileH264ConstrainedBaseline: VAEntrypointStats VAProfileH264Main : VAEntrypointVLD VAProfileH264Main : VAEntrypointEncSlice VAProfileH264Main : VAEntrypointEncSliceLP VAProfileH264Main : VAEntrypointFEI VAProfileH264Main : VAEntrypointStats VAProfileH264High : VAEntrypointVLD VAProfileH264High : VAEntrypointEncSlice VAProfileH264High : VAEntrypointEncSliceLP VAProfileH264High : VAEntrypointFEI VAProfileH264High : VAEntrypointStats VAProfileH264MultiviewHigh : VAEntrypointVLD VAProfileH264MultiviewHigh : VAEntrypointEncSlice VAProfileH264StereoHigh : VAEntrypointVLD VAProfileH264StereoHigh : VAEntrypointEncSlice VAProfileVC1Simple : VAEntrypointVLD VAProfileVC1Main : VAEntrypointVLD VAProfileVC1Advanced : VAEntrypointVLD VAProfileNone : VAEntrypointVideoProc VAProfileJPEGBaseline : VAEntrypointVLD VAProfileJPEGBaseline : VAEntrypointEncPicture VAProfileVP8Version0_3 : VAEntrypointVLD VAProfileVP8Version0_3 : VAEntrypointEncSlice VAProfileHEVCMain : VAEntrypointVLD VAProfileHEVCMain : VAEntrypointEncSlice
無事に認識できましたね。
ちなみに--display
」
次にFFmpegを利用して、
$ sudo apt install ffmpeg $ wget http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_1080p_h264.mov
VAAPI対応デバイスを用いたデコード・
$ time ffmpeg -vaapi_device /dev/dri/renderD129 -hwaccel vaapi \ -hwaccel_output_format vaapi \ -i big_buck_bunny_1080p_h264.mov \ -vf 'format=nv12|vaapi,hwupload' -c:v hevc_vaapi -c:a copy \ big_buck_bunny_1080p_h264.mp4 (中略) Duration: 00:09:56.46, start: 0.000000, bitrate: 9725 kb/s Stream #0:0(eng): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080, 9282 kb/s, 24 fps, 24 tbr, 2400 tbn, 4800 tbc (default) (中略) Stream #0:0(eng): Video: hevc (hevc_vaapi) (Main) (hev1 / 0x31766568), vaapi_vld, 1920x1080, q=2-31, 24 fps, 12288 tbn, 24 tbc (default) (中略) frame=14315 fps= 88 q=-0.0 Lsize= 225251kB time=00:09:56.45 bitrate=3093.7kbits/s speed=3.66x video:193017kB audio:31863kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.164760% real 2m42.887s user 0m19.135s sys 0m23.921s
CPU時間をほぼ使うことなく再エンコードできました。比較のためにVAAPIを使わずにエンコードしてみましょう。
$ time ffmpeg \ -i big_buck_bunny_1080p_h264.mov \ -vf 'format=nv12' -c:v hevc -c:a copy \ big_buck_bunny_1080p_h264_2.mp4 (中略) frame=14315 fps= 22 q=-0.0 Lsize= 111046kB time=00:09:56.45 bitrate=1525.1kbits/s speed=0.897x video:78777kB audio:31863kB subtitle:0kB other streams:0kB global headers:2kB muxing overhead: 0.366397% x265 [info]: frame I: 155, Avg QP:23.70 kb/s: 14753.00 x265 [info]: frame P: 4384, Avg QP:28.07 kb/s: 2239.70 x265 [info]: frame B: 9776, Avg QP:34.67 kb/s: 344.90 x265 [info]: Weighted P-Frames: Y:4.1% UV:3.0% x265 [info]: consecutive B-frames: 10.6% 23.8% 10.4% 50.1% 5.1% encoded 14315 frames in 664.95s (21.53 fps), 1081.19 kb/s, Avg QP:32.53 real 11m5.079s user 42m30.934s sys 0m3.594s
実際に経過した時間は4倍強ですが、
なお、
コンテナの中からOpenCLを利用する
GPUを利用するもうひとつの例がOpenCLです。こちらもGPUがコンテナから見えるようになっていたら、
まずはOpenCL関連パッケージをインストールしておきましょう。
$ sudo apt install beignet-opencl-icd clinfo
GPUが見えない時にclinfo
を実行してもGPUが見つからないと表示されます。
$ clinfo --list beignet-opencl-icd: no supported GPU found, this is probably the wrong opencl-icd package for this hardware (If you have multiple ICDs installed and OpenCL works, you can ignore this message) Platform #0: Intel Gen OCL Driver
GPUが見える時にclinfo
を実行すると、
$ clinfo --list Platform #0: Intel Gen OCL Driver `-- Device #0: Intel(R) HD Graphics Skylake Desktop GT2
LibreOffice CalcやBlender、
コンテナの中からCUDAを実行する
CUDAはNVIDIA製GPUで使える、/dev/
」/dev/
」
そこでLXD 3.nvidia-container-cli
でリストアップされる
あらかじめホストマシンにNVIDA製のドライバーをインストールしておいてください。手順は第454回が参考になるでしょう。なおUbuntu 18.
$ apt search "^nvidia-driver-[0-9]{3}$" Sorting... Done Full Text Search... Done nvidia-driver-390/bionic 390.48-0ubuntu3 amd64 NVIDIA driver metapackage
またX11関連パッケージが不要なサーバー向けに依存関係を調整した
$ apt search "^nvidia-headless-[0-9]{3}$" Sorting... Done Full Text Search... Done nvidia-headless-390/bionic 390.48-0ubuntu3 amd64 NVIDIA headless metapackage
2018年8月上旬時点でUbuntuリポジトリからインストールされるNVIDIAドライバーは2018年3月28日にリリースされた390.
$ cat /proc/driver/nvidia/version NVRM version: NVIDIA UNIX x86_64 Kernel Module 390.48 Thu Mar 22 00:42:57 PDT 2018 GCC version: gcc version 7.3.0 (Ubuntu 7.3.0-16ubuntu3)
それに対してNVIDIAから提供されているLong-lived branchの最新版は2018年7月16日にリリースされた390.
NVIDIAのドライバーは、
CUDA | カーネルドライバー |
---|---|
9. |
>= 384. |
9. |
>= 390. |
9. |
>= 396. |
9. |
>= 396. |
つまり最新のCUDA 9.
今のタイミングであれば、
libnvidia-containerのインストール
次にnvidia-container-cli
コマンドを提供するlibnvidia-containerをホストマシンにインストールします。これが存在しないとnvidia-container-cli
コマンドが組み込まれています。
$ curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | \ sudo apt-key add - $ curl -s -L https://nvidia.github.io/libnvidia-container/ubunt18.04/libnvidia-container.list | \ sudo tee /etc/apt/sources.list.d/libnvidia-container.list $ sudo apt update $ sudo apt install libnvidia-container-tools
nvidia-container-cli
を実行してみましょう。
$ nvidia-container-cli info NVRM version: 390.48 CUDA version: 9.1 Device Index: 0 Device Minor: 0 Model: GeForce GTX 1050 Ti GPU UUID: GPU-6fae1717-190c-1843-3fb8-c3d6cd190739 Bus Location: 00000000:01:00.0 Architecture: 6.1
list
サブコマンドを実行することでコンテナの中に展開するホストのファイルのリストが得られます。
$ nvidia-container-cli list /dev/nvidiactl /dev/nvidia-uvm /dev/nvidia-modeset /dev/nvidia0 /usr/bin/nvidia-smi /usr/bin/nvidia-debugdump /usr/bin/nvidia-persistenced /usr/bin/nvidia-cuda-mps-control /usr/bin/nvidia-cuda-mps-server /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.390.48 /usr/lib/x86_64-linux-gnu/libcuda.so.390.48 /usr/lib/x86_64-linux-gnu/libnvidia-opencl.so.390.48 /usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so.390.48 /usr/lib/x86_64-linux-gnu/libnvidia-fatbinaryloader.so.390.48 /usr/lib/x86_64-linux-gnu/libnvidia-compiler.so.390.48 /usr/lib/x86_64-linux-gnu/libnvidia-encode.so.390.48 /usr/lib/x86_64-linux-gnu/libnvcuvid.so.390.48
これらはすべてホストのファイルがそのままコンテナの中でも見えるようになるので、
具体的にどのように使っているかは/usr/
」
コンテナの中でのNVIDIAドライバーの有効化
実際にコンテナを作るところから見ていきましょう。
$ lxc launch ubuntu:16.04 cuda Creating cuda Starting cuda $ lxc config device add cuda gp107 gpu id=0 デバイス gp107 が gpu に追加されました
この状態でコンテナの中でnvidia-smi
を実行しても、
$ lxc exec cuda nvidia-smi (エラー終了)
そこでnvidia.
オプションをtrue
にします。これにより次回起動時から、nvidia-container-cli
の結果に応じてホストのファイル群がコンテナの中にも展開されるのです。
$ lxc config set cuda nvidia.runtime true $ lxc restart cuda $ lxc exec cuda nvidia-smi Sun Aug 12 11:26:24 2018 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 390.48 Driver Version: 390.48 | |-------------------------------+----------------------+----------------------+ | 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 | 00000000:01:00.0 Off | N/A | | 0% 48C P0 N/A / 72W | 0MiB / 4040MiB | 0% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | No running processes found | +-----------------------------------------------------------------------------+
コンテナの中でもnvidia-smi
を実行できるようになりました
CUDAツールキットのインストール
コンテナにCUDAツールキットをインストールするにあたって、nvidia.
設定はホストのファイルをそのままコンテナの中に見せる仕組みです。よってホスト上ではパッケージからインストールされたファイルであっても、
$ dpkg -S /usr/lib/x86_64-linux-gnu/libcuda.so.390.48 libnvidia-compute-390:amd64: /usr/lib/x86_64-linux-gnu/libcuda.so.390.48
たとえばlibcuda.
コンテナの上で直接CUDA Toolkitを使いたい場合は第456回で紹介した方法のうち、/usr/
以下に保存されるNVIDIAのパッケージ版かスクリプト版のインストール方法を使うと良いでしょう。Ubuntu 18.
$ sudo apt install build-essential $ wget https://developer.nvidia.com/compute/cuda/9.1/Prod/local_installers/cuda_9.1.85_387.26_linux $ sudo bash cuda_9.1.85_387.26_linux --no-opengl-libs (NVIDIAドライバーのインストールは不要)
CUDA 9.
サンプルコードがホームディレクトリにインストールされているので、
$ cd ~/NVIDIA_CUDA-9.1_Samples/1_Utilities/bandwidthTest/ $ make
うまくビルドできたら、
$ ~/NVIDIA_CUDA-9.1_Samples/bin/x86_64/linux/release/deviceQuery /root/NVIDIA_CUDA-9.1_Samples/bin/x86_64/linux/release/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 9.1 / 9.1 CUDA Capability Major/Minor version number: 6.1 Total amount of global memory: 4040 MBytes (4236312576 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 Supports Cooperative Kernel Launch: Yes Supports MultiDevice Co-op Kernel Launch: 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 = 9.1, CUDA Runtime Version = 9.1, NumDevs = 1 Result = PASS
うまく認識してくれているようですね。
実際のところ、