Подтвердить что ты не робот

Ошибка Cortex A9 NEON против VFP

Я пытаюсь создать библиотеку для процессора Cortex A9 ARM (более OMAP4), и я немного замешана в отношении того, когда\когда использовать NEON vs VFP в контексте с плавающей запятой операций и SIMD. Следует отметить, что я знаю разницу между двумя аппаратными сопроцессорами (как также указано здесь, на SO), у меня просто есть недоразумение относительно их правильного использования.

В связи с этим я использую следующие флаговые компиляции:

GCC
-O3 -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
-O3 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp
ARMCC
--cpu=Cortex-A9 --apcs=/softfp
--cpu=Cortex-A9 --fpu=VFPv3 --apcs=/softfp

Я прочитал документацию по ARM, много wiki (как этот), форумы и сообщения в блогах, и все, кажется, согласитесь, что использование NEON лучше, чем использование VFP или, по крайней мере, смешение NEON (например, использование instrinsics для реализации некоторых альго в SIMD), а VFP - не такая хорошая идея; Я не уверен на 100%, если это применимо в контексте всей библиотеки приложений\или только к определенным местам (функциям) в коде.

Поэтому я использую neon как FPU для своего приложения, так как я также хочу использовать встроенные функции. В результате у меня немного неприятности, и я смутился о том, как лучше использовать эти функции (NEON vs VFP) на Cortex A9, только углубляется дальше, а не проясняется. У меня есть код, который выполняет бенчмаркинг для моего приложения и использует некоторые пользовательские таймерные классы в которых вычисления основаны на двойной точности с плавающей запятой. Использование NEON в качестве FPU дает совершенно неулокальные результаты (попытка распечатать эти значения приводит к печати в основном inf и NaN, тот же код работает без сбоев при построении для x86). Поэтому я изменил свои вычисления на использование одинарной точности с плавающей запятой, поскольку документировано, что NEON не обрабатывает плавающую точку с двойной точностью. Мои тесты по-прежнему не дают правильных результатов (и, что хуже всего, теперь это больше не работает на x86, я думаю, это из-за потери точности, но я не уверен). Поэтому я почти полностью потерял: с одной стороны, я хочу использовать NEON для возможностей SIMD и использовать его, поскольку FPU не дает правильных результатов, с другой стороны, смешивание его с VFP не кажется очень хорошей идеей. Любые советы в этой области будут очень благодарны!

Я нашел в статье в вышеупомянутой wiki сводку того, что должно быть сделано для оптимизации с плавающей запятой в контексте NEON:

"

  • Использовать только одинарные точки с плавающей запятой
  • Используйте NEON intrinsics/ASM, когда вы найдете функцию FP с узким местом. Вы можете сделать лучше, чем компилятор.
  • Свернуть условные ветки
  • Включить режим RunFast

Для softfp:

  • Встроенный код с плавающей запятой (если только его очень большой)
  • Передавайте аргументы FP через указатели вместо значения и выполняйте целочисленные операции между вызовами функций.

"

Я не могу сильно использовать для float ABI, поскольку я не могу связываться с библиотеками, которые у меня есть. Большинство рекомендаций имеют смысл для меня (за исключением "режима runfast", который я не понимаю точно, что должно было делать, и того факта, что в этот момент я мог бы сделать лучше, чем компилятор), но я продолжаю получать противоречивые результаты и Я ничего не знаю прямо сейчас.

Может ли кто-нибудь пролить свет на то, как правильно использовать плавающую точку и NEON для Cortex A9/A8 и какие флаговые компиляции использовать?

4b9b3361

Ответ 1

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

Но чтобы покрыть одну часть путаницы: Рекомендация "использовать NEON как FPU" звучит как недоразумение. NEON - это SIMD-движок, VFP - это FPU. Вы можете использовать NEON для операций с плавающей запятой с одинарной точностью с одновременным до четырех значений с одной точностью, что (когда это возможно) подходит для производительности.

-mfpu=neon можно рассматривать как сокращенное обозначение -mfpu=neon-vfpv3.

Подробнее см. http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html.

Ответ 2

... форумы и сообщения в блогах, и все, похоже, согласны с тем, что использование NEON лучше, чем использование VFP или, по крайней мере, смешение NEON (например, использование instrinsics для реализации некоторых algos в SIMD), а VFP - не такая хорошая идея

Я не уверен, что это правильно. Согласно ARM на Представляем статью NEON Development | Регистры NEON:

Банк регистрации NEON состоит из 32 64-битных регистров. Если оба Продвинуты SIMD и VFPv3, они делят этот регистр банка. В этом случае VFPv3 реализуется в форме VFPv3-D32, которая поддерживает 32 с плавающей запятой с двойной точностью. Эта интеграция упрощает поддержку поддержки контекста контекста, поскольку те же подпрограммы, которые сохраняют и восстанавливают контекст VFP, также сохраняют и восстановить NEON-контекст.

Модуль NEON может просматривать тот же банк регистров, что и:

  • шестнадцать 128-битных регистров квад- рала, Q0-Q15
  • тридцать два 64-битных регистра двойных слов, D0-D31.

Регистры NEON D0-D31 совпадают с регистрами VFPv3 D0-D31 и каждый из регистров Q0-Q15 отображается на пару регистров D. На рисунке 1.3 показаны различные виды общих NEON и VFP зарегистрировать банк. Все эти взгляды доступны в любое время. Программного обеспечения не нужно явно переключаться между ними, поскольку Используемая инструкция определяет соответствующий вид.

Регистры не конкурируют; скорее они сосуществуют в качестве взглядов на банк регистров. Невозможно отключить механизм NEON и FPU.


В связи с этим я использую следующие флаговые компиляции:

-O3 -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
-O3 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp

Вот что я делаю; ваш пробег может отличаться. Он получен из mashup информации, собранной с платформы и компилятора.

gnueabihf говорит мне, что платформа использует жесткие поплавки, что может ускорить процедурные вызовы. Если есть сомнения, используйте softfp, потому что он совместим с жесткими поплавками.

BeagleBone Black:

$ gcc -v 2>&1 | grep Target          
Target: arm-linux-gnueabihf

$ cat /proc/cpuinfo
model name  : ARMv7 Processor rev 2 (v7l)
Features    : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32 
...

Таким образом, BeagleBone использует:

-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard

CubieTruck v5:

$ gcc -v 2>&1 | grep Target 
Target: arm-linux-gnueabihf

$ cat /proc/cpuinfo
Processor   : ARMv7 Processor rev 5 (v7l)
Features    : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 

Итак, CubieTruck использует:

-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard

Banana Pi Pro:

$ gcc -v 2>&1 | grep Target 
Target: arm-linux-gnueabihf

$ cat /proc/cpuinfo
Processor   : ARMv7 Processor rev 4 (v7l)
Features    : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt

Таким образом, Banana Pi использует:

-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard

Малина Pi 3:

RPI3 уникален в том, что его ARMv8, но работает под 32-разрядной ОС. Это означает его эффективную 32-битную ARM или Aarch32. Там немного больше, чем 32-бит ARM против Aarch32, но это покажет вам флаги Aarch32

Кроме того, RPI3 использует Broadcom A53 SoC, и он имеет NEON и дополнительные инструкции CRC32, но не имеет дополнительных расширений Crypto.

$ gcc -v 2>&1 | grep Target 
Target: arm-linux-gnueabihf

$ cat /proc/cpuinfo 
model name  : ARMv7 Processor rev 4 (v7l)
Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
...

Таким образом, малина Pi может использовать:

-march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard

Или он может использовать (я не знаю, что использовать для -mtune):

-march=armv7-a -mfpu=neon-vfpv4 -mfloat-abi=hard 

ODROID C2:

ODROID C2 использует Amlogic A53 SoC, но использует 64-битную ОС. ODROID C2, он имеет NEON и дополнительные инструкции CRC32, но не имеет дополнительных расширений Crypto (аналогичная конфигурация для RPI3).

$ gcc -v 2>&1 | grep Target 
Target: aarch64-linux-gnu

$ cat /proc/cpuinfo 
Features    : fp asimd evtstrm crc32

Таким образом, ODROID использует:

-march=armv8-a+crc -mtune=cortex-a53

В приведенных выше рецептах я изучил процессор ARM (например, Cortex A9 или A53), проверив данные. В соответствии с этим ответом на Unix и Linux Stack Exchange, который расшифровывает выходные данные из /proc/cpuinfo:

Часть процессора: номер детали. 0xd03 указывает процессор Cortex-A53.

Таким образом, мы сможем найти форму данных в базе данных. Я не знаю, существует ли он или где находится.

Ответ 3

Я бы держался подальше от VFP. Это точно так же, как режим Thmub: он предназначен для компиляторов. Нет смысла оптимизировать для них.

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

Просто инвестируйте два или три дня в базовую сборку ARM: вам нужно только узнать несколько инструкций для управления/завершения цикла.

Затем вы можете начать писать собственные коды NEON, не беспокоясь о том, что компилятор делает что-то астральное, выплевывая множество ошибок/предупреждений.

Обучение инструкциям NEON менее требовательно, чем все эти макросы intrinsics. И все выше, результаты намного лучше.

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

Просто сравните версию OP с моим в приведенной ниже ссылке, тогда вы поймете, что я имею в виду.

Оптимизация преобразования RGBA8888 в RGB565 с помощью NEON

рассматривает