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

Создание оптимизированного кода NDK для нескольких архитектур?

У меня есть C-код для Android, который делает много низкоуровневого хруста. Я хотел бы знать, какие настройки я должен использовать (например, для своих Android.mk и Application.mk), чтобы созданный код запускался на всех современных устройствах Android, но также использует оптимизацию для определенных наборов микросхем. Я ищу хорошие настройки Android.mk и Application.mk по умолчанию, и я хочу, чтобы не засорять мой код C ветвями #ifdef.

Например, я знаю, что ARMv7 имеет инструкции с плавающей запятой, а некоторые чипы ARMv7 поддерживают инструкции NEON и что ARM по умолчанию не поддерживает ни одно из них. Можно ли установить флаги, чтобы я мог строить ARMv7 с помощью NEON, ARMv7 без NEON и стандартной сборки ARM по умолчанию? Я знаю, как делать последние два, но не все. 3. Я осторожно отношусь к тем, какие настройки я использую, поскольку я предполагаю, что текущие значения по умолчанию являются самыми безопасными настройками и какие риски могут иметь другие параметры.

Для специальной оптимизации GCC я использую следующие флаги:

LOCAL_CFLAGS=-ffast-math -O3 -funroll-loops

Я проверил все 3 из этих скоростей моего кода. Есть ли другие общие, которые я мог бы добавить?

Еще один совет: добавить LOCAL_ARM_MODE: = arm в Android.mk, чтобы ускорить работу с новыми фишками (хотя я смущен точно, что это делает и что происходит на старых чипах).

4b9b3361

Ответ 1

Процессоры ARM имеют 2 общих набора инструкций, которые они поддерживают: "ARM" и "Thumb". Хотя есть разные варианты обоих, инструкции ARM имеют 32 бита, а команды Thumb - 16 бит. Основное различие между ними состоит в том, что инструкции ARM имеют возможность делать больше в одной инструкции, чем Thumb. Например, одна команда ARM может добавить один регистр в другой регистр, выполняя сдвиг влево по второму регистру. В Thumb одна инструкция должна была бы сделать сдвиг, тогда вторая инструкция сделает дополнение.

Инструкции ARM не так хороши, но в некоторых случаях они могут быть быстрее. Это особенно актуально для ручной сборки ARM, которая может быть настроена по новым способам наилучшего использования "сдвигов бесплатно". У Thumb-инструкций есть свои преимущества, а также размер: они меньше разряжают батарею.

В любом случае, это то, что LOCAL_ARM_MODE делает - это означает, что вы компилируете свой код как инструкции ARM вместо инструкций Thumb. Компиляция в Thumb является значением по умолчанию в NDK, поскольку она имеет тенденцию создавать меньший двоичный файл, а разница в скорости не является заметной для большинства кодов. Компилятор не всегда может воспользоваться дополнительным "oomph", который может предоставить ARM, поэтому вам в конечном итоге требуется более или менее одинаковое количество инструкций.

Результат того, что вы видите из кода C/С++, скомпилированного в ARM или Thumb, будет идентичным (запрет ошибок компилятора).

Это само по себе совместимо между новыми и старыми ARM-процессорами для всех телефонов Android, доступных сегодня. Это связано с тем, что по умолчанию NDK компилируется в "Application Binary Interface" для процессоров на базе ARM, которые поддерживают набор инструкций ARMv5TE. Этот ABI известен как "armeabi" и может быть явно установлен в Application.mk, помещая APP_ABI := armeabi.

Новые процессоры также поддерживают Android-специфический ABI, известный как armeabi-v7a, который расширяет armeabi, чтобы добавить набор инструкций Thumb-2 и набор команд с плавающей точкой для аппаратных средств, называемый VFPv3-D16. Совместимые с armeabi-v7a процессоры также могут поддерживать набор инструкций NEON, который вы должны проверять во время выполнения и предоставлять коды кода, когда они доступны, а когда нет. Вот пример в каталоге NDK/samples, который делает это (привет-неоновый). Под капотом Thumb-2 более "похож на ARM", поскольку его команды могут выполнять больше одной команды, имея преимущество в том, что все еще занимает меньше места.

Чтобы скомпилировать "жирный двоичный файл", содержащий библиотеки armeabi и armeabi-v7a, вы должны добавить следующее в Application.mk:

APP_ABI := armeabi armeabi-v7a

Когда файл .apk установлен, менеджер пакетов Android устанавливает лучшую библиотеку для устройства. Поэтому на старых платформах он установил библиотеку armeabi, а на более новых устройствах - armeabi-v7a.

Если вы хотите протестировать функции ЦП во время выполнения, вы можете использовать функцию NDK uint64_t android_getCpuFeatures(), чтобы получить функции, поддерживаемые процессором. Это возвращает бит-бит ANDROID_CPU_ARM_FEATURE_ARMv7 на процессорах v7a, ANDROID_CPU_ARM_FEATURE_VFPv3, если поддерживаются аппаратные плавающие точки и ANDROID_CPU_ARM_FEATURE_NEON, если поддерживаются расширенные инструкции SIMD. ARM не может иметь NEON без VFPv3.

Вкратце: по умолчанию ваши программы наиболее совместимы. Использование LOCAL_ARM_MODE может сделать что-то немного быстрее за счет времени автономной работы из-за использования инструкций ARM - и оно совместимо с настройкой по умолчанию. Добавив строку APP_ABI := armeabi armeabi-v7a, вы получите улучшенную производительность на новых устройствах, оставайтесь совместимыми со старыми, но ваш .apk файл будет больше (из-за наличия 2 библиотек). Чтобы использовать инструкции NEON, вам нужно будет написать специальный код, который обнаруживает возможности процессора во время выполнения, и это относится только к более новым устройствам, которые могут запускать armeabi-v7a.

Ответ 2

Отличный ответ, просто добавьте, вы должны использовать

APP_ABI := all

это скомпилирует 4 бинарных файла, armv5, armv7, x86 и mips

вам может понадобиться новая версия ndk