web-dev-qa-db-fra.com

Vous produisez du code NDK optimisé pour plusieurs architectures?

J'ai du code C pour Android qui fait beaucoup de calculs de bas niveau. Je voudrais savoir quels paramètres je dois utiliser (par exemple pour mes fichiers Android.mk et Application.mk) afin que le code produit s'exécute sur tous les appareils Android Android actuels, mais profite également des optimisations pour des chipsets spécifiques. Je recherche de bons paramètres Android.mk et Application.mk par défaut à utiliser et je Je veux éviter d'avoir à jeter mon code C avec des branches #ifdef.

Par exemple, je suis conscient que ARMv7 a des instructions à virgule flottante et que certaines puces ARMv7 prennent en charge les instructions NEON et que la valeur par défaut ARM ne prend en charge aucune de ces options. Est-il possible de définir des indicateurs pour que je puisse construire ARMv7 avec NEON, ARMv7 sans NEON et la valeur par défaut ARM build? Je sais comment faire les deux derniers mais pas tous les 3. Je fais attention aux paramètres que j'utilise car je suppose que le les valeurs par défaut actuelles sont les paramètres les plus sûrs et les risques associés aux autres options.

Pour l'optimisation spécifique à GCC, j'utilise les drapeaux suivants:

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

J'ai vérifié les 3 accélérant mon code. Y en a-t-il d'autres que je pourrais ajouter?

Une autre astuce que j'ai est d'ajouter "LOCAL_ARM_MODE: = arm" à Android.mk pour permettre une accélération sur les puces de bras plus récentes (bien que je ne sache pas exactement ce que cela fait et ce qui se passe sur les puces plus anciennes).

53
rbcc

Les processeurs ARM ont 2 jeux d'instructions générales qu'ils prennent en charge: "ARM" et "Thumb". Bien qu'il existe différentes versions des deux, les instructions ARM sont 32 bits chacune et les instructions Thumb sont 16 bits. La principale différence entre les deux est que les instructions ARM ont la possibilité de faire plus dans une seule instruction que le pouce. Par exemple, une seule instruction ARM peut ajouter un registre à un autre registre, tout en effectuant un décalage vers la gauche sur le second registre. Dans Thumb one instruction devrait faire le quart de travail, puis une deuxième instruction ferait l'addition.

Les instructions ARM ne sont pas deux fois plus efficaces, mais dans certains cas, elles peuvent être plus rapides. Cela est particulièrement vrai dans les assemblages roulés à la main ARM, qui peuvent être réglés de manière innovante pour tirer le meilleur parti des "changements gratuits". Les instructions du pouce ont leur propre avantage ainsi que la taille: ils déchargent moins la batterie.

Quoi qu'il en soit, c'est ce que fait LOCAL_ARM_MODE - cela signifie que vous compilez votre code en tant qu'instructions ARM au lieu d'instructions Thumb. La compilation en Thumb est la valeur par défaut dans le NDK car elle a tendance à créer un binaire plus petit et le la différence de vitesse n'est pas perceptible pour la plupart des codes. Le compilateur ne peut pas toujours tirer parti du "coup de pouce" supplémentaire que ARM peut fournir, donc vous finissez par avoir besoin plus ou moins du même nombre de instructions de toute façon.

Le résultat de ce que vous voyez du code C/C++ compilé en ARM ou Thumb sera identique (sauf bogues du compilateur ).

Ceci est en soi compatible entre les nouveaux et les anciens ARM pour tous les téléphones Android disponibles aujourd'hui. En effet, par défaut, le NDK se compile en une "interface binaire d'application"). "pour les processeurs ARM qui prennent en charge le jeu d'instructions ARMv5TE. Cet ABI est appelé" armeabi "et peut être explicitement défini dans Application.mk en mettant APP_ABI := armeabi.

Les nouveaux processeurs prennent également en charge l'ABI spécifique à Android connu sous le nom de armeabi-v7a, Qui étend l'armeabi pour ajouter jeu d'instructions Thumb-2 et un jeu d'instructions matériel à virgule flottante appelé VFPv3-D16. Les processeurs compatibles armeabi-v7a peuvent également prendre en charge en option le jeu d'instructions NEON, que vous devez vérifier au moment de l'exécution et fournir des chemins de code pour quand il est disponible et quand il ne l'est pas. Il y a un exemple dans le répertoire NDK/samples qui fait cela (bonjour-néon). Sous le capot, le Thumb-2 est plus "ARM-like" dans la mesure où ses instructions peuvent faire plus en une seule instruction, tout en ayant l'avantage de prendre moins de place.

Afin de compiler un "gros binaire" contenant à la fois les bibliothèques armeabi et armeabi-v7a, vous devez ajouter ce qui suit à Application.mk:

APP_ABI := armeabi armeabi-v7a

Lorsque le fichier .apk est installé, le gestionnaire de packages Android installe la meilleure bibliothèque pour le périphérique. Ainsi, sur les anciennes plates-formes, il installerait la bibliothèque armeabi, et sur les périphériques plus récents, l'armeabi-v7a.

Si vous souhaitez tester les fonctionnalités du processeur au moment de l'exécution, vous pouvez utiliser la fonction NDK uint64_t Android_getCpuFeatures() pour obtenir les fonctionnalités prises en charge par le processeur. Cela renvoie un bit-flag de Android_CPU_ARM_FEATURE_ARMv7 Sur les processeurs v7a, Android_CPU_ARM_FEATURE_VFPv3 Si les virgules flottantes matérielles sont prises en charge et Android_CPU_ARM_FEATURE_NEON Si les instructions SIMD avancées sont prises en charge. ARM ne peut pas avoir NEON sans VFPv3.

En résumé: par défaut, vos programmes sont les plus compatibles. L'utilisation de LOCAL_ARM_MODE peut accélérer légèrement les choses au détriment de la durée de vie de la batterie en raison de l'utilisation des instructions ARM - et il est aussi compatible que la configuration par défaut. En ajoutant le APP_ABI := armeabi armeabi-v7a, vous aurez de meilleures performances sur les nouveaux appareils, restez compatible avec les plus anciens, mais votre fichier .apk sera plus volumineux (en raison de la présence de 2 bibliothèques). Pour utiliser les instructions NEON, vous devrez écrire du code spécial qui détecte le capacités du CPU au moment de l'exécution, et cela ne s'applique qu'aux périphériques plus récents qui peuvent exécuter armeabi-v7a.

112
richq

Excellente réponse, tout comme pour ajouter que vous devez utiliser

APP_ABI := all

cela compilera 4 binaires, armv5, armv7, x86 et mips

vous pourriez avoir besoin d'une nouvelle version de ndk

23
user1159819