Pull to refresh

Comments 12

Когда-то задавался в чём разница выровненных и невыровненных (например _mm_load_si128 и _mm_loadu_si128) операций, так вот оказалось - что на мобильных процессорах (ноутбук) выровненные операции быстрее, а на десктопных разницы нет.

В общем да, согласен. Это и от поколения зависит и более современные вроде не так чувствительны. Есть ещё такая фишка как Prefetch, но тут сколько я ни игрался, никакого выигрыша не увидел, либо напротив, результат только хуже. Похоже на то, что современные процессоры с этим сами успешно справляются, и вмешательство им только мешает.

Да, с prefetch тоже экспериментировал, на x86 это не даёт результата. Вот на DSP (вроде Hexagon с Квалкомовских чипов) это ускоряет существенно.

Тема действительно интересная, обширная и сложная. Если брать изображения вообще в общем, как буфер кадра который может прийти откуда угодно, с любой аппаратной части, находится в разного типа памяти, то например в ffmpeg или библиотеках обработки видео и изображений всё становиться еще сложнее. Там у буфера кадра одновременно присутствует и align, и такие понятия как pitch и stride, причем все они могут иметь разные значения в общем случае:
align - это выравнивание начала строки в байтах. Необходимо для того, что бы строка могла быть обработана SIMD инструкциями, которые требуют выравнивания.
pitch - это выравнивания в пикселах (может быть горизонтальным и вертикальным). Необходимо тем или иным алгоритмам, которые работают блоками, например кодеки или специфические фильтры.
stride - это выравнивание строки в байтах. Необходимо как для работы SIMD, так и для менеджера памяти, который используется для хранения изображения (например в видеопамяти).
Также в зависимости от формата изображения могут иметь так называемые плоскости (цветовые компоненты), которые хранятся отдельно друг от друга и имеют собственные выравнивания. На практике всё это может быть не кратно друг другу, а каждый кодек имеет свои значения. В своё время пришлось плотно разбираться с этим и разрабатывать хитрые обертки, что бы сделать прозрачную передачу (без копирования):
кадр из оперативной памяти -> медиа семпл DirectShow -> ffmpeg кадр -> медиа семпл DirectShow -> кадр в оперативной памяти

Все, что описано выше правда. Но не имеет никакого смысла пока не начать думать как описано выше 🤣 Поскольку для таких задач CPU уже странно использовать, то мы упираемся примерно в те же вопросы, нет уже на уровне GPU. И то, что описано как "хитрое" есть как должное. Любой алгоритм на GPU начинается с выбора паттерна доступа к памяти. Очень часто там и заканчивается 🤣

GPU - это отдельная тема, но в моём конкретном случае "бутылочное горлышко" - это передача фрейм буфера в GPU и обратно. Я работаю с рентгеновским плоскопанельным детектором. У него картинка - 2000х2000, 16 бит, то есть 8 мегабайт. Такая картинка прилетает 20 раз в секунду. Технически фреймграббер - это самодельная PCI-E 4х плата c DMA, детектор висит на оптоволокне, вот по нему он и гонит 160 мегабайт в секунду. На каждый фрейм драйвером вызывается callback, где я получаю указатель на область памяти, в которой лежит картинка. И вот у меня есть 50 миллисекунд на то, чтобы забрать эту картинку, выполнить Flat Field Correction (это грубо говоря вычитание Offset и умножение на Gain коэффициенты попиксельно), затем поднять контраст - тут работает лапласиан пирамида, и по уровням этой пирамиды прогоняется LUT "S" - формы, плюс свёртка для High Pass фильтра повышения резкости, переброс в 8 бит и показ на экране, синхронно с vsync монитора. Основная проблема, которая возникает - время передачи в GPU и обратно, ну и пирамида не очень хорошо параллелится, так что всё это крутится на CPU. А, кстати, сколько нынче занимает времени передать 8 мегабайт в GPU и обратно?

Что с пайплайном? Такое обычно делается так, что один фрейм выгружается, второй обрабатывается, третий загружается.

Это не исправляет задержку, но увеличит частоту кадров которую можно обработать.

Пайплайн, конечно есть, но я реализовал двухбуферную "классику" с Front/Back буферами. Там сценарий использования такой, что оператор дёргает за джойстики и видит на экране как перемещается деталь в рентгене. И дискомфортный лаг начинает быть заметен уже где-то с пары сотен миллисекунд (тем более что также есть определённые лаги в ПЛК и манипуляторе - всё ж таки надо елозить туда-сюда несколько сот кило). Мне проще показать - вот эта железяка:

Где-то на 0:50 и 1:30 и 1:50 ненадолго видны Live картинки на левом мониторе, и мне таки пришлось приложить определённые усилия, чтобы достаточно "гладко" показывать 20 FPS поток на каждом третьем кадре 60 Hz монитора без пропуска кадров, потому что даже просто пропуск одного кадра уже заметен оператору в виде "подёргивания".

А, кстати, сколько нынче занимает времени передать 8 мегабайт в GPU и обратно?

PCIe 4.0x16 - это 64 GB/s, так что выходит 250 мкс на туда-обратно. А вообще по идее это неважно, т.к. для отображения на мониторе данные по любому придётся передавать в GPU, вопрос только на каком этапе, до обработки или после. Про пирамиду пишут, что на gpu делают.

Я с GT 9600 игрался лет этак пятнадцать назад с nvpp, и помню что до теоретически достижимой пропускной способности было ох как далеко. Но у меня сейчас есть Radeon Pro WX 9100, она получше, и действительно на гитхабе вижу эксперименты с пирамидами на OpenCL, так что, пожалуй, сделаю ещё один подход к снаряду. Спасибо за наводку, будет чем заняться долгими зимними вечерами.

64 Гб/c у Pci-Ex 4 - это суммарная в обе стороны, в одну сторону 32 Гб/c. По моим тестам реальная скорость в оптимальном для OpenCL варианте (pinned memory) около 75% от максимальной, 23-24 Гб/c на GF3080. Возможно, серией асинхронных запросов с разными картинками можно выжать больше, у меня гонялась одна.

Тесты с обработкой я тоже делал, и получалось, что единичные простые операции (напр. gauss blur) всё-таки нет смысла гонять в видеокарту. Чем сложнее, тем лучше: AHD debayer - умеренное ускорение раза в два, нейросети - да, самое то :)
Или переносить на GPU весь конвейер из простых операций. При этом отлаживать и поддерживать GPU-код сложнее.

Ах если бы всё было так просто и можно было весь пайп-лайн прибить гвоздями. На практике, иногда нет аппаратного декодера или энкодера. Конфигурация определяется динамически и код обязан работать корректно. Аппаратура не совершенна и многие карты захвата не могут класть данные напрямую в GPU. Даже если энкодер аппаратный, нам приходится приходится правильно передавать данные из CPU в GPU.

Sign up to leave a comment.

Articles