Несколько месяцев назад мы рассмотрели, как можно реализовать обработку нескольких данных с помощью одной инструкции (SIMD) с использованием DSP48 в программируемой логике. Использование SIMD таким образом в PL позволяет нам получить как оптимальную производительность, так и использование ресурсов.

В этом блоге мы собираемся изучить, как мы можем сделать подобное, используя SIMD/векторный модуль с плавающей запятой в системе обработки.

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

SIMD не ограничивается только обработкой изображений и аудио. Это также дает значительные преимущества для приложений, в том числе:

  • Умножение матриц
  • Исправление ошибок — например. Рид-Соломон
  • Криптография на эллиптических кривых

На этом этапе вы можете задаться вопросом, в чем разница между реализацией алгоритма с использованием SIMD в NEON или ускорением проектирования до программируемой логики с использованием HLS для использования SIMD в DSP48. Ответ действительно зависит от требований к производительности, которых мы пытаемся достичь.

Как часть стандартной архитектуры Arm Cortex-A9, модуль NEON поддерживается разработчиком ПО «из коробки». Это также означает, что существует широкая экосистема поддержки модуля NEON в различных библиотеках и API, особенно при работе с операционными системами более высокого уровня, такими как PetaLinux, где такие библиотеки, как FFMPEG, FFTW и Project NE10, поддерживают использование NEON. Эта стандартная функциональность поддерживает внедрение и упрощает создание и отладку программ.

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

Какое решение использовать NEON или PL SIMD, зависит от требований к производительности приложения. Осведомленность о NEON/VFPU и его возможностях дает нам еще один инструмент в наборе инструментов встроенной системы, о котором нужно знать и учитывать при разработке наших решений.

В Zynq-7000 модуль NEON предоставляет 32 64-битных регистра, которые также можно рассматривать как 16 128-битные регистры. Это означает, что полосы данных могут иметь ширину от 8, 16, 32 или 64 бит со знаком или без знака или с плавающей запятой одинарной точности. Линия данных — это количество параллельных операций, поддерживаемых одновременно.

Когда код компилируется для выполнения в NEON, используются специальные инструкции сборки NEON. Если мы нацеливаемся на NEON, мы можем дважды проверить, используются ли инструкции NEON, заглянув в ELF.

Открытие ELF в SDK покажет нам инструкции по сборке NEON. Мы можем легко идентифицировать их в ассемблере, так как они начинаются с буквы V, например, VADD, VMUL и т. д.

V{‹mod›}‹op›{‹shape›}{‹cond›}{.‹dt›}(‹dest›}, src1, src2

Чтобы убедиться, что мы используем NEON в наших приложениях Zynq, нам необходимо правильно настроить параметры сборки C/C++ в SDK.

Используемые настройки:

  • -std=c99 — C99 вводит новые функции, которые может использовать движок NEON.
  • -mfpu = neon — указывает, какой модуль с плавающей запятой доступен на оборудовании.
  • уровень оптимизации = -O3 — включает агрессивную оптимизацию, встраивание и увеличение скорости. Также включает -ftree-vectorise, который включает векторизацию кода C/C++ для NEON.
  • -mfloat-abi=softfp / -mfloat-abi = hard — указывает, какой ABI с плавающей запятой используется.
  • -mvectorize-with-neon-quad- будет векторизовать слова Quad, а не двойные слова, которые используются по умолчанию в GCC 4.4.
  • -ftree-vectorizer-verbose=n — позволяет увидеть информацию о процессе векторизации.
  • -fdump-tree-vect — создаст файл дампа, в котором сообщается об усилиях по векторизации.

Взяв простой пример кода, который генерирует точечный продукт, мы можем скомпилировать код с указанными выше настройками для использования NEON (см. исходный код в XApp1206).

Изучив сгенерированные инструкции в файле ELF, мы можем увидеть команды NEON в нескольких местах.

Мы также можем изучить файл vect, который предоставляет информацию об усилиях по векторизации в каталоге SRC. Мы можем увидеть этот файл, если у нас есть -ftree-vectorizer-verbose=n и -fdump-tree-vect, установленные в параметрах сборки.

Изучение файла в SDK покажет усилия и соображения, предпринятые в процессе компиляции NEON.

Когда я запустил приведенный выше пример кода, который включает как векторизованный код NEON, так и код, векторизованный вручную, мы увидели, что автоматически векторизованный код работает немного лучше.

Я скоро вернусь к блоку NEON и посмотрю, как он используется, когда мы запускаем Linux в системе обработки. Но на данный момент мы видим, что он может обеспечить значительные преимущества для ряда приложений.

Посмотрите мои проекты FPGA/SoC:Адам Тейлор на Hackster.io

Получите код:ATaylorCEngFIET (Адам Тейлор)

Доступ к архивам MicroZed Chronicles с более чем 300 статьями о FPGA / Zynq / Zynq MpSoC, которые еженедельно обновляются на MicroZed Chronicles.