ARM NEON: инструменты для прогнозирования проблем с производительностью из-за ограниченной пропускной способности доступа к памяти?

Я пытаюсь оптимизировать критические части кода C для обработки изображений на устройствах ARM и недавно обнаружил NEON.

Читая советы здесь и там, я получаю довольно хорошие результаты, но есть кое-что, что ускользает от меня. Я вижу, что общая производительность очень сильно зависит от доступов к памяти и от того, как они выполняются.

Какой самый простой способ (под простым я подразумеваю, если это возможно, не запускать весь скомпилированный код в эмуляторе или симуляторе, а что-то, что можно скармливать небольшим фрагментам сборки и анализировать их), чтобы получить представление того, как доступ к памяти является «узким местом» подпрограммы?

Я знаю, что это невозможно сделать точно, не запуская его на определенном оборудовании и в определенных условиях, но цель состоит в том, чтобы иметь инструмент проб и ошибок для «сравнения», с которым можно экспериментировать, даже если результаты являются только приблизительными.

(что-то похожее на этот отличный инструмент для подсчета циклов)


person Jordi C.    schedule 11.02.2014    source источник
comment
К сожалению, каждая система будет иметь разные циклы для памяти. Для того, чтобы сделать надлежащий анализ, вам потребуются точные тайминги. Для DDR SDRAM это может быть очень сложно, так как всплеск в пределах страницы, в банке, чтение с последующей записью и т. д. имеют разные тайминги. Чтобы сделать это менее зависимым от аппаратного обеспечения (или даже того, куда распределитель помещает вещи), вам нужен ваш алгоритм для доставки данных в L2 или L1 задолго до использования.   -  person artless noise    schedule 11.02.2014
comment
Спасибо! Я так и предполагал. Но решил спросить, так как мне не нужны точные тайминги, и я просто хотел что-то, чтобы дать мне подсказки о том, могут ли определенные изменения принести пользу или убить мою подпрограмму, прежде чем тестировать их на платформах ARM-NEON, но я полагаю, что это все еще слишком общее. Кстати, когда вы говорите о получении данных на L2 или L1, вы имеете в виду использование предварительной загрузки (PLD)? Если есть еще, пожалуйста, где я могу найти?   -  person Jordi C.    schedule 11.02.2014
comment
Да, PLD это обычный способ сделать это. См. раздел преобразование цвета Cortex-A8 Neon и т. д. Большинство В документах ARM говорится, что PLD похож на фальшивый доступ к памяти, который не ожидает завершения. Он просто заполнит строки L1 и L2 для этого адреса в фоновом режиме, пока ЦП делает другие вещи. Эти размеры линий могут быть разными в зависимости от конкретного чипа. Есть способы узнать это динамически, но большинство людей жестко кодируют это для конкретной системы, чтобы упростить ассемблер.   -  person artless noise    schedule 12.02.2014
comment
Некоторые ARM имеют PLD вместо NOP, например ARM926. Так что для него PLD - это просто загрязнение инструкций. Ссылка ARM на memcpy() для cortex-A8, который ограничивает PLD размером L2. Я думаю, что промах L1 не так уж и дорог. Обратите внимание, что они выполняют предварительную выборку заблаговременно. Ваш алгоритм будет привязан либо к процессору, либо к памяти. Зная пропускную способность памяти, вы можете сказать, какой из них. Знание тайминга кода нулевого цикла может привести к ограничению ЦП. Зная оба, вы должны знать, с какой стороны работать.   -  person artless noise    schedule 12.02.2014
comment
Спасибо, очень интересная ссылка memcpy! Любые советы для части записи?   -  person Jordi C.    schedule 12.02.2014
comment
Я не думаю, что запись должна вызывать остановку процессора. запись выполняется из процессора в DDR. чтение выполняется из DDR в ЦП. Это возможно, если есть много ожидающих записей, которые вы можете заблокировать. Однако ваш алгоритм, вероятно, ограничивает пропускную способность памяти, если запись блокируется. Ничто не сравнится с измерением реального времени, чтобы увидеть.   -  person artless noise    schedule 12.02.2014


Ответы (2)


Думаю, вы, наверное, сами ответили на свой вопрос. Память — это эффект системного уровня, и многие разработчики ARM (Apple, Samsung, Qualcomm и т. д.) реализуют систему по-разному с разными результатами.

Однако, конечно, вы можете оптимизировать вещи для определенной системы, и она, вероятно, будет хорошо работать на других, поэтому на самом деле все сводится к выяснению способа, которым вы можете быстро повторять и тестировать / моделировать эффекты на уровне системы. Это усложняется, поэтому вы можете заплатить немного денег за симуляторы системного уровня, такие как включенные в ARM RealView. Или я мог бы порекомендовать получить какое-нибудь оборудование с открытым исходным кодом, такое как Panda Board, и использовать cache-grind от valgrind. С Linux на доске Panda вы можете написать несколько скриптов для автоматизации тестирования.

Это может быть хлопотно, но если оптимизация для ARM станет частью вашей профессиональной жизни, то это стоит (относительно низких по сравнению с вашей зарплатой) инвестиций в программное обеспечение и оборудование и времени.

Примечание 1: я не рекомендую использовать PLD. Это очень зависит от настройки системы, и если вы хорошо работаете на одной реализации ARM, это может повредить вам для следующего поколения чипов или другой реализации. Это может быть намеком на то, что попытка оптимизации на системном уровне, кроме некоторой локализации базовых данных и упорядочивания, может не стоить ваших усилий? (См. комментарий Стивена ниже).

person Peter M    schedule 12.02.2014
comment
Что касается PLD, стоит отметить, что большинство более современных ядер имеют ту или иную форму «потоковой предварительной выборки»; они будут распознавать линейный доступ к памяти и выполнять предварительную выборку самостоятельно, не требуя явных инструкций по предварительной выборке. - person Stephen Canon; 13.02.2014
comment
Да, я подозревал что-то подобное, но предпочел спросить, так как я совсем новичок в этом мире. В любом случае, поскольку я вижу разницу в производительности (на конкретной платформе, то есть на моем мобильном устройстве) в зависимости от того, как я использую PLD, я хотел знать, есть ли для этого волшебное правило. Другая возможность (просто интересно) состояла бы в том, чтобы определить в режиме реального времени лучшую схему PLD для конкретной платформы, которую нужно выбрать из 2 или 3, но не знаю, будет ли это иметь смысл, если поведение системы также изменится динамически. - person Jordi C.; 13.02.2014
comment
Да, действительно было бы интересно определить во время выполнения, как лучше всего использовать очень специфичные для системы функции, такие как PLD. Лучшие библиотеки DSP, такие как Intel Performance Primitives, выполняют диспетчеризацию ЦП — они определяют конкретный используемый вариант ЦП Intel, а затем используют для него лучшую сборку. К сожалению, в мире ARM многие поставщики очень скрытно относятся к своим реализациям ARM ISA, поэтому (мне) сложно разработать решение так, как это делает Intel. - person Peter M; 18.02.2014

Доступ к памяти — это одна вещь, которую просто нельзя смоделировать из «небольших фрагментов сборки» для получения осмысленного руководства. Иерархии кэширования, буферы хранения, очереди пропуска загрузки, политика кэширования и т. д. под LSU скрывается огромное количество «состояний», и любой мелкомасштабный анализ не может точно зафиксировать это состояние.Тем не менее, есть несколько основных рекомендаций для достижения наилучшей производительности:

  • максимизировать соотношение инструкций «полезных вычислений» к операциям LSU.
  • выровняйте доступ к памяти (в идеале до 16 байт).
  • если вам нужно выбрать между выравниванием грузов или выравниванием магазинов, выровняйте свои магазины.
  • старайтесь выписывать полные строки кэша, когда это возможно.
  • PLD в основном полезен для неоднородных, но как-то предсказуемых шаблонов доступа к памяти (такие встречаются редко).
  • В частности, для NEON лучше использовать инструкции vld1 и vst1 (с подсказкой выравнивания). В большинстве микроархитектур в большинстве случаев это самый быстрый способ переключения между NEON и памятью. В частности, избегайте v[ld|st][3|4]; это привлекательная неприятность, в большинстве случаев медленнее, чем отдельные перестановки на большинстве микроархитектур.
person Stephen Canon    schedule 12.02.2014
comment
Спасибо за подсказки, воспользуюсь и посмотрю что получится. Конкретная процедура, на которой я застрял, предназначена для поворота изображения. В простом C потребовалось около 2-3 мс, чтобы повернуть изображение 240 * 400. Когда я хотел удвоить плотность (480 * 800), я ожидал, что время увеличится в 4 раза, но это занимает более 20 мс. Потом решил попробовать с NEON, в некоторых других рутинах (не ротация) скорость сильно увеличилась. А вот в этом такой же или даже медленнее. - person Jordi C.; 13.02.2014
comment
Вы вращаетесь на 90 градусов или делаете произвольное вращение? - person Stephen Canon; 13.02.2014
comment
Всего 90 штук в разных конфигурациях, иногда против часовой стрелки и/или с переворачиванием. Цель состоит в том, чтобы адаптировать предварительный просмотр камеры (после преобразования его в RGB) к настройкам экрана и сделать некоторые вещи поверх того же предварительного просмотра. - person Jordi C.; 13.02.2014
comment
Только что измерил, примерно 13 мс, но все равно многовато. - person Jordi C.; 13.02.2014
comment
И как я могу узнать размер кэшлайна? - person Jordi C.; 13.02.2014