Modalités d'Évaluation & Sujets Libres
Le projet d'optimisation est construit tout au long des 4 jours. Vous pouvez soit choisir un sujet libre, soit choisir l'une des 10 suggestions de projets (WorldGen, Sudoku, RayTracer, Bot d'Échecs, Jeu de la Vie, Order Book HFT, PixelWar, SIEM Détection, Mini-Vector DB, Spatial Game Server) soumises à la même grille d'évaluation technique.
Au choix : La seule contrainte est de pouvoir appliquer optimisations & benchmarks au fur et à mesure du cours.
10 alternatives (Fintech, Rendu 3D, Moteur d'échecs, IA Vectorielle) avec mêmes critères d'optimisation.
Code source versionné, mesures de temps avant/après, profils d'exécution et rapport d'audit comparatif.
1. Définition & Ressources Critiques
La performance est la capacité d'un système à accomplir une charge de travail donnée en minimisant le temps d'exécution et l'empreinte sur les ressources matérielles.
Cycles CPU consommés, temps d'attente et blocages (I/O, locks, synchronisation).
Allocations dynamiques (Tas/Heap), pression sur le Garbage Collector et localité des caches.
Bande passante, saturation des sockets ouvertes et surcoût de sérialisation.
Dimensionnement serveur, facture Cloud et empreinte carbone de l'infrastructure.
- Fiabilité & SLA : Garantir des temps de réponse prédictibles sous forte charge.
- Scalabilité & Coûts : Absorber 10× plus de trafic sans multiplier les serveurs par 10.
- Sobriété Numérique : Optimiser l'efficacité du code avant d'empiler du matériel.
2. Règle d'Or du Développement
Exactitude d'abord. Valider le besoin métier. Un code ultra-rapide qui produit un résultat faux est inutile.
Architecture lisible. Code testé, propre et modulaire. Ne jamais optimiser sur une base instable ou confuse.
Optimiser après mesure. Cibler uniquement les goulots d'étranglement prouvés, sans complexité prématurée.
- Loi absolue : Ne jamais inverser l'ordre ! L'optimisation prématurée est la première cause de complexité accidentelle.
3. Macro vs Micro-Optimisation
Impact structurel sur l'architecture, la complexité formelle et les flux :
• Algorithmes : Réduire la complexité formelle (O(n²) → O(n log n)).
• Structures de données : Tableaux contigus vs listes chaînées, tables de hachage.
• Architecture système : Asynchronisme, streaming, distribution de charge et caches.
Exploitation fine du matériel ciblée sur les chemins critiques (Hot Paths) :
• Primitives bas niveau : Utiliser des fonctions vectorisées (ex: copy() en Go).
• Chasse aux copies : Élimination des allocations temporaires et passages par référence.
• Aide au compilateur : Inlining automatique et déroulement de boucles.
4. Notation Grand O & Complexité Asymptotique
La notation Grand O (O(...)) quantifie l'évolution du nombre d'opérations et de cycles consommés quand la taille des données N augmente :
5. Compromis Espace-Temps (RAM/CPU)
Le compromis fondamental (Space-Time Trade-off) : choisir entre dépenser des cycles CPU ou occuper des octets en mémoire :
• Mémoïsation & Caching : Mettre en cache les résultats de calculs récurrents.
• Dénormalisation : Dupliquer l'information pour éviter des jointures coûteuses.
• Tables de correspondance : Remplacer des calculs par une lecture indexée directe.
• Compression à la volée : Dépenser du CPU (gzip, zstd) pour soulager la RAM et le réseau.
• Streaming par blocs : Traiter au fil de l'eau avec un buffer constant minimal.
Surconsommer de la RAM engendre des défauts de cache CPU (Cache Misses) et sature le Garbage Collector : l'excès de mémoire finit par dégrader aussi le CPU !
6. Goulots d'Étranglement & Loi d'Amdahl
La vitesse globale d'un système est dictée par son maillon le plus lent. La loi d'Amdahl borne mathématiquement l'accélération maximale atteignable :
Latence réseau, APIs tierces et sockets bloquantes.
Requêtes N+1, tables non indexées et saturation du pool.
Contention sur verrous partagés et files bloquantes.
Parsing lourd, allocations continues et boucles critiques.
- Loi du maillon faible : Si une portion ne pèse que 5% du temps total d'une requête, l'optimiser n'apportera jamais plus de 5% de gain global, même avec une accélération infinie (S → ∞).
- Règle scientifique : Toujours profiler avant d'optimiser pour cibler mathématiquement le goulot prédominant.
7. Le Hot Path : Chemin Critique
Dans tout service backend, le code se divise en deux réalités mécaniques distinctes :
Démarrage, injection de dépendances, chargement de configuration, gestion des erreurs rares.
Principe : Privilégier la maintenabilité. Optimiser ici ne produit aucun gain mesurable.
Boucles d'ingestion, parsing réseau, logique métier exécutée des millions de fois sous charge.
Principe : Zéro allocation sur le tas, zéro copie inutile, inlining maximal.
- Règle fondamentale : On ne devine jamais le Hot Path, on le mesure avec un profileur (Flamegraph,
pprof).
Données & Représentation Binaire
8. Transistors & Signal Binaire
À l'échelle physique élémentaire, un processeur fonctionne par modulation de tensions électriques :
- Pourquoi le binaire ? Deux états de tension distincts éliminent les erreurs de lecture causées par le bruit électrique.
- Un CPU moderne regroupe des milliards de transistors sur quelques millimètres carrés de silicium.
9. Bits, Octets & Puissances
Toutes les structures de données en mémoire sont des combinaisons d'octets :
- 1 Bit : Unité élémentaire d'information (état logique
0ou1). - 1 Octet (Byte) : Groupement ordonné de 8 bits contigus.
- Poids binaires (Puissances de 2) :
- Chaque bit vers la gauche double en valeur : 1 · 2 · 4 · 8 · 16 · 32 · 64 · 128.
- Valeur maximale non signée :
128 + 64 + 32 + 16 + 8 + 4 + 2 + 1= 255 (256 combinaisons de 0 à 255).
10. Simulateur Binaire Interactif
Activez les bits pour observer l'interprétation numérique et textuelle en direct :
11. Encodage Texte : ASCII & UTF-8
Valeurs de 0 à 127 pour l'alphabet latin de base, les chiffres et caractères de contrôle.
Rétrocompatible ASCII sur 1 octet, et dimension dynamique pour l'ensemble des caractères mondiaux :
12. Piège Mémoire des Chaînes
Différence cruciale entre octets physiques en mémoire et caractères logiques (glyphes) :
En mémoire, une chaîne est un tableau d'octets immuable.
len("Go") == 2 octets / 2 caractères.
len("Café") == 5 octets pour seulement 4 caractères ('é' pèse 2 octets en UTF-8).
- Danger d'intégrité : Accéder à
s[3]dans"Café"extrait le premier demi-octet isolé (0xC3) et corrompt la donnée. - Règle backend : Toujours itérer sur les points de code décodés (ex:
runesen Go,.chars()en Rust) plutôt que d'indexer les octets bruts.
TP Fil Rouge (Séance 1) : Mise en Place & Craqueur Naïf (Baseline)
Mission : Initialiser votre projet dans le langage de votre choix, coder l'algorithme combinatoire naïf pour résoudre z3D puis Sh3n, et noter votre temps d'exécution de référence.
1. Initialisation & Choix du Langage
Initialiser un nouveau projet dans le langage de votre choix (Go, Rust, C++, C#, Java, etc.) sur votre poste. Aucun template n'est imposé.
2. Algorithme Naïf (Compteur Base-N)
Coder le générateur combinatoire pour produire chaque mot candidat dans l'alphabet choisi et calculer son condensat SHA-256.
3. Résolution des Cibles (z3D & Sh3n)
Valider que le programme découvre avec succès le mot de passe en clair pour la cible Niveau 1 (z3D) puis Niveau 2 (Sh3n).
4. Chronométrage & Baseline Initiale
Mesurer le temps d'exécution initial (chronométrage simple) et consigner ce temps de référence (Baseline) pour comparer les futurs gains.