Профессиональные GPU в серверах позиционируются как устройства для высокопроизводительных вычислений, систем искусственного интеллекта и рендеринговых ферм для 3D-графики. Стоит ли их применять для энкодинга, или это стрельба из пушки по воробьям? Попробуем разобраться.
Для работы с многопоточным видео достаточно мощностей современных CPU и решений наподобие Intel Quick Sync. Более того, некоторые специалисты считают, будто загрузка профессиональных GPU декодингом и энкодингом — пустая трата ресурсов. Для потребительских видеокарт количество входящих потоков специально ограничивают до двух-трех, хотя мы уже убедились, что небольшое шаманство с драйвером позволяет это ограничение обойти. В предыдущей статье тестировались бытовые видеокарты, а сейчас мы займемся более серьезными — NVIDIA RTX A4000.
Подготовка к тестированию
Что делать, если вывод lscpu выдает вам что-то вроде AMD Ryzen 9 5950X 16-Core Processor, но в компьютер вставлена NVIDIA RTX A4000 с 16 ГБ оперативной памяти, а вы хотите перекодировать и записать поток с нескольких сетевых камер? Информация с них обычно поступает через http, rtp или rtsp, и наша задача — поймать эти потоки, перекодировать их в нужный формат и записать каждый в отдельный файл.
Для проверки мы в HOSTKEY создали небольшой тестовый стенд из имеющихся выделенных серверов с указанной выше конфигурацией CPU/GPU без специальной оптимизации и 32 ГБ оперативной памяти. На нем через FFmpeg мы будем принимать мультикаст-вещание в форматах http и rtsp (использован видеофайл bbb_sunflower_1080p_30fps_normal.mp4 из деморепозитория Blender), декодировать его в разном количестве потоков FFmpeg и записывать каждый из них в отдельный файл. Как видно из названия, мы принимаем поток в формате 1080p (30 кадров в секунду). Энкодинг будет применяться только к видео, а звуковые потоки пойдут без изменения.
Также несущественно, берем мы один входящий поток и имитируем его мультипоточность или параллельно обрабатываем несколько потоков. Работа с сетью и текущие процессы на тестовом стенде отнимают менее 1% ресурсов CPU, поэтому можно считать, что основную нагрузку на процессор и дисковую подсистему даст именно энкодинг.
![](https://habrastorage.org/getpro/habr/upload_files/5a3/928/278/5a392827807231e9b7e0c56d54a38f72.png)
Все дальнейшее повествование будет вестись для вещания через http, поскольку результаты для потока rtsp оказались сравнимыми. Чтобы не плодить множество консолей терминала на сервере, для теста были созданы простые bash-скрипты, в которые при запуске передается требуемое количество инстансов FFmpeg, перекодирующих видеопоток в h264.
Энкодинг на голом CPU:
#!/bin/bash
for (( i=0; i<$1; i++ )) do
ffmpeg -i http://XXX.XXX.XXX.XXX:5454/ -an -vcodec h264 -y Output-File-$i.mp4 &
done
На GPU мы будем использовать возможности видеокарты через NVENC (как собрать FFmpeg с его поддержкой, мы рассказывали в первой статье цикла):
#!/bin/bash
for (( i=0; i<$1; i++ )) do
ffmpeg -i http://XXX.XXX.XXX.XXX:5454/ -an -vcodec h264_nvenc -y Output-File-$i.mp4 &
done
Скрипты запускают в цикле мультикаста и ловят в сети нашего кролика. Предварительно стоит проверить через тот же vlc или ffplay, что поток реально вещается. Результат мы будем оценивать по загрузке CPU/GPU, утилизации памяти и качеству записываемого видео, где главными для нас будут два параметра: fps (он должен быть стабильным и не опускаться ниже 30 кадров в секунду) и speed (показывает, успеваем ли мы обрабатывать видео на лету). Для realtime параметр speed должен быть больше 1.00x.
Проседания этих двух параметров приводят к выпадению кадров, артефактам, проблемам кодировки и другим повреждениям картинки, которые не хотелось бы видеть на записях с камер видеонаблюдения.
Проверяем энкодинг на голом CPU
![](https://habrastorage.org/getpro/habr/upload_files/ffe/907/5e7/ffe9075e7295c925fc31f97285add600.png)
Запуск одной копии FFmpeg дает нам такую начальную картину:
![](https://habrastorage.org/getpro/habr/upload_files/20f/b0b/317/20fb0b31726b98c0b788b433d3d8c95a.png)
Загрузка по ядрам процессора в среднем на уровне 18–20%, а вывод FFmpeg показывает следующее:
frame=196 fps=87 q=-1.0 Lsize=2685kB time=00:00:06.43 bitrate=3419.0kbits/s speed=2.84x
Запас есть, и можно попробовать сразу три потока:
frame=310 fps=54 q=29.0 size=4608kB time=00:00:07.63 bitrate=4945.3kbits/s speed=1.33x
Четыре потока выбирают почти все мощности CPU и «отъедают» 13 ГБ оперативной памяти.
![](https://habrastorage.org/getpro/habr/upload_files/03e/e45/5b0/03ee455b076193c6d983aa78755414d8.png)
При этом вывод FFmpeg показывает, что резервы не исчерпаны:
frame=332 fps=49 q=29.0 size=3072kB time=00:00:08.36 bitrate=3007.9kbits/s speed=1.23x
Увеличиваем количество потоков до пяти. Процессор держится на пределе, местами начинаются просадки скорости кадров и битрейта на 5–10%:
frame=491 fps=37 q=29.0 size=4864kB time=00:00:13.66 bitrate=2915.6kbits/s speed=1.03x
Запуск шести потоков показывает, что предел достигнут. Мы все больше и больше отстаем от реального времени и начинаем пропускать кадры:
frame=140 fps=23 q=29.0 size=1024kB time=00:00:01.96 bitrate=2954.4kbits/s speed=0.446x
Включаем мощности GPU
![](https://habrastorage.org/getpro/habr/upload_files/ccc/ec5/083/cccec5083b40d680105736f5dbba37b2.png)
Запускаем один поток FFmpeg с энкодингом через h264_nvenc. Убеждаемся через вывод nvidia-smi, что у нас задействована именно видеокарта:
![](https://habrastorage.org/getpro/habr/upload_files/831/bf0/0a7/831bf00a7499ae910d851ad790d9196b.png)
Поскольку вывод достаточно громоздкий, мы будем отслеживать параметры GPU с помощью следующей команды:
nvidia-smi dmon -s pucm
Расшифруем обозначения:
pwr — потребляемая видеокартой мощность в ваттах;
gtemp — температура видеоядра (в градусах Цельсия);
sm — SM, mem — память, enc — энкодер, dec — декодер (утилизация их ресурсов указана в процентах);
mclk — текущая частота памяти (в МГц), pclk — текущая частота процессора (в МГц);
fb — использование кадрового буфера (в Мб).
gpu | pwr | gtemp | mtemp | sm | mem | enc | dec | mclk | pclk | fb | bar1 |
Idx | W | C | C | % | % | % | % | MHz | MHz | MB | MB |
0 | 35 | 48 | – | 1 | 0 | 6 | 0 | 6500 | 1560 | 213 | 5 |
Нас в этом выводе будут интересовать значения загрузки энкодеров GPU и утилизации видеопамяти.
Вывод FFmpeg дает следующие результаты:
frame=192 fps=96 q=23.0 Lsize=1575kB time=00:00:06.36 bitrate=2027.1kbits/s speed=3.17x
Запускаем сразу пять потоков. Как видно из вывода htop, в случае энкодинга на GPU загрузка процессора минимальна, а большая часть работы ложится именно на видеокарту. Дисковая подсистема также загружена гораздо меньше.
![](https://habrastorage.org/getpro/habr/upload_files/144/007/19a/14400719af4dc082ae99a6158e8dec80.png)
gpu | pwr | gtemp | mtemp | sm | mem | enc | dec | mclk | pclk | fb | bar1 |
Idx | W | C | C | % | % | % | % | MHz | MHz | MB | MB |
0 | 36 | 48 | – | 8 | 2 | 40 | 0 | 6500 | 1560 | 1035 | 14 |
Загрузка блоков энкодинга увеличилась до 40%, память мы заняли почти на гигабайт, но видеокарта по факту загружена не сильно. Вывод FFmpeg подтверждает это, показывая, что у нас есть ресурсы для увеличения количества потоков минимум в 2 раза:
frame=239 fps=67 q=36.0 Lsize=2063kB time=00:00:07.93 bitrate=2130.3kbits/s speed=2.22x
Ставим десять потоков. Утилизация CPU на уровне 15–20%.
![](https://habrastorage.org/getpro/habr/upload_files/6c1/0cd/24b/6c10cd24be26894c7208f4714ccbb56d.png)
Параметры видеокарты:
gpu | pwr | gtemp | mtemp | sm | mem | enc | dec | mclk | pclk | fb | bar1 |
Idx | W | C | C | % | % | % | % | MHz | MHz | MB | MB |
0 | 55 | 48 | – | 14 | 4 | 61 | 0 | 6500 | 1920 | 2064 | 24 |
Потребление электроэнергии возросло, видеокарта вынуждена была разогнать частоту видеоядра, но мощности энкодинга и видеопамять позволяют увеличивать нагрузку. Проверяем вывод FFmpeg, чтобы в этом убедиться:
frame=1401 fps=36 q=29.0 Lsize=12085kB time=00:00:46.66 bitrate=2121.5kbits/s speed=1.2x
Пробуем добавить еще четыре потока и получаем загрузку блоков энкодинга в 100%.
gpu | pwr | gtemp | mtemp | sm | mem | enc | dec | mclk | pclk | fb | bar1 |
Idx | W | C | C | % | % | % | % | MHz | MHz | MB | MB |
0 | 68 | 59 | – | 18 | 7 | 100 | 0 | 6500 | 1920 | 2886 | 33 |
Вывод FFmpeg подтверждает, что мы достигли предела. Утилизация CPU при этом все еще не превышает 20%.
frame=668 fps=31 q=26.0 Lsize=5968kB time=00:00:22.23 bitrate=2199.0kbits/s speed=1.04x
Контрольные 15 потоков показывают, что GPU начинает сдавать, так как блоки энкодинга работают с перегрузкой, а также наблюдается рост температуры и потребляемой мощности.
gpu | pwr | gtemp | mtemp | sm | mem | enc | dec | mclk | pclk | fb | bar1 |
Idx | W | C | C | % | % | % | % | MHz | MHz | MB | MB |
0 | 70 | 63 | – | 18 | 7 | 100 | 0 | 6500 | 1920 | 3092 | 35 |
FFmpeg также подтверждает, что видеокарте становится тяжеловато. Частота обработки и пропуск кадров уже не внушают оптимизма:
frame=310 fps=28 q=29.0 size=2560kB time=00:00:10.23 bitrate=2049.4kbits/s speed=0.939x
CPU vs GPU
Подытожим: применение GPU в такой конфигурации можно назвать оправданным, поскольку максимальное количество обрабатываемых видеокартой потоков в 3 раза превышает возможности далеко не самых слабых процессоров (особенно без поддержки технологий аппаратного кодирования). С другой стороны, мы используем только минимальную часть возможностей видеоадаптера. Поскольку остальные его блоки и видеопамять не сильно нагружены, ресурсы дорогостоящего устройства утилизируются неэффективно.
Искушенные читатели могут заметить, что мы не проверили работу в режимах 2K/4K, не использовали возможности современных кодеков (наподобие h265 и VP8/9), а также установили в тестовый стенд видеоадаптер на архитектуре предыдущего поколения.
Тот же A5000 должен показать лучший результат: его работу мы проверили в следующей статье, где немного препарировали и Intel Quick Sync. Оправдались ли надежды, можно узнать здесь.
Напишите в комментариях, какие еще нюансы стоит учесть при тестировании, какие моменты мы упустили и что бы вы хотели узнать по этой теме.
UPD. Сколько в деньгах? (вынесено из комментариев)
Стоимость описанных выше экспериментов измерить просто: можно воспользоваться нашим калькулятором-конфигуратором на этой странице.
На, например, современных Xeon она следующая:
машина с A4000 в самой простой конфигурации обойдется в 22000р, 12 потоков - 1800р на поток в месяц;
машина с A5000 в самой простой конфигурации обойдется в 31000р, 14 потоков - 2214р на поток в месяц;
сервер на i9-9900K в самой простой конфигурации с QuickSync (QSV) обойдется в 5000-6000р, 11 потоков, 450р на поток.
Серверы для такого необходимо собирать на материнских платах без удаленного управления, что мы умеем. Обращайтесь!
Кстати, все серверы HOSTKEY предоставляются с нашим модулем полного удаленного управления сервером IPMI и панелью управления серверами и API. Об устройстве последней мы рассказали в этой статье.