Résumé
Cet article présente de façon détaillée des méthodes de développement et de portage d’une application Android sur la plate-forme Intel Atom et décrit les méthodes les plus connues de développement d’applications utilisant le kit NDK (Native Development Kit) Android et d’optimisation des performances. Les développeurs Android peuvent utiliser ce document comme référence pour créer des applications de haute qualité pour l’architecture Intel.
1. Classification des applications Android
Les applications Android peuvent être classées en deux types comme le montre la Figure 1.
- Les applications Dalvik qui comprennent du code Java* et utilisent uniquement l’API du SDK Android officiel et les fichiers de ressource nécessaires, comme xml et png, compilés dans un fichier APK.
- Les applications NDK Android qui comprennent du code Java et des fichiers de ressources ainsi que du code source C/C++ et quelque fois du code assembleur. Tout le code natif est compilé dans une bibliothèque DLL (dynamic linked library) (fichier .so) puis appelé par Java dans le programme principal à l’aide d’un mécanisme JNI.
Figure 1 : Deux types d’applications Android
2. Kit de développement natif (NDK) Android
2.1 Introduction
Le NDK (Native Development Kit) Android est un outil d’accompagnement du SDK Android. Le NDK est un outil puissant pour développer des applications Android car :
- Il crée les portions essentielles aux performances de vos applications en code natif. Lors de l’utilisation de code Java, le code source basé sur Java doit être interprété en langage machine à l’aide d’un ordinateur virtuel. En revanche, le code natif est compilé en code binaire et optimisé directement avant l’exécution. Avec une utilisation appropriée du code natif, vous pouvez incorporer du code hautes performances dans votre application, comme pour l’encodage et décodage vidéo matériel, le traitement graphique et les opérations arithmétiques.
- Il réutilise le code natif existant. Les codes C/C++ peuvent être compilés en bibliothèque dynamique pouvant être appelée par code Java par un mécanisme JNI.
2.2 Présentation des outils
Lors du développement, vous pouvez utiliser le gestionnaire Intel® Hardware Execution Manager (HAXM) pour améliorer les performances du simulateur Android. HAXM est un moteur d’assistance matérielle à la virtualisation (hyperviseur) qui utilise la technologie de virtualisation Intel® pour accélérer l’émulation des applications Android sur un ordinateur hôte. En combinaison avec les images d’émulateur Android x86 fournies par Intel et avec le gestionnaire SDK Android officiel, HAXM offre une émulation Android plus rapide sur les systèmes dotés de la technologie de virtualisation Intel. Pour davantage d’informations sur HAXM, consultez : http://software.intel.com/fr-fr/articles/intel-hardware-accelerated-execution-manager.
2.3 Installation d’HAXM
Vous pouvez utiliser le gestionnaire du SDK Android pour installer HAXM (recommandé) ou installer HAXM manuellement en téléchargeant le programme d’installation depuis le site Web d’Intel. Si vous voulez le mettre à jour automatiquement, installez-le à l’aide du gestionnaire du SDK Android comme illustré dans la Figure 2. [1]
Figure 2 : Installer Intel HAXM à l’aide du gestionnaire du SDK Android
Vous pouvez également télécharger un kit d’installation approprié depuis http://software.intel.com/fr-fr/android sur votre plate-forme hôte, puis suivez les instructions pas à pas pour l’installer.
2.3.1 Configuration d’HAXM
L’image système Android x86 fournie par Intel est nécessaire lors de l’exécution d’HAXM. Vous pouvez télécharger l’image système à l’aide du gestionnaire du SDK Android ou la télécharger manuellement depuis le site Web de la Zone des développeurs Intel®.
Après avoir installé les images avec succès, les images d’émulateur Android Intel® x86 s’exécutent automatiquement à l’aide du binaire « emulator-x86 » fourni avec le SDK Android. L’émulateur Android est accéléré par la technologie de virtualisation Intel, ce qui accélère votre processus de développement.
3. Développer et porter des applications NDK pour l’architecture Intel Atom
3.1 Développement d'applications NDK pour des appareils basés sur le processeur Intel Atom
Après avoir installé le NDK avec succès, prenez quelques minutes pour lire les documents se trouvant dans le répertoire <ndk>/docs/, notamment OVERVIEW.html et CPU-X86.html, afin de bien comprendre le mécanisme du NDK et comment l’utiliser.
Le développement d’une application NDK peut être divisé en cinq étapes, comme l’illustre la Figure 3 :
Figure 3 : Processus de développement d’une application NDK
La démo hello-jni est utilisée pour illustrer ces cinq étapes. Vous trouverez la démo dans le dossier Root\samples\hello-jni de votre NDK [5]. La démo hello-jni est une simple application fournie dans le NDK qui tire une chaîne d’une méthode native d’une bibliothèque partagée et l’utilise dans l’interface utilisateur de l’application.
3.1.1. Créer un code natif
Créez un nouveau projet Android et placez votre code source natif sous <projet>/jni/. Le contenu du projet est montré dans la Figure 4. La démo contient une simple fonction en code natif appelée Java_com_example_hellojni_HelloJni_stringFromJNI(). Comme le montre le code source, elle retourne une simple chaîne de JNI.
Figure 4 : Créer un code natif
3.1.2 Créer un fichier MakeFile « Android.mk »
Les applications NDK sont créées par défaut pour la plate-forme ARM. Pour créer des applications NDK pour la plate-forme Intel Atom, vous devez ajouter APP_ABI := x86 au fichier MakeFile.
Figure 5 : Créer le fichier MakeFile
3.1.3 Compiler le code natif
Construisez le code natif en exécutant le script « ndk-build » depuis le répertoire du projet. Il se trouve au niveau supérieur du répertoire du NDK. Le résultat est montré dans la Figure 6.
Figure 6 : Code natif compilé
Les outils de compilation copient automatiquement les bibliothèques partagées nettoyées à l’emplacement correct dans le répertoire du projet de l’application.
3.1.4 Appeler le code natif depuis Java
Lorsque vous déployez la bibliothèque partagée avec succès, vous pouvez appeler la fonction depuis Java. Le code est montré dans la Figure 7. Un appel de fonction native publique stringFromJNI() est créé en code Java, puis cette fonction charge la bibliothèque partagée en utilisant System.loadlibrary().
Figure 7 : Appeler le code natif depuis Java
3.1.5 Déboguer avec GDB
Si vous voulez déboguer l’application NDK avec GDB, les conditions suivantes doivent être remplies :
- L’application NDK est compilée avec « ndk-build »
- L’application NDK est configurée sur « debuggable » dans Android.manifest
- L’application NDK est exécutée sur Android 2.2 (ou une version supérieure)
- Une seule cible est en cours d’exécution
- Ajouter le répertoire d’adb au PATH
Utilisez la commande ndk-gdb pour déboguer l’application. Vous pouvez définir un point d’arrêt ou utiliser un débogage pas à pas pour suivre l'historique des changements d'une valeur de variable comme illustré dans la Figure 8.
Figure 8 : Déboguer une application NDK avec GDB
3.2 Portage d’applications NDK existantes sur des appareils basés sur le processeur Intel Atom
Dans cette section, nous prenons pour hypothèse que vous avez une application Android pour la plate-forme ARM et que vous devez la porter avant de la déployer sur la plate-forme Intel Atom.
Le portage d’applications Android sur la plate-forme Intel Atom est similaire au processus de développement. Les étapes sont montrées dans la Figure 9.
Figure 9 : Porter des applications Android sur la plate-forme Intel Atom
3.2.1 Porter des applications Dalvik
Les applications Dalvik peuvent être exécutées directement sur des appareils basés sur le processeur Intel Atom. L’interface utilisateur doit être ajustée pour l’appareil cible. Pour un appareil haute résolution, comme une tablette dotée d’une résolution de 1280*800 ou supérieure, il est possible que l’allocation de mémoire par défaut ne remplisse pas les exigences de l’application, ce qui entraîne l’incapacité de lancer l’application. Nous vous recommandons d’accroître l’allocation de mémoire par défaut pour les appareils haute résolution.
3.2.2 Porter des applications NDK Android
Le portage d’applications NDK est un peu plus compliqué que le portage d’applications Dalvik. Toutes les applications NDK peuvent être divisées en trois types en fonction des propriétés suivantes du code natif :
- Constitué uniquement de code C/C++ non lié au matériel
- Utilise une DLL tierce
- Inclut du code d’assemblage qui est hautement lié à des plates-formes qui ne sont pas d’architecture Intel
Code natif constitué uniquement de code C/C++ non lié au matériel
- Recompilez le code natif pour exécuter l’application sur la plate-forme Intel Atom avec succès.
- Ouvrez le projet NDK, recherchez le fichier Android.mk et ajoutez APP_ABI := armeabi armeabi-v7a x86 au fichier Android.mk et recompilez le code natif avec ndk-build.
- Si le fichier Android.mk est introuvable, utilisez la commande ndk-build APP_ABI="armeabi armeabi-v7a x86" pour compiler le projet.
- Créez à nouveau le package d’application avec les plates-formes x86 prises en charge.
Si le code natif utilise une DLL tierce, la bibliothèque partagée doit être recompilée en version x86 pour la plate-forme Intel Atom.
Si le code natif contient du code d’assemblage hautement lié à des plates-formes qui ne sont pas d'architecture Intel, le code doit être réécrit avec un assemblage d’architecture Intel ou en C/C++.
4. Meilleures méthodes connues de développement de code natif
4.1 Alignement de mémoire forcé
En raison des différences qui existent entre les architectures, les plates-formes et les compilateurs, la taille des données d’une même structure de données peut être différente sur des plates-formes différentes. Sans alignement de mémoire forcé, des erreurs de chargement peuvent se produire en raison des différences de taille des données. [2]
L’exemple suivant explique les tailles de données de la même structure de données sur des plates-formes différentes :
struct TestStruct {
int mVar1;
long long mVar2;
int mVar3;
};
Il s’agit d’une structure simple possédant trois variables appelées mVar1, mVar2 et mVar3.
mVar1 est une int, et elle coûte 4 octets
mVar2 est une long long int, qui coûte 8 octets
mVar3 est aussi une int, qui coûte 4 octets.
Combien d’espace est nécessaire sur les plates-formes ARM et Intel Atom ?
La taille des données compilées pour les plates-formes ARM et Intel Atom avec le commutateur par défaut du compilateur est montrée dans la Figure 10. ARM adopte automatiquement double malign et occupe 24 octets, alors que x86 occupe 16 octets.
Figure 10 : Mémoire allouée par les balises de compilation par défaut
La variable mVar2 de 8 octets (64 bits) entraîne une disposition différente de TestStruct car ARM nécessite un alignement de 8 octets pour les variables de 64 bits comme mVar2. Dans la plupart des cas, cela ne cause pas de problèmes car la création d’applications x86 depuis des applications ARM nécessite une compilation complète.
Cependant une incohérence de taille peut se produire si une application sérialise les classes ou les structures. Par exemple, vous créez un fichier dans une application ARM et elle écrit une TestStruct dans un fichier. Si vous chargez ensuite les données de ce fichier sur une plate-forme x86, la taille de classe de l’application est différente de celle du fichier. Des problèmes d’alignement de mémoire similaires peuvent se produire dans un trafic réseau qui attend une disposition de mémoire spécifique.
L’option « -malign-double » du compilateur GCC génère le même alignement de mémoire sur x86 et ARM.
Figure 11 : Mémoire allouée lorsque des balises -malign-double sont ajoutées
4.2 Portage d’instructions NEON* sur SSE [3]
4.2.1 NEON
La technologie ARM NEON* est utilisée principalement dans le multimédia, comme dans les applications pour smartphones et téléviseurs haute définition. D’après la documentation ARM, sa technologie basée sur un moteur SIMD de 128 bits, qui est une extension de Cortex*-A Series ARM, offre des performances au moins trois fois supérieures à celles de l’architecture ARMv5 et au moins deux fois supérieures à celles de son successeur, ARMv6. Pour davantage d’informations sur la technologie NEON, consultez : http://www.arm.com/products/processors/technologies/neon.php.
4.2.2 SSE : L’équivalent Intel
SSE est l’extension Streaming SIMD pour l’architecture Intel. Le processeur Intel Atom prend actuellement en charge SSSE3 (Supplemental Streaming SIMD Extensions 3) et les versions antérieures, mais ne prend pas encore en charge SSE4.x. SSE est un moteur 128 bits qui traite le conditionnement des données en virgule flottante. Le modèle d’exécution a commencé avec la technologie MMX et SSx est essentiellement la nouvelle génération remplaçant MMX. Pour plus d’informations, reportez-vous à la section « Volume 1: Basic Architecture » du manuel Intel 64 and IA-32 Architectures Software Developer’s Manuals. La présentation des SSE, dans la section 5.5, fournit les instructions pour SSE, SSE2, SSE3 et SSSE3. Ces opérations sur les données déplacent des valeurs en virgule flottante de précision conditionnées entre des registres XMM ou entre des registres XMM et la mémoire. Les registres XMM sont prévus en remplacement des registres MMX.
4.2.3 NEON vers SSE au niveau de l’assemblage
Alors que vous utilisez le manuel des développeurs de logiciels pour architectures Intel comme référence pour toutes les mnémoniques SSE(x) individuelles, jetez également un coup d’œil aux différentes instructions SSE de niveau assemblage situées à : http://neilkemp.us/src/sse_tutorial/sse_tutorial.html. Utilisez la table des matières pour accéder aux exemples de code ou examiner les informations documentaires.
De même, le manuel suivant d’ARM fournit des informations sur NEON et contient des extraits de code d’assemblage dans la section 1.4, « Developing for NEON » : http://infocenter.arm.com/help/topic/com.arm.doc.dht0002a/DHT0002A_introducing_neon.pdf.
Principales différences entres les codes d’assemblage NEON et SSE :
- Boutisme. Intel prend uniquement en charge l’assemblage petit-boutiste, alors qu’ARM prend en charge les ordres petit-boutiste ou gros-boutiste (ARM est bi-boutiste). Dans les exemples de code fournis, le code ARM est petit-boutiste comme celui d’Intel. Remarque : certaines implications peuvent exister avec le compilateur ARM. Par exemple, la compilation pour ARM avec GCC comprend les balises –mlittle-endian et –mbig-endian. Pour davantage d’informations, reportez-vous à http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html.
- Granularité. Dans le cas des simples exemples de code d’assemblage en référence, comparez les instructions ADDPS pour SSE (Intel) avec VADD.ix pour NEON, comme x = 8 ou 16. Notez que ce dernier introduit de la granularité dans les données à traiter dans le cadre de la mnémonique référencée.
Remarque : ces différences ne sont pas les seules. Vous verrez probablement d’autres différences entre NEON et SSE.
4.2.3 NEON vers SSE au niveau C/C++
De nombreux problèmes d’API peuvent survenir lors du portage de code C/C++ et NEON sur SSE. Gardez à l’esprit la présomption que l’assemblage en ligne n’est pas utilisé mais qu’un veritable code C/C++ est utilisé. Les instructions NEON fournissent également des bibliothèques C natives. Bien que ces instructions soient en code C, elles ne peuvent pas être exécutées sur la plate-forme Intel Atom et doivent être réécrites.
5. Optimisation des performances de l’application
5.1 Réglage des performances
Lors du codage, utilisez les méthodes suivantes pour optimiser les performances de l'application sur la plate-forme Intel Atom.
5.1.1 Utilisez des fonctions en ligne plutôt que des fonctions courtes utilisées fréquemment
Les fonctions en ligne sont le mieux utilisées pour les fonctions courtes telles que l'accès aux membres de données privées. Les fonctions courtes sont sensibles au temps système utilisé par les appels de fonction. Les fonctions plus longues passent proportionnellement moins de temps dans les séquences d’appel/retour et bénéficient moins d’une mise en ligne. [4]
Les fonctions en ligne économisent du temps système sur :
- Les appels de fonction (y compris la transmission des paramètres et le placement de l’adresse de l’objet sur la pile)
- La préservation de la structure de pile de l’appelant
- La configuration d'une nouvelle structure de pile
- La communication de la valeur retournée
- La restauration de l’ancienne structure de pile
- Le retour
5.1.2 Utilisez le calcul en virgule flottante plutôt que le calcul à double précision
FPU est une unité de virgule flottante qui fait partie d’un système informatique spécialement conçu pour réaliser des opérations sur des nombres à virgule flottante, telles que : additions, soustractions, multiplications, divisions et racines carrées. Certains systèmes (notamment les anciennes architectures basées sur des microcodes) peuvent également réaliser différentes fonctions transcendantes comme des calculs exponentiels ou trigonométriques. Les processeurs actuels réalisent ces calculs à l’aide de routines de bibliothèques logicielles. Dans la plupart des architectures informatiques modernes destinées à un usage général, une ou plusieurs FPU sont intégrées à l’UC [6].
La FPU est activée sur la plate-forme Intel Atom. Dans la plupart des cas, l’utilisation d’un calcul en virgule flottante plutôt qu’un calcul à double précision accélère le traitement des données et économise de la largeur de bande mémoire sur les appareils basés sur le processeur Intel Atom.
5.1.3 Codage multithread
Le codage multithread vous permet d’utiliser la fonction d’hyperthreading du processeur Intel Atom afin d’accélérer le débit et d’améliorer les performances générales. Pour davantage d’informations sur le multithreading, reportez-vous à : http://www.intel.com/content/www/fr/fr/architecture-and-technology/hyper-threading/hyper-threading-technology.html.
5.2 Créer des applications hautes performances avec des balises de compilateur
Comme vous le savez, le code natif est créé par GCC dans les applications Android. Mais connaissez-vous l'appareil cible par défaut de GCC ? C’est le processeur Pentium® Pro. Le code binaire ciblé s’exécute mieux sur la plate-forme Pentium Pro si vous n’ajoutez pas de balises lors de la compilation de votre code natif. La plupart des applications Android s’exécutent sur la plate-forme Intel Atom plutôt que sur Pentium Pro. Nous vous recommandons fortement d’ajouter des balises spécifiques en fonction de votre plate-forme cible. Vous pouvez ajouter les balises recommandées suivantes lors de la compilation sur la plate-forme Intel Atom :
-march=atom
-msse4
-mavx
-maes
Pour davantage d’informations sur les paramètres de compilateur, reportez-vous à : http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86-64-Options.html
6. Conclusion
Ce document décrit comment développer et optimiser des applications Android sur les plates-formes Intel Atom et comment développer et porter des applications NDK.
Le résumé des points principaux comprend :
- La plupart des applications Android peuvent s’exécuter directement sur la plate-forme Intel Atom. Les applications NDK doivent recompiler le code natif. Si le code d’assemblage est inclus dans l’application, cette portion du code doit être réécrite.
- Tirez pleinement partie des fonctionnalités de l’architecture Intel pour améliorer les performances de votre application Android.
- Ajoutez des commutateurs de compilation spécifiques à la plate-forme pour que le code compilé par GCC soit plus efficace.
Référence
- http://software.intel.com/en-us/articles/installation-instructions-for-intel-hardware-accelerated-execution-manager-windows/
- http://software.intel.com/en-us/blogs/2011/08/18/understanding-x86-vs-arm-memory-alignment-on-android/
- http://software.intel.com/en-us/articles/ndk-android-application-porting-methodologies/
- http://msdn.microsoft.com/fr-fr/library/1w2887zk.aspx
- http://developer.android.com/sdk/ndk/index.html
- http://fr.wikipedia.org/wiki/Unit%C3%A9_de_calcul_en_virgule_flottante
À propos de l'auteur
Dawei est un ingénieur d’application spécialisé dans les applications mobiles, y compris le développement et l’optimisation d’applications Android pour appareils x86 et le développement d’applications Web HTML5. Dawei possède également une expérience étendue dans la conception d’interfaces utilisateur et d’expériences utilisateur d’applications mobiles.
Avis
LES INFORMATIONS CONTENUES DANS CE DOCUMENT CONCERNENT LES PRODUITS INTEL. LA SOCIÉTÉ INTEL N'ACCORDE AUCUNE LICENCE EXPRESSE, NI IMPLICITE, PAR FORCLUSION OU AUTRE SUR UN DROIT QUELCONQUE DE PROPRIÉTÉ INTELLECTUELLE. À L'EXCEPTION DES DISPOSITIONS PRÉVUES AUX CONDITIONS GÉNÉRALES DE VENTE D'INTEL POUR LESDITS PRODUITS, INTEL DÉCLINE TOUTE RESPONSABILITÉ ET EXCLUT TOUTE GARANTIE EXPLICITE OU IMPLICITE SE RAPPORTANT À LEUR VENTE OU À LEUR UTILISATION. INTEL DÉCLINE NOTAMMENT TOUTE RESPONSABILITÉ ET TOUTE GARANTIE CONCERNANT LEUR ADÉQUATION À UN USAGE PARTICULIER, LEUR QUALITÉ LOYALE ET MARCHANDE, LA CONTREFAÇON DE TOUT BREVET, LA VIOLATION DE DROITS D'AUTEUR OU D'AUTRES DROITS DE PROPRIÉTÉ INTELLECTUELLE.
SAUF ACCORD ÉCRIT D’INTEL DANS CE SENS, SES PRODUITS NE SONT PAS CONÇUS NI PRÉVUS POUR ÊTRE UTILISÉS DANS UN CONTEXTE OÙ LEUR DÉFAILLANCE POURRAIT CONDUIRE À DES SITUATIONS DE PRÉJUDICES CORPORELS OU À LA MORT.
Intel se réserve le droit de modifier à tout moment sans préavis les spécifications et les descriptions de ses produits. Les concepteurs ne doivent pas se fier à l'absence ou aux caractéristiques de fonctionnalités ou d'instructions marquées comme « réservées » ou « non définies ». Intel se réserve la possibilité de compléter ses définitions à l'avenir et ne saurait être tenu responsable de quelque manière que ce soit pour les conflits et les incompatibilités découlant des modifications qui y seront apportées alors. Les informations fournies ici sont sujettes à modification sans préavis, ne finalisez aucune conception avec ces informations.
Les produits décrits dans le présent document peuvent comporter des défauts ou erreurs de conception, connus sous le nom d’errata, susceptibles de faire s’écarter le produit des spécifications publiées. La liste des errata déjà identifiés peut être fournie sur demande.
Interrogez votre point de vente local ou votre distributeur Intel pour obtenir les plus récentes spécifications avant de passer commande d'un produit.
Des copies des documents comportant un numéro d'ordre et référencés dans le présent document ou dans d'autres documents Intel peuvent être obtenues en appelant le 1-800-548-4725 ou depuis le site Web d'Intel : http://www.intel.com/design/literature.htm. Les logiciels et les charges de travail utilisés dans les tests de performances peuvent n'avoir été optimisés que pour des performances sur microprocesseurs Intel. Les tests de performances, comme SYSmark* et MobileMark*, sont mesurés à l'aide d'éléments spécifiques : systèmes informatiques, composants, logiciels, opérations et fonctions. Toute modification de l'un de ces facteurs peut provoquer une variation des résultats. Vous devez consulter d'autres infos et d'autres tests de performances pour évaluer en connaissance de cause les achats que vous envisagez de faire, et notamment les performances de ce produit combiné à d'autres.
Les codes source de logiciel reproduits dans ce document sont fournis dans le cadre d’une licence logicielle et ne peuvent être utilisés ou copiés qu’en accord avec les conditions de cette licence.
Intel, Atom, Pentium et le logo Intel sont des marques commerciales d'Intel Corporation aux États-Unis et/ou dans d'autres pays.
Copyright © 2012 Intel Corporation. Tous droits réservés.
* Les autres noms et désignations peuvent être revendiqués comme marques par des tiers.
**Cet exemple de code source est divulgué dans le cadre du Contrat de licence sur les exemples de code source Intel (Intel Sample Source Code License Agreement).