ELE-542 Systèmes ordinés en temps réels Cours # 3 Langage C et temps réel Jean-Marc Beaulieu et Bruno De Kelper Site internet: http://www.ele.etsmtl.ca/academique/ele542/ Systèmes ordinés en temps réel 1 Qu’est ce qui influence le temps d’exécution Matériel Matériel Programme Compilateur Compilateur Processeur Taille (8, 16, 32 bits) Instructions Pipeline, cache Mémoire Bus système Programme Optimisation du code Déroulement de boucle Utilisation de registres « Inlining » Instructions spéciales du CPU Algorithmes Choix des variables Type des variables Emplacement en mémoire Choix des opérations Algorithmes Algorithmes 2 Systèmes ordinés en temps réel 1 Le matériel Bus de données Bus d’adresse Mémoire Processeur Systèmes ordinés en temps réel 3 Le langage C pour le temps réel Ce qu’on veut analyser : • En quoi le langage C aide-t-il à la conception temps réel ? • Quelles sont les caractéristiques désirables pour le T.R ? • En C, qu’est-ce qui influence le temps d’exécution ? Pourquoi le langage C ? • • • • Les compilateurs sont très performants; Le temps de développement est beaucoup plus court; Beaucoup de développement déjà existant; Portabilité d’une architecture à une autre. Systèmes ordinés en temps réel 4 2 Architecture du programme Systèmes ordinés en temps réel 5 Modularité en langage C La modularité permet de décomposer un projet en bloc plus facile à gérer. En C, nous avons la notion de fonction et la notion de bloc de code (code entre { }). Au plus haut niveau, l’approche consiste à découper le code en utilisant plusieurs types de fichiers. Identifier les fichiers sources (.c); Identifier les fichiers d’en-têtes et d’inclusions (.h); Identifier les fichiers de données et les fichiers spéciaux. Systèmes ordinés en temps réel 6 3 Sortes de fichiers Sortes de fichiers • .c Code source en C. Le module principal doit contenir la définition de la fonction main(). Permet d’exploiter la compilation séparée. • .obj, .o Code objet. Fonction compilée traduite en assembleur mais non localisée en mémoire. (adresse relative) Code orienté selon un processeur cible. Résultant de la compilation d’une source .c. Systèmes ordinés en temps réel 7 Sortes de fichiers • .h Fichier d’inclusion et d’en-têtes; Utilisation : • #include <math.h> /*répertoire système*/ • #include ”math.h ” /*répertoires courants*/ Contient les déclarations de fonctions (prototype); Contient les structures de données (typedef STRUCT); Contient les définitions communes (#define PI 3.141592); Contient les variables globales. Systèmes ordinés en temps réel 8 4 Sortes de fichiers • .lib Bibliothèque; Regroupement de fonctions compilées sous format objet (.o); Outil tlib pour construire et générer une bibliothèque. • .exe (.hex) Exécutable; Contient un code compilé à charger en mémoire; Comprend le code du programme et de tous ces modules, localisés en mémoire; Résultant de l’édition des liens (Linker). Systèmes ordinés en temps réel 9 Processus de compilation Compilateur : Traduction en langage .h .h .c .h .c Compilateur .lib .o .o Linker .exe machine. Adresse relative. Laisse un espace pour les appels de fonctions. Utilise les prototypes des fonctions appelées pour garder un espace. Étape lente • Votre source appelle; fabs(float); /*nécessite l’entête dans math.h*/ Linker : Assemble toutes les portions de code compilées. Place des adresses absolues. Le code des fonctions provient de vos .o ou des biblio .lib. • Votre source a besoin du code compilé de fabs(), alors il le prendra dans math.lib. Systèmes ordinés en temps réel 10 5 Avantages et désavantages de la modularité Avantages : • Masquage Fonctionnement interne caché. Permet une description du module en terme d ’entrée/sortie sans les détails internes. • Interface par paramètres La description des paramètres indique sur quelles données la fonction va travailler. • Traitement spécifique et restreint Chaque module a une tâche spécifique. • Division possible du travail Chaque membre de l’équipe s’occupe d’un module. Systèmes ordinés en temps réel 11 Avantages et désavantages de la modularité • Auto-suffisance Un module est complet en lui-même. Il peut être testé séparément en lui fournissant des paramètres de vérification. • Compilation séparée On peut recompiler que les sources modifiées avec des utilitaires. (make, project) • Réutilisation On peut réutiliser les blocs dans un autre projet ou encore les commercialiser avec seulement (.lib +.h) Les désavantages sont très faibles : • Ralentissement causé par les accès mémoire supplémentaires (appel de fonctions) Systèmes ordinés en temps réel 12 6 Note sur la programmation Pour éviter … • programme confus; • difficile à déboguer; • difficile à modifier ou à adapter. Règles générales d’écriture de programme • Indentation des blocs et des boucles • Aération du code source • En-tête de fonction Description, paramètres E/S, structure, date, auteur) • Commentaires • Nom de variable significatif Systèmes ordinés en temps réel 13 Réentrance Et Passage de paramètres Systèmes ordinés en temps réel 14 7 Réentrance et récursivité Quelques définitions : Réentrance • Propriété d’une fonction qui peut être interrompue et être appelée de nouveau dans la fonction de traitement de l’interruption. Récursivité • Propriété d’une fonction qui s’appelle elle-même. Région critique ou atomique • Partie de code qui ne peut pas être interrompue. Systèmes ordinés en temps réel 15 Réentrance et récursivité En C, les conditions pour avoir une fonction réentrante sont : 1) La fonction utilise seulement des variables locales (sur la pile) -- Attention aux pointeurs; 2) La fonction appelle seulement des fonctions réentrantes; 3) La fonction utilise les variables non locales de façon atomique. -- En C, les accès sont protégés par désactivation des interruptions, sémaphores, etc... Systèmes ordinés en temps réel 16 8 Passage de paramètres Il existe 2 grandes catégories pour le passage de paramètres à une fonction. Par liste de paramètres Passage par valeur; Passage par référence. Par variables globales Systèmes ordinés en temps réel 17 Passage par liste de paramètres Attention…. • Souvent les IRQ sont désactivées durant la copie des paramètres sur la pile. Augmente le temps de latence des interruptions a b c d Prenons un exemple de fonction : float moyenne(a, b, c, d); une IRQ pourrait survenir au milieu du transfert des paramètres sur la pile, et cette IRQ pourrait modifier les valeurs a, b, c, d; Alors on aura pour la fonction moyenne( ) des nouvelles valeurs et des anciennes valeurs. Systèmes ordinés en temps réel 18 9 Passage par variables globales Variables globales • Visibles de tous les modules parce que définies à l’extérieur; • Possibilité de référer en mode d’adressage direct, donc; Plus rapide parce qu’elles ne passent pas par la pile; • Pas nécessaire de désactiver les interruptions; • Seule façon (sauf par registre) de transmettre un paramètre à une routine d ’interruptions. • DANGER n’importe quel module peut modifier la valeur; difficile à documenter Systèmes ordinés en temps réel 19 Comparaison Quoi faire si on a plusieurs paramètres à transmettre à une fonction ? • Rendre toutes les variables globales : peu pratique • Transmettre tous les paramètres : lent, beaucoup d’accès pile • Transmettre un pointeur sur une liste oui, si les valeurs sont placées à la suite en mémoire... En résumé... • Si le temps est "moins" important ou crucial ¾ Liste de paramètres; ¾ Meilleur pour la modularité, encapsulation Æ entretien du code. • Si le temps est très, très important ¾ Variable globale • Si on doit transmettre à une routine d’IRQ ¾ Variable globale Systèmes ordinés en temps réel 20 10 Les données Systèmes ordinés en temps réel 21 Gestion de données Outre les variables GLOBALES et LOCALES Classes d'allocation (Un préfixe à la déclaration…) Permet de spécifier l’endroit où sont emmagasinées les données • Dans la région mémoire de la pile, le heap, les données, un registre; • • • • • Register Static Auto Extern Volatile un registre du CPU sera attribué, si possible…; une variable globale au fichier seulement….; une variable locale est une auto par défaut... pour partager une variable globale entre fichiers… une variable qui est modifiée par des instructions non apparentes Exemple : variable modifiée dans une interruption Systèmes ordinés en temps réel 22 11 Types de données Répertoire • Le langage C possède un grand répertoire de types disponibles au programmeur. Plus facile de structurer les données; Plus grand choix d’espace d’enregistrement; • Exemple : La valeur du CAN 8 bits : unsigned char. Le C permet des opérations sur des types différents. • Mais la conversion implicite peut entraîner une pénalité dans le temps d'exécution. Systèmes ordinés en temps réel 23 Types de données Systèmes ordinés en temps réel 24 12 Opérations sur des données Dépend du processeur Les opérations ont des performances différentes selon le type des données : Dépend du processeur RAPIDE LENT ÷ double float long int int char X double float long int int char + double float long int int char - double float long int int char long int int char & RAPIDE Systèmes ordinés en temps réel 25 Opérations sur des données Soit x,y,z : entiers 16 bits 2 opérations d’addition zLSB = xLSB + yLSB zMSB = xMSB + yMSB+ carry Processeur 8 bits 2 cycles d’écriture 2 cycles de lecture z = x+ y 1 cycle de lecture 1 cycle d’écriture Processeur 16 bits 1 opération d’addition z=x+y Systèmes ordinés en temps réel 26 13 Types de données Conversion implicite des données • En C, les 2 données d’une opération sont converties au type le plus exigeant avant d’effectuer l’opération. Ceci a pour conséquence : • Temps d’exécution plus long *** en général ***; • Mécanisme pas facile à prévoir; Long double double • Exemple de problématique ( le 2 est pris comme un int, alors) unsigned char resul, n = 5; resul = 2 * n; float unsigned long int long int • Solution, la conversion explicite («casting») resul = (unsigned char)2 * n; unsigned int int char • Un autre exemple plus complexe : *(int *)(0x0074) = (int) codec_interrupt; short Systèmes ordinés en temps réel 27 Valeurs logiques versus entiers Le langage C ne possède pas de type booléen, donc les opérations sont faites avec des variables entières (ou char). Pour utiliser efficacement les ressources, on regroupe souvent plusieurs booléens. Zéro = FAUX et non-zéro = VRAI Exemples : Bits 15 - 11 Hours Bits 10 - 5 Minutes Bits 4 - 0 Seconds ÷ 2 MS/DOS packed representation of time. 7 RXC 6 TXC 5 UDRE 4 FE 3 DOR 2 PE 1 U2X 0 MPCM Registre UCSRA du UART du ucontrôleur ATMega16 Réf. : Lewis, Chap. 3 Systèmes ordinés en temps réel 28 14 Deux types d’opérateurs : Booléens et binaires Opérations AND OR XOR NOT Décalage à gauche Décalage à droite Opérateur booléen Opérateur binaire && & || | non-supporté ^ ! ~ non-supporté << non-supporté >> Tester un bit if ((bits != 0) Test 6 */ if (bits&&64) (1 << 6)) /* /* Test dudu bitbit 6 */ b7b6b5b4b3b2b1b0 Réf. : Lewis, Chap. 3 & 0b6000000 01000000 Systèmes ordinés en temps réel 29 Opérations sur les bits Assigner un bit bits = bits | (1 << 7) ; b7b6b5b4b3b2b1b0 | /* sets bit 7 */ 10000000 1 b6b5b4b3b2b1b0 Remise à zéro d’un bit bits &= ~(1 << 7) ; Note : Réf. : Lewis, Chap. 3 (1 << 7) ~(1 << 7) /* resets bit 7 */ 10000000 01111111 Systèmes ordinés en temps réel 30 15 Opérations sur les bits Inverser un bit – XOR bits ^= (1 << 6) ; /* inversion du bit 6 */ Attention à la taille par défaut des variables entières (int) selon le compilateur/processeur Si les int sont de 32 bits 0xFFFFFFFFL & ~(1 << 14) ⇒ 0xFFFFFFFFL & ~(1L << 14)⇒ Si les int sont de 16 bits FFFFBFFF (ok) FFFFBFFF (ok) 0xFFFFFFFFL & ~(1 << 15) ⇒ 0xFFFFFFFFL & ~(1L << 15)⇒ 00007FFF (error) FFFF7FFF (ok) Réf. : Lewis, Chap. 3 Systèmes ordinés en temps réel 31 Utilisation des structures pour manipuler les bits Exemple : struct { unsigned Bits 15 - 11 Hours seconds minutes hours Bits 10 - 5 Minutes Bits 4 - 0 Seconds ÷ 2 :5 , :6 , :5 ; } time ; time.hours = 13 ; time.minutes = 34 ; time.seconds = 18 / 2 ; Réf. : Lewis, Chap. 3 Systèmes ordinés en temps réel 32 16 Exemple : Bits réservés mais inutilisés typedef struct { unsigned CF PF AF ZF SF TF IF DF OF :1, :1, :1, :1, :1, :1, :1, :1, :1, :1, :1, :1, :4 ; /* /* /* /* /* /* /* /* /* /* /* /* /* Bit 0: Carry Flag Bit 1: (unused) Bit 2: Parity Flag Bit 3: (unused) Bit 4: Auxiliary Carry Flag Bit 5: (unused) Bit 6: Zero Flag Bit 7: Sign Flag Bit 8: Trap Flag Bit 9: Interrupt Enable Flag Bit 10: Direction Flag Bit 11: Overflow Flag Bits 12-15: (unused) */ */ */ */ */ */ */ */ */ */ */ */ */ } PSW ; Réf. : Lewis, Chap. 3 Systèmes ordinés en temps réel 33 Accès selon différents types – UNION Vous voulez accéder aux mêmes cases mémoires mais en utilisant des types différents. union { unsigned long dd ; unsigned short dw[2] ; unsigned char db[4] ; }; 31 0 dd dw[1] db[3] db[2] 31 24 23 dw[0] db[1] db[0] 16 15 87 0 Occupe le même espace en mémoire Réf. : Lewis, Chap. 3 Systèmes ordinés en temps réel 34 17 Exemple : Structure et union de bits typedef union { struct { char TXB8 :1, RXB8 :1, UCSZ2 :1, TXEN :1, RXEN :1, UDRIE :1, TXCIE :1, RXCIE :1, } Bits; unsigned char Byte; } USCRB ; Réf. : Lewis, Chap. 3 /* Bit 8 : transmission /* Bit 8 : réception /* MSB de Taille de données /* Activation du transmetteur /* Activation du récepteur /* Registre de donnée vide /* Fin de transmission /* Fin de réception */ */ */ */ */ */ */ */ Exemple d’utilisation : UCSRB.Byte = (char) 0x00; UCSRB.Bits.TXEN = 1; UCSRB.Bits.RXEN = 1; Systèmes ordinés en temps réel 35 Accès aux ports d’entrées / sorties Accès de type « I/O Mapped » Utilisation d’instructions spéciales (IN ou OUT) ou de fonctions C [inportb() ou outportb()]. Certains ports sont accessibles seulement en lecture ou en écriture. Plusieurs registres peuvent avoir la même adresse dans l’espace des adresses E/S. • Dans ce cas, la procédure d’accès est importante (ordre d’accès, lecture/écriture, bit de sélection, …). Exemple : // lire contenu du registre de données, port série COM3, 8250 carac_recu = inportb (0x03E8); Systèmes ordinés en temps réel 36 18 Compilateur Systèmes ordinés en temps réel 37 Techniques d’optimisation utilisées par les compilateurs Utilisation d’identités arithmétique Utilise les identités arithmétique pour éliminer des opérations inutiles tels que : z = x + 1*y → z = x + y z = 3*x + 0 → z = 3*x Réduction de force des opérations Choisit les instructions les plus performantes, tel que z = 8*x → z = x << 3 Élimination de sous expressions communes Regroupe des sous expressions communes, tel que x = y + a*b y = a*b + z t = a*b x=y+t y=t+z Systèmes ordinés en temps réel 38 19 Techniques d’optimisation utilisées par les compilateurs Utilisation de fonctions intrinsèque Remplace des appels de fonctions par des « macro » insérées directement à la place de l’appel de fonction. Pliage de constantes Regroupe les constantes ensembles, tel que z = 7*x*2 → z = 14*x Optimisation des parties invariantes des boucles Extrait les parties des boucles qui ne changent pas, tel que x = 100; while (x > 0) { x = x – y + z; } x = 100; t = y + z; while (x > 0) { x = x + t; } Systèmes ordinés en temps réel 39 Techniques d’optimisation utilisées par les compilateurs Élimination des inductions dans les boucles Élimination des calculs de « décalage » inutiles, tel que for (i = 0; i < 10; i++) a[i+2] = 1; for (i = 2; i < 12; i++) a[i] = 1; Utilisation de registres et de mémoire cache Place les variables fréquemment utilisées dans des registres du processeur ou dans la mémoire cache. Élimination de code « mort » ou inatteignable Élimine le code qui ne sera jamais exécuté, tel que debug = 0; if (debug) x = x + t; Systèmes ordinés en temps réel 40 20 Techniques d’optimisation utilisées par les compilateurs Propagation de constantes Certaines assignations à des variables peuvent être remplacées par des constantes, tel que x = 100; y = x; x = 100; y = 100; Élimination de stockage « mort » ou inutile Certaines variables utilisées pour du stockage temporaire peuvent être éliminées, tel que t = y + z; x = sin(y+z); x = sin(t); Élimination de variables « mortes » Élimine les variables qui semblent inutiles, tel que x = y + z; x = y; x = y; Systèmes ordinés en temps réel 41 Techniques d’optimisation utilisées par les compilateurs Équations logiques court-circuitées Transforme une équation logique compliquée en une série de sous-expressions qui seront évalué une à la fois, tel que if (x > 0) if (y > 0) z = 1; if (x > 0) && (y > 0) z = 1; Déroulement de boucle Déroule les boucles courtes, tel que for (i = 0; i < 3; i++) a[i] = 7*b[i+2]; a[0] = 7*b[2]; a[1] = 7*b[3]; a[2] = 7*b[4]; Systèmes ordinés en temps réel 42 21 Optimisation du code Systèmes ordinés en temps réel 43 Trucs et conseils pour optimiser le code C Limites et mise en garde • Les langages de haut niveau offrent plus ou moins de contrôle sur les instructions générées; • Les options du compilateur (en particulier, le niveau d’optimisation) ont un impact prépondérant sur la performance; • Rien ne peut remplacer la sélection d’algorithmes performants. Systèmes ordinés en temps réel 44 22 Truc 1 – Réduire l’utilisation de la pile Réduire les paramètres et les variables locales. Réduire le nombre de fonctions. • Compromis entre performance et clarté du code. Simuler les fonctions • Il est possible de «simuler ou mimer» les fonctions avec les directives de pré-compilation. Ex. : #define poly2( a , b, c , x) \ ( (a)*(x)*(x)+ (b)*(x)+(c) ) Systèmes ordinés en temps réel 45 Truc 2 - Pas d’allocation dynamique Ne pas utiliser l’allocation de mémoire dynamique. • L’allocation de mémoire fait appel au système d’exploitation pour obtenir une portion de la mémoire disponible; • C’est un processus lent. Solution : • Allocation statique, ou; • Allocation dynamique SEULEMENT durant l’initialisation. Systèmes ordinés en temps réel 46 23 Truc 3 – Variables de type register Déclarer les variables très utilisées (ex. : les compteurs) comme registres. • Mode d'allocation Æ register. Il n’est pas sous garantie que le processeur utilisera un registre, mais c’est souvent le cas. Systèmes ordinés en temps réel 47 Truc 4 – Rendre les conversions explicites Le langage C se convertit toujours au type qui exige le plus de ressources avant de faire des opérations. • Exemple : double multiplicateur = 2.0; int x, n; x = ((int) multiplicateur) * n; Comme x et n sont de type int, on évite que l'opération soit effectuée en double. Systèmes ordinés en temps réel 48 24 Truc 5 – Réduire la complexité mathématique L'objectif est d'utiliser des instructions plus simples pour faire les mêmes calculs (pyramide des instructions). Logiques Bit shift Branchements Plus rapide ADD CMP SUB Multiplication Division Exemple : * 2n Remplacer par un décalage à gauche de n bits; Division par x * 1/x si x ne change pas ou si votre CPU offre une instruction INVERSION plus performante. Racine carrée Systèmes ordinés en temps réel 49 Truc 6 – Éliminer les appels au OS ou au BIOS Les appels au système d'exploitation (ou au BIOS) peuvent être plus lents parce que : • Le système effectue des opérations / vérifications afin de protéger le système. Validation des arguments; Vérification des erreurs. • Implique généralement une interruption logicielle; • Lors des appels au système, celui-ci en profite souvent pour faire des mises à jour internes ("housekeeping") – Exemple : mise à jour de l'horloge. Deux problèmes : • Solution est beaucoup moins portable; • Votre code doit être optimisé – plus vite que celui du OS. Systèmes ordinés en temps réel 50 25 Truc 7 – Ordre dans l'accès au tableau En langage C, les éléments des tableaux sont emmagasinés "par colonnes« . table[5][3] Dans une boucle, optimiser l'accès en "bouclant" d'abord sur le dernier index. Exemple : int somme = 0; for (i=0; i<5;i++) for (j=0;j<3;j++) somme += table[i][j]; Systèmes ordinés en temps réel 51 Truc 8 – Réduire et simplifier les équations On a avantage à éliminer la répétition de calculs Factorisation xp[i] = cos(theta) * x[i] + sin(theta) * y [i]; yp[i] = - sin(theta) * x[i] + cos(theta) * y [i]; c_theta = cos(theta); s_theta = sin(theta); xp[i] = c_theta* x [i] + s_theta * y [i]; Éliminer les opérations inutiles Æ*0 , *1 , +0 , -0 Æa=b x = sqrt ( a2 – b2) Systèmes ordinés en temps réel 52 26 Truc 9 – Pré-calcul des constantes Exemple : • w = 2 * PI * frequence; • #define 2PI 6.28301 • w = 2PI *frequence; Systèmes ordinés en temps réel 53 Truc 10 – Simplifier les boucles Éliminer les expressions constantes ou communes dans les boucles. Exemple : for (i=0; i < 100 ; i++) x[i] = x [i] + 2*w*t; devient z = 2*w * t; for (i=0; i < 100 ; i++) x[i] = x [i] + z; // on sauve 198 multiplications Systèmes ordinés en temps réel 54 27 Truc 11 – Dérouler les petites boucles Dans les petites boucles, on accepte d'augmenter la taille du programme pour éliminer les tests. for (i=1; i < 4 ; i++) x[i] = x [i] + 1; devient x[1] = x [1] + 1; x[2] = x [2] + 1; x[3] = x [3] + 1; On sauve 9 instructions car le "for" est en fait Æ Systèmes ordinés en temps réel INC TEST (…..) JMP 55 Truc 12 – Combiner les boucles Il faut regrouper les boucles : for (i=0; i < 100 ; i++) x[i] = y [i] * 8; for (i=0; i < 100 ; i++) z[i] = x [i] * y[i]; devient for (i=0; i < 100 ; i++) { x[i] = y [i] * 8; z[i] = x [i] * y[i]; } On sauve 300 instructions car le "for" est en fait Æ Systèmes ordinés en temps réel INC TEST (…..) JMP 56 28 Truc 13 – Choisir un type de variable plus simple Lorsqu'on utilise que "certaines propriétés" d'un type on peut essayer de prendre un type plus simple. Exemple : Simuler les variables réelles (float) par une variable entière multipliée par la précision voulue Si la précision sur un calcul est limitée (ex.: par le capteur), alors nous pouvons utiliser des entiers. 1382 138.2 Plus rapide de faire les calculs avec des opérations entières int Float 36 3.6 Systèmes ordinés en temps réel 57 Truc 14 – Table de correspondance Si vous utilisez souvent une fonction mathématique complexe, il peut être avantageux d'échantillonner la fonction et de calculer ses valeurs par interpolation. Exemple : sin (x) = x – x3/3! + x5/5! – x7/7! + x9/9! - … x 0 1 2 3 sin(x) 0 … … … … Note : Possible de perdre de la précision sur la valeur obtenue. Taille du tableau augmente rapidement avec le nombre de variables. Systèmes ordinés en temps réel 58 29 (Truc 15) – Écrire le code en assembleur En principe, il est possible d'écrire le code en assembleur afin d'obtenir la meilleure performance possible. En pratique, Difficile (coûteux) de produire du code assembleur; Difficile (coûteux) de produire du code "plus optimisé" que les compilateurs; Difficile à maintenir et non portable. En pratique, on optimise que des petites portions très critiques du code. • Pas en examen Systèmes ordinés en temps réel 59 Mesure de performance Systèmes ordinés en temps réel 60 30 3.9 Mesure de la performance Objectif : Améliorer l’exécution des portions critiques de notre code en langage C. Mesure : Chronométrage des fonctions • Nous allons voir 3 façons d’estimer le temps d’exécution d’une section de code : Mesure directe • Boucle sur plusieurs itérations; • Chronométrage de haute précision. Décompte d’instructions Décompte des entrées / sorties Trucs possibles Systèmes ordinés en temps réel 61 3.9 Mesure directe de la performance Mesure du temps d’exécution dans une boucle mesure_du_temps_avant; // ex: gettime() ou clock() for (i=0, i < Nb_itération ; i++) ma_fonction ( ); mesure_du_temps_après; Avantages : • Pas besoin d’une mesure très précise de l’horloge; • Moyenne sur les plusieurs exécutions. Inconvénients : • Attention à l’impact du compilateur (i.e. optimisation); • Vérifier la linéarité pour Nb_itération assez grand. Systèmes ordinés en temps réel 62 31 3.9 Mesure du temps – Horloge vs minuterie Deux concepts interreliés Horloge (« Clock ») • Fournie un mesure du temps • Définition : 1 seconde = 1/86 400 de la journée solaire moyenne; 1 seconde = 1/31 566 925.9747 année 1900 au tropique; 1 seconde = 9 192 631 770 vibration Cesium133. • Mesure du temps ↔ intervalle entre deux évènements. Minuterie (« Timer ») • Génère un événement après un intervalle de temps spécifié. Systèmes ordinés en temps réel 63 3.9 ANSI C – Fonction date & time Æ time_t time( time_t *timer ); // timer.h Get current system time as type time_t Résultat : struct tm { int tm_sec; /* seconds after the minute - [0,59] */ int tm_min; /* minutes after the hour - [0,59] */ int tm_hour; /* hours since midnight - [0,23] */ int tm_mday; /* day of the month - [1,31] */ int tm_mon; /* months since January - [0,11] */ int tm_year; /* years since 1900 */ int tm_wday; /* days since Sunday - [0,6] */ int tm_yday; /* days since January 1 - [0,365] */ int tm_isdst; /* daylight savings time flag */ }; Résolution : ± 1 seconde Systèmes ordinés en temps réel 64 32 3.9 ANSI C – Fonction clock Æ clock_t clock( void ); Retourne le nombre de ticks de l’horloge Notes : • • • • typedef long clock_t; Temps en secondes = clock_t/CLOCKS_PER_SEC; Sous Windows2000, CLOCKS_PER_SEC = 1 000; Sous DOS (TurboC), CLOCKS_PER_SEC = 18.2. Résolution : ± 1 milliseconde Systèmes ordinés en temps réel 65 3.9 Test – Clock on Windows2000 Programme de test : start = clock(); Sleep (1); // sleep time in milliseconds finish = clock(); duration = (double)(finish - start) / CLOCKS_PER_SEC; Résultat : • (finish - start) = 15 et duration = 0.015 s • Avec Sleep(0) ou sans Sleep(); • (finish - start) = 0 et duration = 0 Systèmes ordinés en temps réel 66 33 3.9 Mesure du temps – INTEL Mesure du temps d’exécution avec instruction RDTSC : read time-stamp counter Registre de 64 bit incrémenté à chaque cycle du CPU RDTSC Æ 32 bits dans EDX et 32 bits dans EAX Avantages : • Permet une mesure de sections très petites. Inconvénients : • Disponible seulement sur les processeurs Pentiums; • Besoin de « sérialiser » l’exécution; Pentium support l’exécution hors ordre (out-of-order); Les instructions en assembleur ne sont pas nécessairement exécutées dans l’ordre où elles apparaissent dans le code; • Attention à l’impact du compilateur (ex. : optimisation); Chrono.pdf • Vérifier la linéarité. Systèmes ordinés en temps réel Ref: http://www.intel.com/drg/pentiumII/appnotes/rdtscpm1.pdf 67 3.9 Mesure directe de la performance – INTEL Exemple : (Mode DEBUG Æ Pas d’optimisation) float z,q,x,y,result; result=0.0f; x=2.0f; y=100.0f; z=12.0f; q=5.0f; // CODE DANS LA BOUCLE de mesure du temps d'execution z += y; q *= x; result = z/q; Moyenne (5 itérations) Average cycles per loop : Average cycles per loop : Average seconds per loop: 782.000000 (incluant la mesure) 257.000000 (excluant la mesure) 0.000000129 secondes Moyenne (5 000 itérations) Average cycles per loop : Average cycles per loop : Average seconds per loop: 2599.000000 (incluant la mesure) 2074.000000 (excluant la mesure) 0.000001037 secondes Pourquoi ? Systèmes ordinés en temps réel 68 34 3.9 Mesure directe de la performance – INTEL Exemple : (Mode DEBUG Æ Pas d’optimisation) float z,q,x,y,result; result=0.0f; x=2.0f; y=100.0f; z=12.0f; q=5.0f; // CODE DANS LA BOUCLE de mesure du temps d'execution x=2.0f; y=100.0f; z=12.0f; q=5.0f; z += y; q *= x; result = z/q; Temps d’éxécution dépend des données Moyenne (5 itérations) Average cycles per loop : Average cycles per loop : Average seconds per loop: 777.000000 (incluant la mesure) 252.000000 (excluant la mesure) 0.000000126 secondes Moyenne (5 000 itérations) Average cycles per loop : Average cycles per loop : Average seconds per loop: 607.000000 (incluant la mesure) 82.000000 (excluant la mesure) 0.000000041 secondes Optimisation sur plusieurs itérations ? Systèmes ordinés en temps réel 69 3.9 Mesure directe de la performance – INTEL Exemple : (Mode RELEASE Æ optimisation temps d’exécution) float z,q,x,y,result; result=0.0f; x=2.0f; y=100.0f; z=12.0f; q=5.0f; // CODE DANS LA BOUCLE de mesure du temps d'execution x=2.0f; y=100.0f; z=12.0f; q=5.0f; z += y; q *= x; result = z/q; Moyenne (5 itérations) Average cycles per loop : Average cycles per loop : Average seconds per loop: 536.000000 (incluant la mesure) 32.000000 (excluant la mesure) 0.000000016 secondes Moyenne (5 000 itérations) Average cycles per loop : Average cycles per loop : Average seconds per loop: 570.000000 (incluant la mesure) 66.000000 (excluant la mesure) 0.000000033 secondes Compilation Systèmes ordinés en temps réel AVR 70 35 3.9 Décompte des instructions Analyse du code assembleur • Évaluation du temps d’exécution de chaque instruction. Difficultés et limites • Pas facile / impossible d’estimer le temps d’exécution d’une séquence d’instructions sur les architectures complexes; • Souvent le temps d’exécution varie; • Travail laborieux . Exemple : Entrée / sortie par interrogation BYTE8 Serial_Input(void) { /* Attendre l’arrivée d’une nouvelle donnée */ while ((inportb(STATUS_PORT) & READY) == 0) {} return inportb(DATA_PORT) ; } void Serial_Output(BYTE8 ch) { /* Attendre que le périphérique soit prêt */ while ((inportb(STATUS_PORT) & READY) == 0){} outportb(DATA_PORT, ch) ; } Réf. : Lewis, Chap. 6 Systèmes ordinés en temps réel 71 3.9 Décompte des instructions _Serial_Input: SI1: MOV DX,02FDh ; DX Å Status Port Address IN AL,DX ; Read Input Status Port TEST AL,00000001B ; Check the “Ready” Bit JZ SI1 ; Continue to wait if not ready MOV DX,02F8h ; Else load DX with Data Port Address XOR EAX,EAX ; Pre-clear most significant bits of EAX IN AL,DX ; Read Data Port RET Réf: Lewis Chap 6. ; return to caller with data in EAX Systèmes ordinés en temps réel 72 36 3.9 Décompte des entrées / sorties Modèle approximatif basé sur l’observation que la performance est souvent limitée par le temps nécessaire aux accès mémoire. On doit inclure : • La lecture des instruction; • Les accès aux registres des périphériques. On néglige : • Les facteurs d’accélération dus à la mémoire cache, à la présence d’un pipeline et de plusieurs ALU; • L’estimation est donc pessimiste. ET TRÈS IMPRÉCISE Systèmes ordinés en temps réel Réf: Lewis Chap 6. 73 3.9 Décompte des entrées / sorties _Serial_Input: MOV SI1: IN TEST JZ MOV XOR IN RET DX,02FDh AL,DX AL,00000001B SI1 DX,02F8h EAX,EAX AL,DX ; ; ; ; ; ; ; ; ; ; Opcode Bytes 1 1 1 1 1 1 1 1 Immediate Stack Bytes Bytes 2 I/O Transfers 1 1 1 2 4 1 14 octets pour les instructions , 4 octets pour la pile , 2 octets pour les entrées / sorties Réf. : Lewis, Chap. 6 Systèmes ordinés en temps réel 74 37 3.9 Décompte des entrées / sorties Exemple : Architecture considérée (Æ c.f. lewis) • Accès en mémoire Æ 60 ns; • Bus PCI 33 MHz Æ 30 ns par accès. En général, les transferts demandent plusieurs cycles d’accès. Décompte: (14 octets / (4 octets par cycle)) * 60 ns = 240 ns (instructions) (4 octets / (4 octets par cycle)) * 60 ns = 60 ns (pile) 2 octets * 30 ns = 60 ns (Entrée / sortie) Total = 360 ns Taux de transfert maximum = 1/360 ns = 2.78 Moctets/s Réf. : Lewis, Chap. 6 Systèmes ordinés en temps réel 75 3.9 Décompte des entrées / sorties Autre exemple : Entrées / sorties par interruption Temps de réponse : R = Li + Cs + LIRQV + Ai + Cr Li = temps de la plus longue instruction • • • • PUSHA Æ sauvegarde des registres 1 cycle d’accès mémoire pour l’instruction 8 cycles d’accès mémoire pour écrire les 8 registres 9 * 60 ns = 540 ns LIRQV = temps de traitement de l’interruption (niveau matériel) • • • • 12 octets sur la pile (3 cycles) 1 octet E/S (lecture du vecteur) 16 octets pour chargement PC (4 cycles) Total Réf. : Lewis, Chap. 6 Systèmes ordinés en temps réel Æ 180 ns Æ 30 ns Æ 240 ns = 450 ns 76 38 3.9 Interruptions – Intel x86 (mode protégé) Réponse aux interruptions Action Bytes Transferred Detailed description 1. Push EFlags register. ESP ← ESP - 4; MEM32[ESP] ← EFlags 4 (stack write) 2. Disable interrupts. IF Flag ← 0 (Also clears TF Flag) n/a 3. Push CS ESP ← ESP - 4; MEM32 [ESP] ← CS 4 (stack write) 3. Push EIP ESP ← ESP - 4; MEM32 [ESP] ← EIP 4 (stack write) 4. Identify interrupt. Read interrupt type code from data bus. 1 (I/O read) 5. Load CS and EIP CSvisible,EIP ← IDT64[8 × int. type code] CShidden Å GDT64[CSvisible] 8 (IDT read) + 8 (GDT read) Réf. : Lewis, Chap. 6 Systèmes ordinés en temps réel 77 3.9 Décompte des entrées / sorties Instr. Data Bytes Bytes _Serial_Input_ISR: STI PUSH PUSH MOV IN MOV MOV OUT POP POP IRET ; Enable high prior. Ints. 1 EAX ; Preserve contents 1 EDX ; of EAX and EDX. 1 DX,02FDh ; Retrieve the data and 3 AL,DX ; clear the request. 1 [_serial_data],AL ; Save the data away. 5 AL,00100000b ; Send EOI command to 2 20h,AL ; Prog. Interrupt Ctlr. 2 EDX ; Restore orig. contents 1 EAX ; of the registers. 1 ; Restore EIP and EFlags. 1 Stack Bytes I/O Transfers 4 4 1 1 4 4 12 1 19 octets pour les instructions , 1 octet pour la donnée 28 octets pour la pile , 2 octets pour les entrées / sorties Réf. : Lewis, Chap. 6 Systèmes ordinés en temps réel 78 39 3.9 Décompte des entrées / sorties Décompte : (19 octets / (4 octets par cycle)) * 60 ns = 300 ns (instructions) (28 octets / (4 octets par cycle)) * 60 ns = 420 ns (pile) ( 1 octet / (4 octets par cycle)) * 60 ns = 60 ns (donnée) 2 octets * 30 ns = 60 ns (Entrées / sorties) Total = 840 ns Taux de transfert maximum = 1/1.95 µs = 0.513 Moctets/s Finir l’instruction PUSHA: 0.54 µs Réponse matérielle Temps d’exécution 0.45 µs 0.84 µs Total = 1.95 µs Réf: Lewis Chap 6. Systèmes ordinés en temps réel 79 40