Ubuntu Weekly Recipe

第532回 LXDのコンテナからGPUを利用する

この記事を読むのに必要な時間:およそ 11.5 分

コンテナの中からVAAPIを利用する

コンテナの中からGPUデバイスにアクセスできるようになれば,コンテナの中でVAAPIVDPAUを利用したソフトウェアを実行可能になります。VAAPI/VDPAUに対応したアプリケーションはたくさん存在しますが,まずは大抵のPCには存在するIntelの内蔵GPUのVAAPIで使える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/dri/renderD128もしくは/dev/dri/card0をデバイスファイルとして扱っているためです。今回の例だとこれらはVAAPIに直接には対応していないNVIDIAのGPUであり,さらにはコンテナの中からは見えないように設定していたため,うまく認識できませんでした。

明示的にデバイスファイルを指定するには,--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

無事に認識できましたね。⁠VAEntrypointVLD」がデコードに対応しているフォーマットで,⁠VAEntrypointEncSlice」がエンコードに対応しているフォーマットです。

ちなみに--displayオプションを指定しなかった場合は,WaylandやX11のディスプレイを開きに行こうとするため,サーバー環境だと「error: failed to initialize display」のようなエラーが表示されます。

次にFFmpegを利用して,ハードウェアデコード・エンコードを行ってみます。対象ファイルはBig Buck BunnyのH.264/MOVです※2)⁠

※2
テスト用途としてはファイルサイズが大きすぎますが,他にちょうどいい感じのライセンス・フォーマットを持ったサンプル動画がなかったのでこれにしました。デバイスがMP4デコードに対応しているならSintelのトレイラーぐらいがちょうどいいかもしれません。4KならTears of Steelという選択肢もあります。
$ sudo apt install ffmpeg
$ wget http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_1080p_h264.mov

VAAPI対応デバイスを用いたデコード・エンコード方法については,FFmpegのドキュメントを参照してください。ここでは次のコマンドでH.264をH.265/HEVCに再エンコードしています。

$ 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倍強ですが,CPUの使用時間は比較にならないほど大きくなっています。また,再エンコード中にtopなどを実行すると,全力でCPUを動かしていることがわかります。

なお,複数のLXDインスタンスから同時に同じGPUに対してffmpegを実行することも可能です。よってユーザー側で排他制御を意識する必要は「基本的には」ありません。もちろん性能を考えてどれかのインスタンスで占有させたい場合は,何らかの排他の仕組みを導入するか,そもそも特定のインスタンスのみGPUを見せる必要があります。

コンテナの中から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,darktableなどデスクトップアプリケーションから,仮想通貨のマイニングに至るまで,OpenCLに対応したソフトウェアはたくさん存在します。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member株式会社 創夢所属。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。