Systèmes informatiques : Une perspective pour programmeurs (Édition mondiale)
Une étude approfondie sur la manière dont les systèmes informatiques exécutent des programmes et stockent des informations. Ce cours comble le fossé entre la programmation de haut niveau et le matériel sous-jacent, en couvrant la représentation au niveau machine, l'architecture des processeurs, la hiérarchie mémoire et la programmation concurrente.
Aperçu du cours
📚 Résumé du contenu
Une analyse approfondie de la manière dont les systèmes informatiques exécutent des programmes et stockent des informations. Ce cours comble le fossé entre la programmation de haut niveau et le matériel sous-jacent, en couvrant la représentation au niveau machine, l'architecture du processeur, la hiérarchie de mémoire et la programmation concurrente.
Maîtrisez l'art de la programmation système en comprenant l'interface matériel-logiciel.
Auteur : Randal E. Bryant, David R. O'Hallaron
Remerciements : Soutenu par les étudiants et enseignants du cours 15-213 à l'Université Carnegie Mellon. Les remerciements incluent les contributions de Manasa S. et Mohit Tahiliani.
🎯 Objectifs d'apprentissage
- Identifier comment l'information est représentée à l'aide de bits et de son contexte au sein d'un système.
- Suivre les quatre étapes du système de compilation, depuis le code source jusqu'à l'exécutable.
- Décrire la structure organisationnelle du matériel et la nature hiérarchique des dispositifs de stockage.
- Convertir entre les notations décimale, binaire et hexadécimale, et expliquer l'adressage au niveau machine (ordre des octets).
- Effectuer des opérations au niveau des bits et logiques en C, et prédire les résultats des décalages arithmétiques.
- Analyser les encodages des entiers pour identifier les vulnérabilités potentielles liées aux dépassements de capacité et aux erreurs de conversion.
- Analyser la correspondance entre les constructions C (boucles, branches, procédures) et les instructions assembly x86-64.
- Déconstruire la pile d'exécution pour expliquer la transmission des paramètres, le stockage des variables locales et la gestion des appels récursifs.
- Évaluer les structures de mémoire pour des données hétérogènes et appliquer les règles d'alignement pour calculer les besoins totaux de stockage.
- Définir l'état visible par le programmeur Y86-64 et encoder/décoder des instructions en séquences d'octets.
🔹 Leçon 1 : Une visite guidée des systèmes informatiques
Aperçu : Cette leçon fournit un aperçu complet de la manière dont les systèmes informatiques représentent l'information, traduisent les programmes et exécutent des instructions grâce à des interactions complexes entre matériel et logiciel. Elle explore le parcours d'un programme du code source à l'exécution, le rôle critique de la hiérarchie de mémoire pour combler l'écart entre processeur et mémoire, les abstractions offertes par le système d'exploitation, et les lois mathématiques régissant les performances et la parallélisation du système.
Objectifs d'apprentissage :
- Identifier comment l'information est représentée à l'aide de bits et de son contexte au sein d'un système.
- Suivre les quatre étapes du système de compilation, depuis le code source jusqu'à l'exécutable.
- Décrire la structure organisationnelle du matériel et la nature hiérarchique des dispositifs de stockage.
🔹 Leçon 2 : Représentation et manipulation de l'information
Aperçu : Cette leçon explore la manière dont les ordinateurs numériques représentent et manipulent l'information au niveau des bits. Elle couvre la transition des notations hexadécimales et des tailles de mots au niveau machine vers les encodages complexes des entiers (non signés et complément à deux) et des nombres à virgule flottante (norme IEEE 754). Les étudiants analyseront les propriétés mathématiques de l'arithmétique informatique, y compris les implications de sécurité liées aux dépassements de capacité et les subtilités du arrondi dans les systèmes à précision finie.
Objectifs d'apprentissage :
- Convertir entre les notations décimale, binaire et hexadécimale, et expliquer l'adressage au niveau machine (ordre des octets).
- Effectuer des opérations au niveau des bits et logiques en C, et prédire les résultats des décalages arithmétiques.
- Analyser les encodages des entiers pour identifier les vulnérabilités potentielles liées aux dépassements de capacité et aux erreurs de conversion.
🔹 Leçon 3 : Représentation au niveau machine des programmes
Aperçu : Cette leçon offre une analyse approfondie de la transformation des programmes C de haut niveau en code machine x86-64. Elle couvre l'architecture fondamentale du processeur, y compris les registres et la pile, l'implémentation du flux de contrôle (conditions, boucles et switches), le fonctionnement des appels de procédure et de la récursion, ainsi que la représentation au niveau machine des structures de données complexes telles que les tableaux, les structs et les unions. Enfin, elle traite de la sécurité système via l'analyse des dépassements de tampon et des instructions spécialisées utilisées pour les opérations arithmétiques à virgule flottante.
Objectifs d'apprentissage :
- Analyser la correspondance entre les constructions C (boucles, branches, procédures) et les instructions assembly x86-64.
- Déconstruire la pile d'exécution pour expliquer la transmission des paramètres, le stockage des variables locales et la gestion des appels récursifs.
- Évaluer les structures de mémoire pour des données hétérogènes et appliquer les règles d'alignement pour calculer les besoins totaux de stockage.
🔹 Leçon 4 : Architecture du processeur
Aperçu : Cette leçon explore l'architecture fondamentale d'un processeur, en se concentrant sur la transition d'une implémentation séquentielle (SEQ) vers une implémentation pipelinnée à haute performance (PIPE) utilisant l'Architecture d'Instruction Y86-64 (ISA). Les étudiants analyseront comment les instructions sont encodées, traitées à travers des étapes distinctes (Récupération, Décodage, Exécution, Mémoire, Écriture-Retour), et comment les aléas matériels sont gérés à l'aide de logique de contrôle, de blocages et de transferts pour maximiser le débit.
Objectifs d'apprentissage :
- Définir l'état visible par le programmeur Y86-64 et encoder/décoder des instructions en séquences d'octets.
- Implémenter la logique de contrôle matérielle en utilisant HCL (Language de Contrôle Matériel) pour les circuits combinatoires et séquentiels.
- Suivre le flux d'instructions à travers les six étapes d'un processeur séquentiel et identifier l'impact du horloger.
🔹 Leçon 5 : Optimisation des performances des programmes
Aperçu : Cette leçon explore une approche systématique d'amélioration des performances des programmes en comprenant l'interaction entre le code de haut niveau, les compilateurs optimisants et les architectures de microprocesseurs modernes. Les étudiants apprendront à identifier les "obstacles à l'optimisation" tels que l'aliasing mémoire, à appliquer des transformations de bas niveau comme le déroulement de boucle et la réassociation, et à utiliser des outils de profilage comme GPROF pour cibler efficacement les goulets d'étranglement de performance.
Objectifs d'apprentissage :
- Identifier et atténuer les obstacles à l'optimisation, notamment l'aliasing mémoire et la surcharge des appels de procédure.
- Quantifier les performances d'un programme à l'aide du métrique Cycles Par Élément (CPE).
- Appliquer des transformations comme le déroulement de boucle, les accumulateurs multiples et la réassociation afin d'exploiter le parallélisme au niveau des instructions.
🔹 Leçon 6 : La hiérarchie de mémoire
Aperçu : Cette leçon explore la conception structurelle et fonctionnelle de la hiérarchie de mémoire, en mettant l'accent sur les compromis entre vitesse, coût et capacité de stockage. Elle détaille les technologies alimentant les systèmes modernes – SRAM, DRAM, disques durs et SSD – et explique comment le principe de localité (temporelle et spatiale) permet à de petites mémoires rapides (caches) d'améliorer significativement les performances des programmes. Les étudiants apprendront à analyser la cartographie des caches (directe, associatif par ensemble, totalement associatif) et à appliquer des techniques d'optimisation comme le réordonnancement et le blocage de boucle pour écrire du code amical avec les caches.
Objectifs d'apprentissage :
- Différencier les technologies de mémoire SRAM, DRAM, ROM et Flash, et leurs rôles dans la hiérarchie.
- Calculer la capacité de stockage des disques et le temps total d'accès en fonction de la géométrie et des composants opérationnels.
- Analyser les adresses mémoire pour déterminer les indices d'ensemble cache, les balises et les décalages de bloc selon différentes stratégies de cartographie.
🔹 Leçon 7 : Lien
Aperçu : Cette leçon explore le processus essentiel de lien au niveau système, qui regroupe le code et les données dans un seul fichier pouvant être chargé en mémoire et exécuté. Les étudiants passeront du code source à des binaires exécutables, en comprenant comment les liens résolvent les références de symboles, fusionnent les sections par relocation, et gèrent les bibliothèques statiques et dynamiques. La leçon se termine par des techniques avancées comme l'interposition de bibliothèque et le code indépendant de position (PIC) utilisées dans les bibliothèques partagées modernes.
Objectifs d'apprentissage :
- Suivre la transformation des fichiers sources par le pilote de compilation jusqu'à l'exécutable final.
- Analyser les fichiers objets ELF pour identifier les types de symboles et l'organisation des sections.
- Appliquer les règles de résolution des symboles pour gérer les noms en double et les dépendances au moment du lien.
🔹 Leçon 8 : Flux de contrôle exceptionnel
Aperçu : Cette leçon explore le Flux de Contrôle Exceptionnel (ECF), le mécanisme par lequel un système informatique réagit aux changements d'état du système. Nous examinons comment l'ECF est implémenté à tous les niveaux du système, depuis les exceptions déclenchées par le matériel, le changement de contexte et le contrôle des processus (fork, wait, execve) au niveau du système d'exploitation, jusqu'aux signaux et aux sauts non locaux au niveau logiciel. Les étudiants apprendront à gérer la concurrence, à traiter les erreurs système et à écrire du code robuste et sûr aux signaux.
Objectifs d'apprentissage :
- Distinction entre les quatre catégories d'exceptions matérielles (interruptions, traps, fautes, aborts) et leurs mécanismes de gestion.
- Gérer les cycles de vie des processus à l'aide d'appels système pour la création (
fork), le ramassage (waitpid) et l'exécution (execve). - Mettre en œuvre des gestionnaires de signaux sûrs prenant en compte la concurrence, les signaux non mis en file d'attente et la sécurité face aux signaux asynchrones.
🔹 Leçon 9 : Mémoire virtuelle
Aperçu : Cette leçon explore la Mémoire Virtuelle (MV) comme abstraction fondamentale qui fournit à chaque processus un espace d'adressage grand, continu et privé. Nous couvrons ses trois rôles principaux : outil d'optimisation de mise en cache dans la DRAM, mécanisme de gestion et de protection de la mémoire, et base pour la mémoire mappée. En outre, la leçon examine les mécanismes de traduction d'adresse (TLB), l'allocation dynamique de mémoire (gestion du tas), et les principes de collecte automatique de déchets, avant de conclure sur les pièges critiques liés à la mémoire en programmation C.
Objectifs d'apprentissage :
- Distinction entre adressage physique et virtuel, et description du rôle de l'Unité de Gestion de Mémoire (MMU).
- Effectuer la traduction d'adresse virtuelle vers physique en utilisant les tables de pages et le Translate Lookaside Buffer (TLB).
- Analyser et implémenter des stratégies d'allocation dynamique de mémoire, y compris les listes implicites/explicites et le regroupement.
🔹 Leçon 10 : Entrée/Sortie au niveau système
Aperçu : Cette leçon explore l'interface fondamentale entre le système d'exploitation Linux et les programmes applicatifs pour effectuer les entrées/sorties. Elle couvre les appels système Unix de base, les différents types de fichiers rencontrés dans le système de fichiers Linux, et les structures de données au niveau du noyau utilisées pour les gérer. Elle introduit également le package I/O Robuste (RIO) pour gérer les "comptes courts" et fournit des directives pour choisir entre I/O standard et I/O au niveau système selon les contextes de programmation, comme la programmation réseau.
Objectifs d'apprentissage :
- Implémenter des opérations de fichiers de base à l'aide de l'interface Unix I/O (
open,close,read,write). - Différencier les fichiers réguliers, les répertoires et les liens tout en interrogeant les métadonnées des fichiers avec
stat. - Utiliser le package RIO pour effectuer des opérations I/O robustes, tamponnées et non tamponnées.
🔹 Leçon 11 : Programmation réseau
Aperçu : Cette leçon explore l'architecture fondamentale des applications basées sur le réseau, centrée sur le modèle client-serveur et l'Internet IP global. Les étudiants apprendront à naviguer dans l'interface Socket – la principale API pour la communication réseau au niveau système – et progresseront vers la mise en œuvre d'un serveur web fonctionnel (TINY) capable de fournir des fichiers statiques et du contenu dynamique via l'Interface de Passage Commune (CGI).
Objectifs d'apprentissage :
- Comprendre le cycle demande-réponse du modèle client-serveur et la hiérarchie matériel-logicielle de l'Internet IP global.
- Manipuler et convertir des adresses IP, des noms de domaine et des structures socket à l'aide de fonctions indépendantes du protocole comme
getaddrinfo. - Mettre en œuvre un serveur web itératif robuste et des programmes CGI qui utilisent le contrôle des processus et la redirection d'I/O pour servir du contenu dynamique.
🔹 Leçon 12 : Programmation concurrente
Aperçu : Cette leçon explore les modèles fondamentaux de concurrence : processus, multiplexage d’I/O et threads. Elle propose une analyse approfondie de la synchronisation à l’aide de sémaphores pour résoudre les conditions de course, les schémas architecturaux courants comme producteur-consommateur et serveurs pré-threadés, et les métriques utilisées pour évaluer les performances parallèles. Enfin, elle aborde des questions critiques de fiabilité, notamment la sécurité des threads, la réentrance et la prévention des blocages.
Objectifs d'apprentissage :
- Distinction entre les modèles de concurrence basés sur les processus, l'I/O multiplexé et les threads.
- Appliquer les opérations de sémaphore (P et V) pour assurer l’exclusion mutuelle et résoudre des schémas de synchronisation.
- Calculer les métriques de performance parallèle telles que le gain et l'efficacité selon différentes lois d’échelle.