Vous êtes sur la page 1sur 11

Conception de systèmes en temps réel

Université de Sherbrooke, régulier et DGL, STR

http://h-deb.clg.qc.ca/UdeS/STR/index.html

Vous trouverez ici quelques documents et quelques liens pouvant, je l'espère, vous être utiles. Vous pouvez aussi consulter, parmi les liens divers mis à votre disposition, ceux portant sur les STR, ceux portant sur la multiprogrammation et ceux portant sur l'optimisation.

Ce cours est particulier en ce sens qu'il aura été offert, sous une forme semblable, à la fois (mais parfois lors de sessions distinctes) aux étudiant(e)s du DGL (de la MGL,

 

en fait) au Campus Longueuil, et aux étudiant(e)s de fin de baccalauréat et de maîtrise au Campus Sherbrooke. Si

Les documents qui vous sont fournis ici le sont pour vous rendre service.

Je travaille très fort sur chacun de mes cours. Veuillez ne pas vendre (ou donner) les documents que je vous offre ici à qui que ce soit sans mon consentement. Si des abus surviennent, je vais cesser de rendre ce matériel disponible à toutes et à tous.

Si ces documents vous rendent service, faites-le moi savoir. Mon adresse de courriel est disponible sur la page où on trouve mon horaire.

vous remarquez des « références culturelles » particulières, de part et d'autres, c'est sans doute la raison.

Notez aussi que le découpage en séances de ces deux cours diffère, les calendriers des deux campus étant distincts. Ces différences seront compensées par un ajout de 15 minutes au début de chaque séance du cours

IFT729.

Petit menu

IFT729

INF749

Plan de cours

Plan de cours

Consignes quant au projet de session

Consignes quant au projet de session

Sur ce site, vous trouverez :

quelques idées de projets soumises au fil des sessions (pour celles et ceux qui cherchent l'inspiration); le code de quelques cas sous étude dans les notes de cours; des petits descriptifs en lien avec chaque séance en classe; les résultats des divers minitests distribués au cours de la session (IFT729, INF749); les résultats des évaluations des livrables (IFT729, INF749); en lien avec les séances sur QNX.

De belles idées de projets

Il arrive que j'aie en classe des étudiant(e)s qui ont déjà suivi des cours avec moi où l'on trouvait un besoin de multiprogrammation ou de programmation générique.

Malheureusement, faute de préalables, je ne peux pas supposer que tous et toutes ont les bases nécessaires pour escamoter ces concepts, alors j'implore votre tolérance, surtout pour les deux ou trois premières séances, si vous rencontrez des éléments de matière qui sont, pour vous, du déjà vu.

Pour vous donner un aperçu de quelques idées de projets soumises par vos prédécesseurs, voici quelques-uns de ceux qui ont été proposés par le passé :

un outil de modification dynamique en temps réel de la complexité des maillages affichés dans une scène tridimensionnelle; un outil de modification de scène tridimensionnelle collaboratif en temps réel à travers plusieurs ordinateurs; un outil de filtrage en temps réel de pourriel; un outil pour transformer un appareil cellulaire en volant de véhicule pour interagir avec certains jeux vidéos;

une extension d'un outil de localisation universel au monde de la téléphonie mobile, avec intégration au GPS et au WiFi; un simulateur de chimie artificielle (interactions dynamiques entre certaines molécules); un agent intelligent capable de coordonner des actions dans un véritable jeu de stratégie (StarCraft, si je me souviens bien) en temps réel (projet qui ressemble un peu à un exécutif); un outil de peinture aux doigts virtuelle; jeu de cowboys et de veaux avec une guitare de Guitar Hero (fallait le voir pour le croire); véritable voiture (format réduit) qui détecte les collisions de manière préventive; logiciel transformant des Nintendo DS en Walkie Talkie sur WiFi; un outil d'immersion apparente dans un environnement virtuel à l'aide d'une Wiimote; un éditeur de texte multi-usagers réparti avec mises à jour en temps réel des éditions faites par l'un sur l'écran des autres, incluant les opérations « coller » et les opérations « annuler »; étudier les possibilités d'une Kinect pour télévigilance; moteur pour jouer une séquence de MP3 en continu, sans interruptions (ou, du moins, avec interruptions telles que l'oreille humaine ne les détectera pas);

jeu de type Tower Defense sur Android; jeu en réseau sur plateforme Unity; interaction avec minuterie de cuisine; utiliser une Wiimote pour jouer au billard; intelligences artificielles se séparant le temps résiduel d'un affichage à rythme constant et trouvant leur chemin dans un labyrinthe avec obstacles mobiles; simulation de molécules interagissant en grand nombre, avec collisions élastiques; intelligence artificielle morcelable pour jeu de course; réseau de neurones morcelable pour analyse de trafic réseau; vision stéréoscopique à partir d'une Wiimote et d'une paire de lunettes « maison »; système de détection d'intrusions grâce à une Kinect, associé à un lance-missiles USB; reconnaissance du langage des signes et prononciation des mots associés aux gestes reconnus; étude de la distribution de la chaleur dans le corps humain; transformer un téléphone intelligent en instrument de musique à l'aide de son gyroscope et de son accéléromètre; créer un module d'authentification résistant aux attaques par force brute en contrôlant de manière stricte les temps de réponses aux tentatives de connexion incorrectes.

À propos des séances en classe

 

Index des séances théoriques

 

IFT729

S00

S01

S02

S03

S04

S05

S06

S07

S08

S09

S10

S11

S12

   

INF749

S00

S01

S02

S03

S04

S05

S06

S07

S08

S09

S10

S11

S12

S13

S14

Conception de systèmes en temps réel

http://h-deb.clg.qc.ca/UdeS/STR/index.html

Pendant les premières séances, nous examinerons surtout des concepts et techniques de base, qui seront réinvestis dans les exemples et les illustrations concrètes que proposera le professeur.

Ce sont donc des séances plus près de la (saine) programmation au sens large que des STR de manière spécifique.

D'autres approches sont possibles pour un cours de STR, évidemment, mais le choix pédagogique fait par votre chic prof de discuter à la fois de théorie et de pratique demande de mettre sur pied quelques bases au préalable. Je vous remercie de votre tolérance (et, si vous avez apprécié, alors tant mieux!).

 

IFT729

 

INF749

Date

Séance

Contenu

Date

Séance

 

Contenu

18

S00

 

8

S00

 

janvier

Exceptionnellement, cette séance se tiendra un vendredi de 8 h 30 à 11 h 20.

janvier

Au menu :

Au menu :

mise en place d'éléments de vocabulaire; discussion sur la distinction importante entre programmes en temps réel et programmes rapides, du moins dans le cas des STR stricts, et sur les nuances dans le discours quant à la question même de l'idée de temps réel, qui porte plusieurs sens, affectant différemment les gens en fonction de leur domaine d'expertise et de leur milieu de travail. Le tout dans le but de situer les un(e)s et les autres quant au contenu du cours et quant au projet de session qui vous est proposé; présentation du cours et des approches choisies pour y traiter des sujets qui nous y tiennent à coeur; bref tableau de façons de faire que nous utiliserons dans les exemples proposés en classe et dans les notes de cours. Ceci inclut des exemples utilisant entre autres des foncteurs, de la généricité par des templates, un algorithme standard (for_each()) et, pour le plaisir, une λ-expressions.

Petit complément : j'ai rédigé un petit comparatif de performance pour certaines opérations types applicables à un tableau brut, alloué dynamiquement, et à un vecteur standard. Je ne l'ai pas indiqué en classe encore, mais il s'avère que, lorsqu'il est bien utilisé, le vecteur est presque toujours aussi rapide – ou plus rapide! – que son substrat, le tableau brut, parce que le code sous-jacent est extrêmement sophistiqué. Le dire, c'est une chose, mais le démontrer, c'est mieux, alors l'exemple vous attend ici si vous êtes intéressé(e).

Dans les notes de cours, vous trouverez de la matière en lien avec cette séance dans STR – Volume 00 (vocabulaire,

mise en place d'éléments de vocabulaire; discussion sur la distinction importante entre programmes en temps réel et programmes rapides, du moins dans le cas des STR stricts, et sur les nuances dans le discours quant à la question même de l'idée de temps réel, qui porte plusieurs sens, affectant différemment les gens en fonction de leur domaine d'expertise et de leur milieu de travail. Le tout dans le but de situer les un(e)s et les autres quant au contenu du cours et quant au projet de session qui vous est proposé; présentation du cours et des approches choisies pour y traiter des sujets qui nous y tiennent à coeur; bref tableau de façons de faire que nous utiliserons dans les exemples proposés en classe et dans les notes de cours. Ceci inclut des exemples utilisant entre autres des foncteurs, de la généricité par des templates, un algorithme standard (for_each()) et, pour le plaisir, une λ-expressions.

Petit complément : j'ai rédigé un petit comparatif de performance pour certaines opérations types applicables à un tableau brut, alloué dynamiquement, et à un vecteur standard. Je ne l'ai pas indiqué en classe encore, mais il s'avère que, lorsqu'il est bien utilisé, le vecteur est presque toujours aussi rapide – ou plus rapide! – que son substrat, le tableau brut, parce que le code sous-jacent est extrêmement sophistiqué. Le dire, c'est une chose, mais le démontrer, c'est mieux, alors l'exemple vous attend ici si vous êtes intéressé(e).

Dans les notes de cours, vous trouverez de la matière en lien avec cette séance dans STR – Volume 00 (vocabulaire,

donc les pages 5

35).

donc les pages 5

35).

 

25

S01

15

S01

 

janvier

 

Exceptionnellement, cette séance se tiendra un vendredi de 8 h 30 à 11 h 20.

janvier

Au menu, d'une manière teintée par notre besoin d'avoir une approche appropriée pour le développement de STR :

Au menu, d'une manière teintée par notre besoin d'avoir une approche appropriée pour le développement de STR :

retour sur le sujet de la programmation générique en C++, qui est différente de ce qu'on trouve dans bien d'autres langages. en particulier :

retour sur le sujet de la programmation générique en C++, qui est différente de ce qu'on trouve dans bien d'autres langages. en particulier :

générique en C++ , qui est différente de ce qu'on trouve dans bien d'autres langages. en
trouve dans bien d'autres langages. en particulier : les algorithmes ( for_each() , bien sûr, mais

les algorithmes (for_each(), bien sûr, mais aussi transform(), accumulate(), find_if(), etc.);

les conteneurs standards et la théorie des itérateurs; les foncteurs; nuances entre fonction et foncteur, entre autres à l'aide d'un programme de test; sémantique de mouvement.

nuances entre fonction et foncteur , entre autres à l'aide d'un programme de test ; sémantique
nuances entre fonction et foncteur , entre autres à l'aide d'un programme de test ; sémantique

les algorithmes (for_each(), bien sûr, mais aussi transform(), accumulate(), find_if(), etc.);

les conteneurs standards et la théorie des itérateurs; les foncteurs; sémantique de mouvement.

itérateurs ; les foncteurs ; sémantique de mouvement . Munis des idées et techniques mises de
itérateurs ; les foncteurs ; sémantique de mouvement . Munis des idées et techniques mises de

Munis des idées et techniques mises de l'avant dans cette séance, vous devriez être en mesure de comprendre les

Munis des idées et techniques mises de l'avant dans cette séance, vous devriez être en mesure de comprendre les exemples dans STR – Volume 01 (voir le code des cas sous étude). Profitez de l'opportunité pour expérimenter avec ces propositions de tests, pour les modifier, pour essayer de comprendre les métriques que vous parviendrez à en tirer, etc.

Dans les notes de cours, comme mentionné dans le paragraphe précédent, vous trouverez de la matière en lien avec cette séance dans STR – Volume 01.

exemples dans STR – Volume 01

(voir le code des cas sous

étude). Profitez de l'opportunité pour expérimenter avec ces propositions de tests, pour les modifier, pour essayer de comprendre les métriques que vous parviendrez à en tirer, etc.

Dans les notes de cours, comme mentionné dans le paragraphe précédent, vous trouverez de la matière en lien avec cette séance dans STR – Volume 01.

Avant de quitter, je vous ai glissé un mot sur

Conception de systèmes en temps réel

http://h-deb.clg.qc.ca/UdeS/STR/index.html

1 février 4 février S02 S03 un bogue du compilateur sous-jacent à Visual Studio et

1

février

4 février

1 février 4 février S02 S03 un bogue du compilateur sous-jacent à Visual Studio et décrit

S02

S03

un bogue du compilateur sous-jacent à Visual Studio et décrit (avec sa solution) par Stephan T. Lavavej. Si vous voulez des détails, voir http://channel9.msdn.com

/Series/C9-Lectures-Stephan-T-Lavavej-

Core-C- (en particulier la partie 7 de n, qui est celle à laquelle je faisais référence).

Exceptionnellement, cette séance se tiendra un vendredi de 8 h 30 à 11 h 20.

Au menu :

question Q00; survol rapide des traits; petite excursion dans le monde des itérateurs :

catégories, opérations, forces, faiblesses, usages; poursuite de l'examen des itérateurs, en lien avec la fonction distance(), le calcul de la moyenne et l'exemple amusant d'un trait est_convertible.

La fonction std::distance() est un cas d'espèce intéressant, tiré du standard lui-même, qui exploite les traits et les catégories pour réaliser une optimisation presque obscène. J'aime bien faire le tour de cette approche, qui peut être appliquée à bien d'autres trucs, avec des gens qui, comme vous, doivent écrire des programmes dont les performances sont sans compromis.

Dans les notes de cours, vous trouverez de la matière en lien avec cette séance dans STR – Volume 00, annexes 00 et 01, mais vous en trouverez surtout dans les liens ci-dessus.

Au menu :

question Q01; examen d'une stratégie interruptible de compression de données, incluant :

le concept général (une espèce de fonction interruptible_foreach() ); interruptible_foreach());

impact des choix d'implémentation sur les performances à l'exécution, et apport de l'encapsulation dans la résolution de problèmes de ce genre;(une espèce de fonction interruptible_foreach() ); traits de fonctions : approche traditionnelle et pratiques

traits de fonctions : approche traditionnelle et pratiques plus contemporaines; de fonctions : approche traditionnelle et pratiques plus contemporaines;

implémentation d'une minuterie RAII générique sur la base d'un outil de mesure ( voir ceci pour plus de RAII générique sur la base d'un outil de mesure (voir ceci pour plus de détails);

consommation de données brutes d'un fichier binaire (voir ceci pour des détails ); voir ceci pour des détails);

survol de l'idiome d'objets incopiables ; objets incopiables;

utilisation créative d'algorithmes standards et de foncteurs ; foncteurs;

fonctions génératrices et allègement syntaxique;créative d'algorithmes standards et de foncteurs ; survolerons par le fait-même quelques idées préliminaires

survolerons par le fait-même quelques idées préliminaires en métaprogrammation (entre autres, les alternatives statiques et static_assert ); métaprogrammation (entre autres, les alternatives statiques et static_assert);

approche monolithique et approche morcelable à la résolution d'un même problème.quelques idées préliminaires en métaprogrammation (entre autres, les alternatives statiques et static_assert );

morcelable à la résolution d'un même problème. 22 janvier 29 janvier S02 S03 Au menu :

22

janvier

29

janvier

d'un même problème. 22 janvier 29 janvier S02 S03 Au menu : question Q00 ; survol

S02

S03

d'un même problème. 22 janvier 29 janvier S02 S03 Au menu : question Q00 ; survol

Au menu :

question Q00; survol rapide des traits; petite excursion dans le monde des itérateurs :

catégories, opérations, forces, faiblesses, usages; poursuite de l'examen des itérateurs, en lien avec la fonction distance(), le calcul de la moyenne et l'exemple amusant d'un trait est_convertible.

La fonction std::distance() est un cas d'espèce intéressant, tiré du standard lui-même, qui exploite les traits et les catégories pour réaliser une optimisation presque obscène. J'aime bien faire le tour de cette approche, qui peut être appliquée à bien d'autres trucs, avec des gens qui, comme vous, doivent écrire des programmes dont les performances sont sans compromis.

Par la suite, nous avons commencé à examiner une stratégie interruptible de compression de données. Ce fut bref, par contre, et nous avons couvert quelques idées préliminaires en métaprogrammation (entre autres, les alternatives statiques et static_assert).

Parce que nous avançons un peu plus rapidement que prévu, nous avons amorcé la discussion des tâches morcelables, à l'aide d'une stratégie interruptible de compression de données.

Dans les notes de cours, vous trouverez de la matière en lien avec cette séance dans STR – Volume 00, annexes 00 et 01, mais vous en trouverez surtout dans les liens ci-dessus.

Au menu :

question Q01; poursuite de notre examen d'une stratégie interruptible de compression de données, incluant :

le concept général (une espèce de fonction interruptible_foreach() ); interruptible_foreach());

impact des choix d'implémentation sur les performances à l'exécution, et apport de l'encapsulation dans la résolution de problèmes de ce genre;(une espèce de fonction interruptible_foreach() ); traits de fonctions : approche traditionnelle et pratiques

traits de fonctions : approche traditionnelle et pratiques plus contemporaines; de fonctions : approche traditionnelle et pratiques plus contemporaines;

implémentation d'une minuterie RAII générique sur la base d'un outil de mesure ( voir ceci pour plus de RAII générique sur la base d'un outil de mesure (voir ceci pour plus de détails);

consommation de données brutes d'un fichier binaire (voir ceci pour des détails ); voir ceci pour des détails);

survol de l'idiome d'objets incopiables ; objets incopiables;

utilisation créative d'algorithmes standards et de foncteurs ; foncteurs;

fonctions génératrices et allègement syntaxique;créative d'algorithmes standards et de foncteurs ; approche monolithique et approche morcelable à la

approche monolithique et approche morcelable à la résolution d'un même problème.; fonctions génératrices et allègement syntaxique; Dans les notes de cours , vous trouverez de la

Dans les notes de cours, vous trouverez de la matière en lien avec cette séance dans STR – Volume 00, annexes 00 et 01, mais vous en trouverez surtout dans les liens ci-dessus.

cette séance dans STR – Volume 00 , annexes 00 et 01 , mais vous en
cette séance dans STR – Volume 00 , annexes 00 et 01 , mais vous en

Conception de systèmes en temps réel

http://h-deb.clg.qc.ca/UdeS/STR/index.html

Dans les notes de cours, vous trouverez de la matière en lien avec cette séance
Dans les notes de cours, vous trouverez de la matière en lien
avec cette séance dans STR – Volume 00, annexes 00 et
01, mais vous en trouverez surtout dans les liens ci-dessus.
En début de séance, je vous ai glissé un mot
sur un bogue du compilateur sous-jacent à
Visual Studio et décrit (avec sa solution) par
Stephan T. Lavavej. Si vous voulez des
détails, voir http://channel9.msdn.com
/Series/C9-Lectures-Stephan-T-Lavavej-
Core-C- (en particulier la partie 7 de n,
qui est celle à laquelle je faisais référence).
11
S04
5
S04
février
février
Au menu :
question Q02;
bref retour sur les nuances entre fonction et foncteur,
entre autres à l'aide d'un programme de test;
bref retour sur l'importance d'échouer tôt, du moins
lorsqu'on échoue :
Au menu :
question Q02;
poursuite de l'étude du cas d'un algorithme de
compression dans sa version monolithique et dans sa
version morcelable;
bref retour sur les nuances entre fonction et foncteur,
entre autres à l'aide d'un programme de test;
bref retour sur l'importance d'échouer tôt, du moins
lorsqu'on échoue :
privilégier un plantage à la
compilation, avec
static_assert, si cela s'avère
possible; sinon
privilégier un plantage en
laboratoire, peut-être avec
assert(), si le problème détecté
est dynamique et irrécupérable; ou
privilégier un plantage à la
compilation, avec
static_assert, si cela s'avère
possible; sinon
privilégier un plantage en
laboratoire, peut-être avec
assert(), si le problème détecté
est dynamique et irrécupérable; ou
privilégier un plantage en
laboratoire, en levant une
exception, si le problème détecté
est dynamique mais nous semble
mener à une situation que le client
ne peut ignorer et d'où le code
client est susceptible de récupérer;
et enfin
privilégier un plantage en
laboratoire, en levant une
exception, si le problème détecté
est dynamique mais nous semble
mener à une situation que le client
ne peut ignorer et d'où le code
client est susceptible de récupérer;
et enfin
retourner des codes d'erreur pour
les situations problématiques que le
client peut ignorer sans que cela
n'entraîne de conséquences trop
fâcheuses;
retourner des codes d'erreur pour
les situations problématiques que le
client peut ignorer sans que cela
n'entraîne de conséquences trop
fâcheuses;
notez que les
exceptions
sont la
manière
correcte de
signaler un
problème
dans un
constructeur
(à moins que
la situation
ne soit
irrécupérable
– voir
ci-dessus),
ceux-ci
n'ayant pas
de valeur de
retour, mais
notez que les
exceptions
sont la
manière
correcte de
signaler un
problème
dans un
constructeur
(à moins que
la situation
ne soit
irrécupérable
– voir
ci-dessus),
ceux-ci
n'ayant pas
de valeur de
retour, mais
notez aussi
que les
exceptions
ne sont pas
du tout
convenables
dans un
destructeur,
ceci rendant
le
programme
inutilisable;
notez aussi
que les
exceptions
ne sont pas
du tout
convenables
dans un
destructeur,
ceci rendant
le
programme
inutilisable;
quelques considérations de multiprogrammation (il se
peut que celles et ceux ayant suivi INF756 voient des
recoupements dans cette section, mais je ferai un peu de
neuf, promis!) :
survol bref de techniques pour
assurer la mise en place d'outils de
synchronisation portables;
applications de l'idiome pImpl;
applications de l'idiome RAII;
applications de l'idiome Incopiable;
mouvement ou copie;
pointeurs intelligents.
À
propos de Q02, voir ceci

Conception de systèmes en temps réel

http://h-deb.clg.qc.ca/UdeS/STR/index.html

18 S05 12 S05 Au menu : février février question Q03; gestion avancée de la
18
S05
12
S05
Au menu :
février
février
question Q03;
gestion avancée de la mémoire, soit :
comment manipuler de la mémoire
brute;
écrire du code générique et
robuste;
comment spécialiser les
mécanismes d'allocation
dynamique de mémoire;
comment en arriver à une
allocation dynamique
déterministes; etc.
dans notre démarche, nous avons examiné :
la distinction à faire entre
allocation et initialisation de
mémoire, de même que celle à
faire entre finalisation et libération
de mémoire;
Cette semaine, vous serez pris dans les
examens. Nous n'aurons pas d'examen intra
dans ce cours, mais aurons une séance en
classe. Ce sera une séance humaine, qui
tiendra compte des circonstances dans
lesquelles vous êtes plongé(e)s.
le rôle des exceptions dans le
processus de gestion des erreurs;
les services du langage C que sont
malloc() et free();
les services de C++ que sont les
opérateurs new, new[],
delete et delete[];
la spécialisation des services de
C++ :
Au menu :
question Q03;
quelques considérations de multiprogrammation (il se
peut que celles et ceux ayant suivi IFT630 voient des
recoupements dans cette section, mais je ferai un peu de
neuf, promis!) :
de manière
globale, avec
pour exemple
un système
primitif de
détection de
fuites;
survol bref de techniques pour
assurer la mise en place d'outils de
synchronisation portables;
de manière
no-throw;
applications de l'idiome pImpl;
applications de l'idiome RAII;
applications de l'idiome Incopiable;
mouvement ou copie;
pointeurs intelligents;
premiers pas du côté des mécanismes de gestion avancée
de la mémoire.
Dans les notes de cours, vous trouverez de la matière en lien
de manière
positionnelle
(ne
remplacez
pas la
spécialisation
existante
dans ce cas,
je vous en
prie!);
avec cette séance dans STR – Volume 04, pages ≈59
98.
Notez que j'aurai voulu retoucher ce document avant de vous le
livrer, mais le temps me manquera cette session. Cet article sur
la programmation générique appliquée peut aussi contribuer à
votre compréhension de certaines particularités de la matière.
avec
assistants
pour
mémoire
spécialisée;
sous forme
de méthodes
d'instance;
les arénas, qui permettent de gérer
des zones de mémoire choisies;
les allocateurs, qui permettent de
contrôler le comportement des
conteneurs standards pour ce qui
est de la mémoire allouée
dynamiquement.
Dans les notes de cours, vous trouverez de la matière en lien
avec cette séance dans STR – Volume 04, pages ≈59
98.
Notez que j'aurai voulu retoucher ce document avant de vous le
livrer, mais le temps me manquera cette session. Cet article sur
la programmation générique appliquée peut aussi contribuer à
votre compréhension de certaines particularités de la matière.
Vous trouverez aussi dans cet article un exemple plus complet
(et plus complexe) de gestion manuelle de mémoire.
25
S06
19
S06
février
Au menu :
février
Au menu :
question Q04;
gestion avancée de la mémoire, soit :
question Q04;
suite de la gestion avancée de la mémoire :
comment manipuler de la mémoire
brute;
écrire du code générique et
robuste;
comment spécialiser les
mécanismes d'allocation
dynamique de mémoire;
comment en arriver à une
allocation dynamique
déterministes; etc.
dans notre démarche, nous avons examiné :
rédiger un conteneur générique du
calibre de std::vector;
écrire du code générique et
robuste;
sans allocateur;
avec allocateur;
algorithmes standards sur de la mémoire brute et
différences avec algorithmes standards usuels;
opérations modifiant la structure d'un tel conteneur
(insert(), erase()) : subtilités et enjeux;
petite parenthèse sur le mécanisme des templates

Conception de systèmes en temps réel

http://h-deb.clg.qc.ca/UdeS/STR/index.html

la distinction à faire entre allocation et initialisation de mémoire, de même que celle à
la distinction à faire entre
allocation et initialisation de
mémoire, de même que celle à
faire entre finalisation et libération
de mémoire;
le rôle des exceptions dans le
processus de gestion des erreurs;
les services du langage C que sont
malloc() et free();
les services de C++ que sont les
opérateurs new, new[],
delete et delete[];
la spécialisation des services de
C++ :
de manière
globale, avec
pour exemple
un système
primitif de
détection de
fuites;
de manière
no-throw;
de manière
positionnelle
(ne
remplacez
pas la
spécialisation
existante
dans ce cas,
je vous en
prie!);
variadiques.
Dans les notes de cours, vous trouverez de la matière en lien
avec cette séance dans STR – Volume 04, pages ≈59
98.
Notez que j'aurai voulu retoucher ce document avant de vous le
livrer, mais le temps me manquera cette session. Cet article sur
la programmation générique appliquée peut aussi contribuer à
votre compréhension de certaines particularités de la matière.
avec
assistants
pour
mémoire
spécialisée;
sous forme
de méthodes
d'instance;
les arénas, qui permettent de gérer
des zones de mémoire choisies;
les allocateurs, qui permettent de
contrôler le comportement des
conteneurs standards pour ce qui
est de la mémoire allouée
dynamiquement.
Dans les notes de cours, vous trouverez de la matière en lien
avec cette séance dans STR – Volume 04, pages ≈59
98.
Notez que j'aurai voulu retoucher ce document avant de vous le
livrer, mais le temps me manquera cette session. Cet article sur
la programmation générique appliquée peut aussi contribuer à
votre compréhension de certaines particularités de la matière.
Vous trouverez aussi dans cet article un exemple plus complet
(et plus complexe) de gestion manuelle de mémoire.
4
26
S07
Au menu :
mars
février
Relâche au campus principal. Reposez-vous un peu, vous en
avez sûrement besoin!
question Q05;
gestion de l'antémémoire (de la Cache), à partir d'un
document de Scott Meyers;
optimisation;
quelques bases de métaprogrammation;
si le temps le permet : matériel et variables atomiques.
Dans les notes de cours, vous trouverez de la matière en lien
avec cette séance dans STR – Volume 03, essentiellement
dans le document tout entier, mais surtout pp. ≈110
Un document sur les variables atomiques vous sera livré sous
peu (je suis sur le dossier!), mais pour le moment, vous
trouverez des bribes à ce sujet dans STR – Volume 04,
pp. ≈40
11 mars
S07
5
S08
Au menu :
mars
question Q05;
suite de la gestion avancée de la mémoire :
rédiger un conteneur générique du
calibre de std::vector;
écrire du code générique et
robuste;
Cours suspendu : votre chic prof a passé la nuit à l'hôpital,
et ça aurait été; quelque peu plate de le regarder dormir
devant la classe
sans allocateur;
avec allocateur;
algorithmes standards sur de la mémoire brute et
différences avec algorithmes standards usuels;
opérations modifiant la structure d'un tel conteneur

Conception de systèmes en temps réel

http://h-deb.clg.qc.ca/UdeS/STR/index.html

(insert(), erase()) : subtilités et enjeux; petite parenthèse sur le mécanisme des templates variadiques; gestion
(insert(), erase()) : subtilités et enjeux;
petite parenthèse sur le mécanisme des templates
variadiques;
gestion de l'antémémoire (de la Cache), à partir d'un
document de Scott Meyers.
Dans les notes de cours, vous trouverez de la matière en lien
avec cette séance dans STR – Volume 04, pages ≈59
98.
Notez que j'aurai voulu retoucher ce document avant de vous le
livrer, mais le temps me manquera cette session. Cet article sur
la programmation générique appliquée peut aussi contribuer à
votre compréhension de certaines particularités de la matière.
18
S08
12
S09
mars
mars
Au menu : conférence de Mike Hall (Microsoft), événement
qui se tiendra exceptionnellement au local 2630 (Campus de
Longueuil) et au local D3-1058 (salle de vidéoconférence
du Département de physique, Faculté des sciences, Campus
principal) :
The Microsoft Intelligent Systems story –
From Microcontroller to Cloud, and
everything in-between
Au menu : naissance de bébé Ludo. Cours suspendu.
When you hear the name « Microsoft » you
probably think about Windows, Server,
Azure, Visual Studio, but what about
embedded devices, microcontrollers,
hard-real-time embedded operating systems,
intelligent « systems »? In this presentation
we will discuss the Microsoft
embedded/intelligent systems stack, and
have plenty of demos!
Mike Hall is a Principal Software Architect
in the Windows Embedded Business at
Microsoft. Mike has worked on a number
of embedded projects including : hardware
and software definition, « Bare Metal »
software development, porting of operating
systems, hard-real-time systems,
commercial and consumer devices, and
application development for embedded
systems.
25 mars
S09
19
S10
mars
Nous débuterons cette séance à 9:00
plutôt qu'à 9:30, pour compenser un peu
la séance S08 disparue pour de
sympathiques raisons.
Au menu :
remise (tardive, mais ce n'est pas votre faute) du livrable
L01;
question Q06 (le libellé est disponible ici);
entrées/ sorties et STR :
partage de données entre deux
threads par une zone de transit
synchronisée;
partage de données entre deux
threads par un double tampon sans
synchronisation;
modèles architecturaux de STR :
les exécutifs;
les ordonnanceurs (première
approche).
Au menu : naissance de bébé Ludo (en fait, c'était hier,
mais votre chic prof était encore à l'hôpital). Cours
suspendu.
Nous nous dirigeons vers un examen des
exécutifs statiques, reposant sur des tâches
périodiques connues a priori, de même que
de ce que sont les conditions
d'« ordonnançabilité ».
Si vous êtes curieuses ou curieux, un projet
(pas vraiment nettoyé, mais qui peut être
amusant à consulter) est disponible ici.
Étant donné la nature novatrice et
expérimentale de cette chose, je vous invite
à me communiquer tous les bogues que
vous y trouverez.
Dans les notes de cours, vous trouverez de la matière en lien
avec cette séance dans STR – Volume 00, pages ≈35
42

Conception de systèmes en temps réel

http://h-deb.clg.qc.ca/UdeS/STR/index.html

pour les ordonnanceurs TR et dans STR – Volume 04, pages ≈48 58 et ≈158
pour les ordonnanceurs TR et dans STR – Volume 04,
pages ≈48
58
et ≈158
174
pour les entrées/ sorties et
pages ≈134
157
pour les exécutifs.
Rappel : si vous le souhaitez, vous pourrez
remplacer un minitest par une présentation
devant classe de votre projet, que ce soit à
la séance S10 ou à la séance S11.
Commencez à y penser, et contactez votre
chic prof par courriel si vous souhaitez
occuper l'une de ces cases horaires (premier
arrivé, premier servi!)
1
26
S11
Au menu :
avril
mars
question Q06 (le libellé est disponible ici);
entrées/ sorties et STR :
partage de données entre deux
threads par une zone de transit
synchronisée;
partage de données entre deux
threads par un double tampon sans
synchronisation;
modèles architecturaux de STR :
les exécutifs;
les ordonnanceurs (première
approche).
Nous nous dirigeons vers un examen des
exécutifs statiques, reposant sur des tâches
périodiques connues a priori, de même que
de ce que sont les conditions
d'« ordonnançabilité ».
Lundi de Pâques : congé universitaire.
Si vous êtes curieuses ou curieux, un projet
(pas vraiment nettoyé, mais qui peut être
amusant à consulter) est disponible ici.
Étant donné la nature novatrice et
expérimentale de cette chose, je vous invite
à me communiquer tous les bogues que
vous y trouverez.
Dans les notes de cours, vous trouverez de la matière en lien
avec cette séance dans STR – Volume 00, pages ≈35
pour les ordonnanceurs TR et dans STR – Volume 04,
42
pages ≈48
58
et ≈158
174
pour les entrées/ sorties et
pages ≈134
157
pour les exécutifs.
Rappel : si vous le souhaitez, vous pourrez
remplacer un minitest par une présentation
devant classe de votre projet, que ce soit à
la séance S12 ou à la séance S13.
Commencez à y penser, et contactez votre
chic prof par courriel si vous souhaitez
occuper l'une de ces cases horaires (premier
arrivé, premier servi!)
8
avril
S10
2 avril
S12
Nous débuterons cette séance à 9:00
plutôt qu'à 9:30, pour compenser un peu
la séance S08 disparue pour de
sympathiques raisons.
Le cours bizarre du jour où le métro s'est
arrêté
pendant plus d'une heure
avec le
prof dedans
Au menu :
Au menu :
question Q07;
les ordonnanceurs (suite);
considérations de mémoire transactionnelle;
survol des particularités d'un SETR, soit QNX
Neutrino;
la spécification RTSJ pour Java TR;
présentations de projets :
question Q07;
les ordonnanceurs (suite);
considérations de mémoire transactionnelle;
survol des particularités d'un SETR, soit QNX
Neutrino;
la spécification RTSJ pour Java TR.
Gabrielle Denhez et Sonny
Guénette.
Jimmy Fortin.
Vous trouverez quelques textes sur la
mémoire transactionnelle proposée pour
C++ 1y dans la section prévue à cet effet.
Le texte de base est probablement
http://www.open-std.org/jtc1/sc22
Vous trouverez quelques textes sur la
mémoire transactionnelle proposée pour
C++ 1y dans la section prévue à cet effet.
/wg21/docs/papers/2012/n3341.pdf; portez
en particulier attention à l'exemple d'un

Conception de systèmes en temps réel

http://h-deb.clg.qc.ca/UdeS/STR/index.html

Le texte de base est probablement http://www.open-std.org/jtc1/sc22 /wg21/docs/papers/2012/n3341.pdf; portez en
Le texte de base est probablement
http://www.open-std.org/jtc1/sc22
/wg21/docs/papers/2012/n3341.pdf; portez
en particulier attention à l'exemple d'un
swap() transactionnel, qui est
probablement l'exemple canonique d'un
problème de synchronisation sur deux
données et pour lequel d'autres mécanismes
seraient boiteux.
swap() transactionnel, qui est
probablement l'exemple canonique d'un
problème de synchronisation sur deux
données et pour lequel d'autres mécanismes
seraient boiteux.
La spécification la plus récente que j'aie lu
est http://software.intel.com/sites/default
/files/m/4/6/7/e/7/21569-C_2B_2B-
La spécification la plus récente que j'aie lu
est http://software.intel.com/sites/default
transactional-constructs-1.0.pdf
/files/m/4/6/7/e/7/21569-C_2B_2B-
transactional-constructs-1.0.pdf
15 avril
S11
9 avril
S13
Nous débuterons cette séance à 9:00
plutôt qu'à 9:30, pour compenser un peu
la séance S08 disparue pour de
sympathiques raisons.
Au menu :
Au menu :
question Q08;
question Q09;
retour bref sur la mémoire transactionnelle, à laquelle je
n'ai pas rendu justice lors de la séance S10;
présentations de projets :
question Q08;
question Q09;
retour bref sur la mémoire transactionnelle, à laquelle je
n'ai pas rendu justice lors de la séance S12;
présentation du projet Le Muet Parlant;
bref sur les atomiques.
Martin Vézina;
Sébastien Lamanna;
Maxime Forest et Alex Lapointe;
Maxim De Roy;
Robert Radziszewski et Mathieu
Gagnon;
bref sur les atomiques.
Le document sur les atomiques est un
premier jet, sujet à intégration éventuelle
dans le corpus normal des notes de cours.
Toute rétroaction constructive sera la
bienvenue – c'est toujours le cas,
évidemment, mais c'est particulièrement
vrai dans ce cas-ci.
Le document sur les atomiques est un
premier jet, sujet à intégration éventuelle
dans le corpus normal des notes de cours.
Toute rétroaction constructive sera la
bienvenue – c'est toujours le cas,
évidemment, mais c'est particulièrement
vrai dans ce cas-ci.
22
S12
16
S14
avril
Chic examen final plein d'amour, de 9h à 12h au local
avril
Chic examen final plein d'amour
D4-2022

Code des cas sous étude dans les notes de cours

Les sections qui suivent proposent du code ou des exemples proposés en classe, le tout dans le but de vous permettre d'étudier la chose, de critiquer, de commenter, de questionner et d'expérimenter à loisir. Notez que certains des exemples ci-dessous doivent être retouchés à la lueur de l'avènement du standard C++ 11.

En lien avec les cas présentés dans STR – Volume 01

Le code associé aux divers cas sous étude dans STR – Volume 01 est proposé ci-dessous, pour vous épargner la tâche pénible d'en recopier le texte pour en faire l'essai.

Cliquez sur cette cible pour obtenir le code de la chaîne pascal simplifiée, document STR

Cliquez sur cette cible pour obtenir le code de la chaîne pascal simplifiée, document STR – Volume 01

Cliquez sur cette cible pour obtenir le code de la chaîne pascal avec itérateurs, document

Cliquez sur cette cible pour obtenir le code de la chaîne pascal avec itérateurs, document STR – Volume 01

Cliquez sur cette cible pour obtenir le code du test 0.0 , document STR –

Cliquez sur cette cible pour obtenir le code du test 0.0, document STR – Volume 01

Cliquez sur cette cible pour obtenir le code du test 0.0b , document STR –

Cliquez sur cette cible pour obtenir le code du test 0.0b, document STR – Volume 01

Cliquez sur cette cible pour obtenir le code du test 0.1 , document STR –

Cliquez sur cette cible pour obtenir le code du test 0.1, document STR – Volume 01

Cliquez sur cette cible pour obtenir le code du test 1.0 , document STR –

Cliquez sur cette cible pour obtenir le code du test 1.0, document STR – Volume 01

Cliquez sur cette cible pour obtenir le code du test 1.1 , document STR –

Cliquez sur cette cible pour obtenir le code du test 1.1, document STR – Volume 01

Cliquez sur cette cible pour obtenir le code du test 1.2 , document STR –

Cliquez sur cette cible pour obtenir le code du test 1.2, document STR – Volume 01

Cliquez sur cette cible pour obtenir le code du test 1.3 , document STR –

Cliquez sur cette cible pour obtenir le code du test 1.3, document STR – Volume 01

Cliquez sur cette cible pour obtenir le code du test 2.0 , document STR –

Cliquez sur cette cible pour obtenir le code du test 2.0, document STR – Volume 01

Cliquez sur cette cible pour obtenir le code du test 2.1 , document STR –

Cliquez sur cette cible pour obtenir le code du test 2.1, document STR – Volume 01

Conception de systèmes en temps réel

http://h-deb.clg.qc.ca/UdeS/STR/index.html

Cliquez sur cette cible pour obtenir le code du test 2.2 , document STR –

Cliquez sur cette cible pour obtenir le code du test 2.2, document STR – Volume 01

Cliquez sur cette cible pour obtenir le code du test 3.0 , document STR –

Cliquez sur cette cible pour obtenir le code du test 3.0, document STR – Volume 01

En lien avec l'exercice de compression de données

 

Cliquez sur cette cible pour obtenir le projet bmp00, réalisant une compression RLE sur des bitmaps dans un temps raisonnable. Ce projet n'est pas un STR puisqu'il cherche à réaliser rapidement et correctement une tâche mais n'offre aucune garantie de non-dépassement d'un seuil de temps – il n'y a aucun plafond mesurable dans le temps d'exécution de l'algorithme de compression dans ce programme, donc aucune contrainte de temps dont le respect serait déterministe.

L'idée d'offrir d'abord une version opérationnelle d'un algorithme donné, sans se préoccuper de

L'idée d'offrir d'abord une version opérationnelle d'un algorithme donné, sans se préoccuper de contraintes TR, est que cette version est en général plus simple que les versions offrant des garanties TR strictes.

Sur le plan pédagogique, cela donne aussi une excuse à votre professeur pour mettre en place des bases conceptuelles clés du code moderne, pour que toutes et tous comprennent ses exemples, sans aller jusqu'à donner un cours général de techniques de programmation contemporaines. J'essaie de mettre en place des bases conceptuelles et techniques communes sans trop me répéter étant donné la nature bigarrée mais techniquement très solide de la clientèle de ce cours.

 

Cliquez sur cette cible pour obtenir le projet bmp01, réalisant une compression RLE sur des bitmaps dans un temps raisonnable. Ce projet n'est toujours pas un STR et se limite à documenter et à vérifier certaines particularités de la version brute mais opérationnelle ci-dessus. Les commentaires insérés pointent vers des approches à tester pour transformer la version existante en une version TR du même programme.

Cette approche, qui consiste à réfléchir tout haut en documentant le code, est une stratégie

Cette approche, qui consiste à réfléchir tout haut en documentant le code, est une stratégie saine et efficace d'étudier une tâche d'adaptation complexe comme celle de transformer un algorithme de calcul conventionnel en algorithme pouvant respecter des contraintes TR.

 

Cliquez sur cette cible pour obtenir le projet bmp02, réalisant une compression RLE sur des bitmaps dans un temps raisonnable et de manière à ne pas dépasser un certain seuil de tolérance au temps.

Cette version compresse des données RGB brutes selon une approche RLE et peut, contrairement aux deux précédentes, être considérée TR (au sens usuel, pas au sens strict, mais principalement à cause de la plateforme) dans la mesure où le seuil indiquant d'arrêter tiendrait compte du pire cas possible (calculé a priori) pour une séquence de compression RLE donnée. Aller jusque là demanderait toutefois une meilleure connaissance du contexte et obscurcirait quelque peu le propos. Le code du projet est du code de test, montrant qu'il est possible de faire en sorte que l'algorithme de compression s'interrompe « en cours de traitement ».

Quelques suggestions d'exercices pour vous faire la main :

 

ajoutez un traitement arbitraire (que vous pouvez simuler par une attente active basée sur un délai aléatoire) dans la boucle qui invoque la fonction

compressant une séquence selon une approche RLE . Présumez que cette boucle doive itérer n

compressant une séquence selon une approche RLE. Présumez que cette boucle doive itérer

n

fois par seconde, donc que chaque itération de la

boucle prenne au pire

1

seconde, et faites en sorte que la compression n'utilise que le temps restant (s'il y en a). Le temps accordé à l'algorithme de

n

 

compression sera donc un seuil variable plutôt que constant; transformez l'algorithme de compression pour qu'il puisse être interrompu pendant une séquence RLE plutôt qu'entre chaque séquence RLE. Cette version sera globalement plus lente que la version proposée par le professeur mais sera plus près d'une version déterministe, donc moins à risque de déborder des contraintes TR imposées par le contexte. Vous voudrez utiliser un foncteur plutôt qu'une fonction pour réaliser cet exercice; l'algorithme qui transforme une séquence de bytes bruts en vecteur de valeurs RGB est lent. Transformez-le de manière à ce qu'il soit interruptible; plus costaud : transformez la fonction qui compresse un bitmap de manière à ce qu'elle soit interruptible. Ceci sera plus facile à réaliser si l'algorithme transformant une séquence de bytes bruts en séquence RGB est lui-même interruptible. Considérez la fonction consommant un bitmap du flux comme était une opération indivisible (ceci vous permettra de vous concentrer sur l'essentiel); pour que les algorithmes soient plus déterministes, utilisez des tableaux bruts ou des vecteurs préalablement dimensionnés comme conteneurs de destination pour les algorithmes de transformation de séquence de bytes en séquence RGB et de compression RLE. Analysez la solution que vous proposez pour montrer en quoi elle est préférable à la version antérieure et en quoi elle est moins intéressante (évitez les banalités, il y a une réelle réflexion à faire ici).

Cliquez sur cette cible pour la description du format bitmap .  

Cliquez sur cette cible pour la description du format bitmap.

 
Cliquez sur cette cible pour la description de la compression RLE . Pour un peu

Cliquez sur cette cible pour la description de la compression RLE. Pour un peu de pédagogie sur RLE, voir http://hbfs.wordpress.com/2009/04/14/ad-hoc-compression- methods-rle/

En lien avec l'exécutif

methods-rle/ En lien avec l'exécutif Cliquez sur cette cible pour obtenir les sources d'un

Cliquez sur cette cible pour obtenir les sources d'un projet contenant une ébauche fonctionnelle d'exécutif de simulation. Ce projet a été conçu avec Visual Studio 2010, mais les sources sont essentiellement portables (le fichier source non portable est concis, et je pense que vous n'aurez pas de peine à l'identifier).

Un exécutif est un système monoprogrammé qui, avec discipline et avec soin, permet d'atteindre des performances prévisibles et des comportements se rapprochant de ceux qu'on retrouve dans les systèmes multiprogrammés, mais sans payer le prix associés outils de synchronisation. Rien n'est parfait (la mécanique ne peut être répartie sur plusieurs coeurs qu'au prix d'efforts manuels) mais l'idée peut être stimulante et repose sur des techniques qu'on enseigne peu à dans nos institutions aujourd'hui.

En lien avec les séances sous QNX

Notez que l'aide en ligne pour QNX est de très bonne qualité, pour ce système en particulier comme pour les STR en général. La racine pour la version la plus récente de cette aide (à ma connaissance, du moins) est http://www.qnx.com/developers

/docs/6.5.0/index.jsp

Pour les séances avec QNX, vous trouverez le code source des illustrations à travers les liens suivants (ce ne sont que de petits exemples pour vous démarrer, sans plus) :

Pour une image frappante, je vous invite à comparer le schéma des états d'un processus qu'on trouve sur le Wiki à ce sujet avec celui que met de l'avant QNX (document d'origine). C'est divertissant.

Conception de systèmes en temps réel

illustration 00; illustration 01; illustration 02; illustration 03; et illustration 04.

http://h-deb.clg.qc.ca/UdeS/STR/index.html

Le lien le plus important est sans doute celui offrant de l'aide sur la bibliothèque standard de la platreforme, soit http://www.qnx.com/developers/docs/6.5.0/topic /com.qnx.doc.neutrino_lib_ref/about.html. Pour la messagerie synchrone, portez une attention particulière au trio d'opérations MsgSend(), MsgReceive() et MsgReply().

De la documentation touffue vous est offerte sur les SETR et sur QNX dans la section à cet effet : http://www.qnx.com/developers/docs/6.5.0/topic/com.qnx.doc.neutrino /bookset.html

À propos du développement TR pour processeurs à plusieurs coeurs, la section http://www.qnx.com/developers/docs/6.5.0/topic/com.qnx.doc.multicore_en/bookset.html peut vous intéresser.

En lien avec les entrées/ sorties

Les sources du code de Double-Buffering et du code du serveur d'entrées/ sorties non-bloquantes sont mises à votre disposition. Désolé de ne pas avoir fait une meilleure présentation, le temps m'a manqué.

Résultats des minitests

Les résultats des minitests distribués au cours de la session vont comme suit. Notez que la moyenne globale indiquée ici tient compte du fait que je ne retiens que les huit meilleurs résultats sur dix. Notez aussi que les présentations en classe sont susceptibles de mener au remplacement d'un minitest moins bien réussi, ce qui fait que les moyennes en fin de compte sera probablement un peu meilleure que celles indiquées ici.

 

Pour IFT729

   

Pour INF749

 

QXX

Séance

µ

n

QXX

Séance

µ

n

Q00

S02

70, 71%

14

Q00

S02

71, 00%

5

Q01

S03

72, 00%

15

Q01

S03

61, 00%

5

Q02

S04

83, 60%

14

Q02

S04

69, 00%

5

Q03

S05

83, 43%

16

Q03

S05

84%

5

Q04

S06

74, 06%

15

Q04

S06

71%

5

Q05

S07

78%

16

Q05

S07

77%

5

Q06

S09

79%

15

Q06

S11

88%

5

Q07

S10

75%

16

Q07

S12

76%

4

Q08

S11

??%

??

Q08

S13

??%

??

Q09

S11

28%

16

Q09

S13

36%

5

µ

:

74, 01%

µ

:

74, 63%

Résultats des livrables

Les résultats de l'évaluation des livrables remis au cours de la session vont comme suit. Ici,

n représente le nombre de projets livrés.

 

Pour IFT729

   

Pour INF749

 

LXX

Remise à la séance

µ

σ 2

n

LXX

Remise à la séance

µ

σ 2

n

L00

S03

87, 00%

3, 00%

15

L00

S03

92, 71%

1, 47%

3

L01

S08

??, ??%

??, ??%

??

L01

S08

88, 5%

5, 76%

3

L02

S12

??, ??%

??, ??%

??

L02

S12

??, ??%

??, ??%

??

76% 3 L02 S12 ??, ??% ??, ??% ?? L02 S12 ??, ??% ??, ??% ??