dimanche 26 avril 2020

Chapitre 87 : assembleur ARM 64 bits : mesure des performances d'une routine


Il y a quelque temps j’avais essayé de porter le programme 32 bits qui indiquait le nombre d’instructions et de cycles d’une routine en assembleur 64 bits. Je n’y étais pas arrivé car l’appel système PERF_EVENT_OPEN n’était pas disponible en 64 bits. J’avais donc essayé de lire les valeurs directement du registre compteur de cycles proposé par le processeur Cortex A53 mais hélas les instructions de type msr ou mrs sont refusées lors de l’exécution d’un programme exécuté avec la version raspbian buster. Je n’ai pas trouvé pourquoi !!
Mais je me suis repenché sur le problème et maintenant le fonctionnement de PERF_EVENT_OPEN est correct en 64 bits. Est-ce la nouvelle version de Buster ? la mise à jour du package linux-perf ? ou la mise en place des packages suivants nécessaires pour la création de modules du kernel :
sudo apt install build-essential fakeroot dpkg-dev perl libssl-dev bc gnupg dirmngr libncurses5-dev libelf-dev flex bison
je l’ignore mais maintenant il est possible d’extraire le nombre d’instructions, le nombre de cycles et le temps pris par des instructions ou une routine.

Je vous conseille de vous plonger dans la documentation (en anglais) de l’appel système linux PERF_EVENT_OPEN car les possibilités sont nombreuses.
Ici je vais utiliser la possibilité de regrouper les 3 mesures dans le même buffer en créant un process leader et 2 process fils. Cette solution permet de lancer en une seule commande la mesure et d’arrêter la mesure grâce à l’identifiant du leader seul. Les commandes utilisent l’appel système IOCTL puis l’appel READ pour lire les résultats.
Les tests du programme mesurePerf1.s  montrent que les résultats sont surprenants. Le comptage des instructions doit tenir compte de toutes les instructions comprises entre les 2 svc de lancement et d’arrêt de la mesure.
Pour les cycles, les résultats sont très variables si on se contente d’une seule mesure. J’ai donc mis une boucle de mille mesures ce qui permet d’avoir une meilleure estimation du nombre de cycles.
Par exemple pour le simple test du mov x0,1, le nombre d’instruction est de 3012, ce qui correspond à 1001 fois les 3 instructions mov, subs et cbnz et les 9 autres instructions comprises entre les 2 svc (et en les comptant).
Pour le nombre de cycles , celui est variable autour de 2080 ce qui semble indiquer que les 3003 instructions de la boucle correspondent à 2000 cycles.
Or je m’attendais à avoir un nombre de cycles supérieur au nombre d’instructions !! Ce n’est pas le cas et la recherche du fonctionnement de ce type de processeur me fait penser que l’on voit là le gain des architectures pipe line de traitement des instructions.
Si on ajoute une instruction mul, le nombre de cycles augmente seulement de mille alors que cette instruction est donnée pour utiliser au minimum 2 cycles.

En ce qui concerne les temps, ils sont très très variables !!! Donc la recherche d’optimisation ne va être très facile sauf à faire tourner les routines des millions de fois pour voir l’évolution d’une modification.

Mais ce n’est que le début et je vais poursuivre des tests en particulier sur la routine de division de nombres de 128 bits utilisée dans le chapitre précédent.
 


2 commentaires:

  1. Bonjour :-) Super job!
    J’ai des problèmes d’accès au chapitre 4, 12 et 14.
    Mon compte google n’est pas autorisé :-p

    RépondreSupprimer
  2. Bonsoir.
    J'ai republié ces chapitres ainsi que le chapitre 87 pour essayer de résoudre ces problèmes car je n'ai rien changé dans blogger pour ces chapitres particuliers.
    Merci et bon courage.

    RépondreSupprimer