# Cheatsheet Architecture des Ordinateurs - Guide Complet pour Développeurs Débutants


[OK] QU'EST-CE QUE L'ARCHITECTURE DES ORDINATEURS ?

L'architecture des ordinateurs est l'étude de la conception et de l'organisation 
des composants matériels et logiciels qui permettent à un ordinateur de fonctionner.
C'est comprendre COMMENT un ordinateur exécute réellement votre code.

# POURQUOI c'est important pour un développeur ?

1. PERFORMANCE - Comprendre le hardware permet d'écrire du code plus rapide
2. DEBUGGING - Comprendre comment la mémoire fonctionne aide à trouver les bugs
3. OPTIMISATION - Savoir comment le CPU exécute les instructions aide à optimiser
4. SYSTÈMES - Comprendre l'architecture est essentiel pour la programmation système
5. SÉCURITÉ - Comprendre le bas niveau aide à identifier les vulnérabilités

# QUAND utiliser ces connaissances ?

[OK] Optimisation de code critique (performance)
[OK] Programmation système (OS, drivers)
[OK] Développement embedded (IoT, robotique)
[OK] Debugging de problèmes complexes
[OK] Compréhension des limitations hardware
[OK] Choix d'architectures pour applications


# === VUE D'ENSEMBLE DE L'ARCHITECTURE ===

Un ordinateur moderne est composé de plusieurs couches :

┌──────────────────────────────────────────────────────────────┐
│                    APPLICATIONS                               │
│         (Python, JavaScript, Java, etc.)                     │
└────────────────────┬─────────────────────────────────────────┘
                     │
┌────────────────────[BLACK_DOWN-POINTING_TRIANGLE]─────────────────────────────────────────┐
│              SYSTÈME D'EXPLOITATION                          │
│         (Windows, Linux, macOS, Android)                     │
│    - Gestion processus                                       │
│    - Gestion mémoire                                         │
│    - Gestion fichiers                                        │
└────────────────────┬─────────────────────────────────────────┘
                     │
┌────────────────────[BLACK_DOWN-POINTING_TRIANGLE]─────────────────────────────────────────┐
│                    HARDWARE                                   │
│                                                              │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐       │
│  │   CPU   │  │ Mémoire │  │ Disque  │  │   I/O   │       │
│  │         │  │  (RAM)  │  │  (SSD)  │  │         │       │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘       │
└──────────────────────────────────────────────────────────────┘


[OK] PARTIE 1 : LE PROCESSEUR (CPU - Central Processing Unit)


# === QU'EST-CE QUE LE CPU ? ===

Le CPU est le "cerveau" de l'ordinateur. C'est lui qui :
- Exécute les instructions de vos programmes
- Effectue les calculs mathématiques
- Prend les décisions logiques (if/else)
- Coordonne les autres composants


# === ANATOMIE D'UN CPU ===

┌──────────────────────────────────────────────────────────────┐
│                         CPU                                   │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              CONTROL UNIT (CU)                         │ │
│  │    Contrôle et coordonne toutes les opérations        │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │       ARITHMETIC LOGIC UNIT (ALU)                      │ │
│  │    Effectue les calculs et opérations logiques        │ │
│  │    (+, -, *, /, AND, OR, NOT, etc.)                   │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │                  REGISTRES                             │ │
│  │    Mémoire ultra-rapide intégrée au CPU               │ │
│  │    - PC (Program Counter)                             │ │
│  │    - IR (Instruction Register)                        │ │
│  │    - Accumulateur                                     │ │
│  │    - Registres généraux (EAX, EBX, ECX, EDX...)      │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │                    CACHE                               │ │
│  │    Mémoire rapide pour données fréquentes            │ │
│  │    L1 Cache (le plus rapide, le plus petit)          │ │
│  │    L2 Cache (moyen)                                   │ │
│  │    L3 Cache (le plus grand, partagé)                 │ │
│  └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘


# === COMMENT LE CPU EXÉCUTE UNE INSTRUCTION ? ===

Le CPU suit un cycle appelé "Fetch-Decode-Execute" (Chercher-Décoder-Exécuter)

# Exemple concret avec du code Python simple :

x = 5 + 3

# Ce code simple nécessite plusieurs instructions CPU :

┌──────────────────────────────────────────────────────────────┐
│ ÉTAPE 1 : FETCH (Chercher)                                   │
├──────────────────────────────────────────────────────────────┤
│ Le CPU cherche la prochaine instruction en mémoire           │
│                                                              │
│ Program Counter (PC) = 0x1000  <- Adresse de l'instruction    │
│ CPU lit l'instruction à l'adresse 0x1000                     │
│ Instruction : LOAD 5 -> Registre A                            │
└──────────────────────────────────────────────────────────────┘
                          v
┌──────────────────────────────────────────────────────────────┐
│ ÉTAPE 2 : DECODE (Décoder)                                   │
├──────────────────────────────────────────────────────────────┤
│ Le Control Unit décode l'instruction                         │
│                                                              │
│ Instruction décodée :                                        │
│ - Opération : LOAD (charger une valeur)                      │
│ - Opérande : 5 (la valeur à charger)                         │
│ - Destination : Registre A                                   │
└──────────────────────────────────────────────────────────────┘
                          v
┌──────────────────────────────────────────────────────────────┐
│ ÉTAPE 3 : EXECUTE (Exécuter)                                 │
├──────────────────────────────────────────────────────────────┤
│ L'ALU exécute l'opération                                    │
│                                                              │
│ Registre A = 5                                               │
└──────────────────────────────────────────────────────────────┘
                          v
┌──────────────────────────────────────────────────────────────┐
│ ÉTAPE 4 : FETCH (instruction suivante)                       │
├──────────────────────────────────────────────────────────────┤
│ PC = 0x1004  <- Adresse suivante                              │
│ Instruction : LOAD 3 -> Registre B                            │
└──────────────────────────────────────────────────────────────┘
                          v
┌──────────────────────────────────────────────────────────────┐
│ ÉTAPE 5 : DECODE                                             │
├──────────────────────────────────────────────────────────────┤
│ Opération : LOAD, Opérande : 3, Destination : Registre B     │
└──────────────────────────────────────────────────────────────┘
                          v
┌──────────────────────────────────────────────────────────────┐
│ ÉTAPE 6 : EXECUTE                                            │
├──────────────────────────────────────────────────────────────┤
│ Registre B = 3                                               │
└──────────────────────────────────────────────────────────────┘
                          v
┌──────────────────────────────────────────────────────────────┐
│ ÉTAPE 7 : FETCH                                              │
├──────────────────────────────────────────────────────────────┤
│ PC = 0x1008                                                  │
│ Instruction : ADD Registre A, Registre B -> Registre C        │
└──────────────────────────────────────────────────────────────┘
                          v
┌──────────────────────────────────────────────────────────────┐
│ ÉTAPE 8 : DECODE                                             │
├──────────────────────────────────────────────────────────────┤
│ Opération : ADD (addition)                                   │
│ Opérandes : Registre A (5) + Registre B (3)                  │
│ Destination : Registre C                                     │
└──────────────────────────────────────────────────────────────┘
                          v
┌──────────────────────────────────────────────────────────────┐
│ ÉTAPE 9 : EXECUTE                                            │
├──────────────────────────────────────────────────────────────┤
│ ALU calcule : 5 + 3 = 8                                      │
│ Registre C = 8                                               │
└──────────────────────────────────────────────────────────────┘
                          v
┌──────────────────────────────────────────────────────────────┐
│ ÉTAPE 10 : FETCH                                             │
├──────────────────────────────────────────────────────────────┤
│ PC = 0x100C                                                  │
│ Instruction : STORE Registre C -> Variable x                  │
└──────────────────────────────────────────────────────────────┘
                          v
┌──────────────────────────────────────────────────────────────┐
│ ÉTAPE 11 : DECODE                                            │
├──────────────────────────────────────────────────────────────┤
│ Opération : STORE (sauvegarder)                              │
│ Source : Registre C (8)                                      │
│ Destination : Adresse mémoire de x                           │
└──────────────────────────────────────────────────────────────┘
                          v
┌──────────────────────────────────────────────────────────────┐
│ ÉTAPE 12 : EXECUTE                                           │
├──────────────────────────────────────────────────────────────┤
│ Écrire 8 dans la mémoire à l'adresse de x                    │
│ Mémoire[adresse_x] = 8                                       │
└──────────────────────────────────────────────────────────────┘

# Résultat final : x = 8


# === LES REGISTRES EN DÉTAIL ===

Les registres sont la mémoire LA PLUS RAPIDE de l'ordinateur.
Ils sont situés directement dans le CPU.

# Types de registres (Architecture x86/x64) :

┌──────────────────────────────────────────────────────────────┐
│                    REGISTRES GÉNÉRAUX                        │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ 64 bits (x64)     32 bits (x86)    Usage principal           │
│ ───────────────────────────────────────────────────────────  │
│ RAX               EAX              Accumulateur (résultats)  │
│ RBX               EBX              Base (adresses)           │
│ RCX               ECX              Compteur (boucles)        │
│ RDX               EDX              Données                   │
│ RSI               ESI              Source Index              │
│ RDI               EDI              Destination Index         │
│ RBP               EBP              Base Pointer (stack)      │
│ RSP               ESP              Stack Pointer             │
│ R8-R15            -                Registres additionnels    │
│                                                              │
└──────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────┐
│                 REGISTRES SPÉCIAUX                           │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ RIP (Instruction Pointer) - Adresse de l'instruction actuelle│
│ RFLAGS - Flags de statut (zero, carry, overflow, etc.)       │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# EXEMPLE : Utilisation des registres en assembleur

# Code Python :
def add_numbers(a, b):
    return a + b

result = add_numbers(5, 3)

# Équivalent en assembleur (simplifié) :
# 
# ; Charger les paramètres dans les registres
# MOV EAX, 5        ; EAX = 5 (paramètre a)
# MOV EBX, 3        ; EBX = 3 (paramètre b)
# 
# ; Effectuer l'addition
# ADD EAX, EBX      ; EAX = EAX + EBX = 8
# 
# ; Le résultat est dans EAX (convention d'appel)
# MOV [result], EAX ; Sauvegarder le résultat en mémoire


# === POURQUOI les registres sont si rapides ? ===

# Hiérarchie de vitesse d'accès :

Registres     ~0.5 ns   (cycles CPU)      │LE PLUS RAPIDE
Cache L1      ~1 ns     (quelques cycles)  │
Cache L2      ~3 ns     (dizaines cycles)  │
Cache L3      ~12 ns    (centaines cycles) │
RAM           ~100 ns   (milliers cycles)  v
SSD           ~100 µs   (millions cycles)  │
HDD           ~10 ms    (milliards cycles) │LE PLUS LENT

# Donc utiliser les registres est ~200x plus rapide que la RAM !


# === LE CACHE DU PROCESSEUR ===

Le cache est une mémoire intermédiaire entre le CPU et la RAM.

# POURQUOI le cache existe ?

Le CPU est BEAUCOUP plus rapide que la RAM.
Sans cache, le CPU passerait son temps à ATTENDRE les données.

# COMMENT fonctionne le cache ?

┌──────────────────────────────────────────────────────────────┐
│                   HIÉRARCHIE DU CACHE                        │
│                                                              │
│  ┌──────────────┐                                            │
│  │     CPU      │                                            │
│  │  (Cores)     │                                            │
│  └──────┬───────┘                                            │
│         │                                                    │
│  ┌──────[BLACK_DOWN-POINTING_TRIANGLE]───────┐                                            │
│  │  L1 Cache    │  32-64 KB par core   ~1 ns                 │
│  │ (le plus     │  Instructions + Données                    │
│  │  rapide)     │                                            │
│  └──────┬───────┘                                            │
│         │                                                    │
│  ┌──────[BLACK_DOWN-POINTING_TRIANGLE]───────┐                                            │
│  │  L2 Cache    │  256-512 KB par core  ~3 ns                │
│  │              │  Données + Instructions                    │
│  └──────┬───────┘                                            │
│         │                                                    │
│  ┌──────[BLACK_DOWN-POINTING_TRIANGLE]───────┐                                            │
│  │  L3 Cache    │  8-32 MB (partagé)   ~12 ns                │
│  │ (le plus     │  Partagé entre cores                       │
│  │  grand)      │                                            │
│  └──────┬───────┘                                            │
│         │                                                    │
│  ┌──────[BLACK_DOWN-POINTING_TRIANGLE]───────┐                                            │
│  │     RAM      │  8-64 GB             ~100 ns               │
│  │              │                                            │
│  └──────────────┘                                            │
└──────────────────────────────────────────────────────────────┘


# === CACHE HIT vs CACHE MISS ===

┌──────────────────────────────────────────────────────────────┐
│ CACHE HIT (succès) - Donnée dans le cache                    │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ CPU demande donnée -> Cache L1 -> TROUVÉE ! -> Renvoyée au CPU  │
│                                                              │
│ Temps : ~1 ns [OK] RAPIDE                                       │
└──────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────┐
│ CACHE MISS (échec) - Donnée pas dans le cache                │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ CPU -> L1 (pas trouvé) -> L2 (pas trouvé) -> L3 (pas trouvé)    │
│     -> RAM (trouvé!) -> Copie dans cache -> Renvoyée au CPU     │
│                                                              │
│ Temps : ~100 ns [X] LENT (100x plus lent)                      │
└──────────────────────────────────────────────────────────────┘


# === EXEMPLE PRATIQUE : Impact du cache sur la performance ===

# Code Python : Accès séquentiel vs aléatoire

import numpy as np
import time

# Créer un grand tableau
size = 10_000_000
arr = np.arange(size)

# TEST 1 : Accès séquentiel (cache-friendly)
start = time.time()
total = 0
for i in range(len(arr)):
    total += arr[i]  # Accès séquentiel
sequential_time = time.time() - start

# TEST 2 : Accès aléatoire (cache-unfriendly)
import random
indices = list(range(len(arr)))
random.shuffle(indices)

start = time.time()
total = 0
for i in indices:
    total += arr[i]  # Accès aléatoire
random_time = time.time() - start

print(f"Séquentiel : {sequential_time:.3f}s")
print(f"Aléatoire  : {random_time:.3f}s")
print(f"Différence : {random_time/sequential_time:.1f}x plus lent")

# Résultat typique :
# Séquentiel : 0.150s
# Aléatoire  : 1.200s
# Différence : 8.0x plus lent
#
# POURQUOI ? 
# - Accès séquentiel : Le cache précharge les données suivantes
# - Accès aléatoire : Chaque accès provoque un cache miss


# === OPTIMISATION : Écrire du code cache-friendly ===

# [X] MAUVAIS : Accès non séquentiel (cache miss fréquents)

# Matrice 1000x1000
matrix = [[0] * 1000 for _ in range(1000)]

# Accès par colonne (mauvais en Python car row-major)
for col in range(1000):
    for row in range(1000):
        value = matrix[row][col]  # Cache miss à chaque ligne

# [OK] BON : Accès séquentiel (cache hit fréquents)

# Accès par ligne (bon en Python)
for row in range(1000):
    for col in range(1000):
        value = matrix[row][col]  # Cache hit la plupart du temps


# === PRINCIPE DE LOCALITÉ ===

Le cache exploite deux principes :

# 1. LOCALITÉ TEMPORELLE
# Si une donnée est utilisée, elle sera probablement réutilisée bientôt

def sum_array(arr):
    total = 0  # 'total' est réutilisé à chaque itération
    for num in arr:
        total += num  # Accès répété à 'total' -> cache L1
    return total

# 2. LOCALITÉ SPATIALE
# Si une donnée est utilisée, les données voisines le seront probablement

arr = [1, 2, 3, 4, 5]  # Stockées consécutivement en mémoire

# Accès à arr[0] charge aussi arr[1], arr[2], etc. dans le cache
for i in range(len(arr)):
    print(arr[i])  # Cache hit après le premier accès


# === CACHE COHERENCY (Multi-core) ===

# PROBLÈME : Plusieurs cores modifient la même donnée

┌──────────────────────────────────────────────────────────────┐
│                   CACHE COHERENCY                            │
│                                                              │
│  Core 1           Core 2                                     │
│  ┌────────┐      ┌────────┐                                  │
│  │ L1: x=5│      │ L1: x=5│  <- Chaque core a sa copie        │
│  └────────┘      └────────┘                                  │
│      │               │                                       │
│      │ x = 10        │ x = 20                                │
│      v               v                                       │
│  ┌────────┐      ┌────────┐                                  │
│  │L1: x=10│      │L1: x=20│  <- Incohérence !                 │
│  └────────┘      └────────┘                                  │
│                                                              │
│  Solution : Protocole MESI (Modified-Exclusive-Shared-       │
│             Invalid) pour synchroniser les caches            │
└──────────────────────────────────────────────────────────────┘


# === INSTRUCTIONS CPU ===

Le CPU comprend un jeu d'instructions (ISA - Instruction Set Architecture)

# Principaux types d'instructions :

┌──────────────────────────────────────────────────────────────┐
│                  TYPES D'INSTRUCTIONS                        │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ 1. TRANSFERT DE DONNÉES                                      │
│    MOV  - Copier données                                     │
│    LOAD - Charger depuis mémoire                             │
│    STORE- Sauvegarder en mémoire                             │
│    PUSH - Empiler sur la stack                               │
│    POP  - Dépiler de la stack                                │
│                                                              │
│ 2. ARITHMÉTIQUES                                             │
│    ADD  - Addition                                           │
│    SUB  - Soustraction                                       │
│    MUL  - Multiplication                                     │
│    DIV  - Division                                           │
│    INC  - Incrémenter                                        │
│    DEC  - Décrémenter                                        │
│                                                              │
│ 3. LOGIQUES                                                  │
│    AND  - ET logique                                         │
│    OR   - OU logique                                         │
│    XOR  - OU exclusif                                        │
│    NOT  - NON logique                                        │
│    SHL  - Décalage à gauche                                  │
│    SHR  - Décalage à droite                                  │
│                                                              │
│ 4. CONTRÔLE DE FLUX                                          │
│    JMP  - Saut inconditionnel                                │
│    JE   - Saut si égal                                       │
│    JNE  - Saut si différent                                  │
│    JG   - Saut si plus grand                                 │
│    CALL - Appel de fonction                                  │
│    RET  - Retour de fonction                                 │
│                                                              │
│ 5. COMPARAISON                                               │
│    CMP  - Comparer deux valeurs                              │
│    TEST - Tester avec AND                                    │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === EXEMPLE : Code Python -> Assembleur ===

# Code Python simple :
def max_value(a, b):
    if a > b:
        return a
    else:
        return b

result = max_value(10, 5)

# Équivalent en assembleur x86 (simplifié) :

# ; Fonction max_value
# max_value:
#     ; Paramètres : a dans EDI, b dans ESI
#     CMP EDI, ESI      ; Comparer a et b
#     JG  return_a      ; Si a > b, sauter à return_a
#     
#     ; Sinon, retourner b
#     MOV EAX, ESI      ; EAX = b (valeur de retour)
#     RET               ; Retourner
# 
# return_a:
#     MOV EAX, EDI      ; EAX = a (valeur de retour)
#     RET               ; Retourner
# 
# ; Appel de la fonction
# MOV EDI, 10           ; Premier paramètre = 10
# MOV ESI, 5            ; Deuxième paramètre = 5
# CALL max_value        ; Appeler la fonction
# MOV [result], EAX     ; Sauvegarder le résultat (10)


# === PIPELINING ===

Le pipelining permet au CPU d'exécuter plusieurs instructions simultanément

# SANS pipelining :

┌──────────────────────────────────────────────────────────────┐
│                    EXÉCUTION SÉQUENTIELLE                    │
│                                                              │
│ Cycle 1:  [Fetch Inst1]                                      │
│ Cycle 2:         [Decode Inst1]                              │
│ Cycle 3:                [Execute Inst1]                      │
│ Cycle 4:                       [Fetch Inst2]                 │
│ Cycle 5:                              [Decode Inst2]         │
│ Cycle 6:                                     [Execute Inst2] │
│                                                              │
│ Total : 6 cycles pour 2 instructions                         │
└──────────────────────────────────────────────────────────────┘

# AVEC pipelining :

┌──────────────────────────────────────────────────────────────┐
│                    EXÉCUTION PIPELINÉE                       │
│                                                              │
│ Cycle 1:  [Fetch Inst1]                                      │
│ Cycle 2:  [Fetch Inst2] [Decode Inst1]                       │
│ Cycle 3:  [Fetch Inst3] [Decode Inst2] [Execute Inst1]       │
│ Cycle 4:  [Fetch Inst4] [Decode Inst3] [Execute Inst2]       │
│                                                              │
│ Total : 4 cycles pour 4 instructions (au lieu de 12)         │
│ Gain : 3x plus rapide !                                      │
└──────────────────────────────────────────────────────────────┘


# === HAZARDS DU PIPELINE ===

# PROBLÈME 1 : Data Hazard (dépendance de données)

# Code :
x = 5
y = x + 3  # Dépend de x

# Assembleur :
# MOV EAX, 5      ; Instruction 1: x = 5
# ADD EBX, EAX, 3 ; Instruction 2: y = x + 3 (DÉPEND de Inst1)

# L'instruction 2 ne peut pas être décodée tant que l'instruction 1
# n'est pas exécutée -> STALL du pipeline


# PROBLÈME 2 : Control Hazard (branchement)

if x > 10:
    y = x * 2
else:
    y = x + 1

# Le CPU ne sait pas quel chemin prendre avant l'évaluation de la condition
# -> BRANCH PREDICTION pour deviner le chemin probable


# === BRANCH PREDICTION ===

Le CPU essaie de PRÉDIRE le résultat d'un branchement

# Exemple :

for i in range(1000000):
    if i % 2 == 0:  # Branchement prévisible (alternance)
        even_count += 1
    else:
        odd_count += 1

# Le CPU apprend le pattern et prédit correctement -> RAPIDE

# ──────────────────────────────────────────────────────────────

import random

for i in range(1000000):
    if random.randint(0, 1) == 0:  # Branchement IMPRÉVISIBLE
        even_count += 1
    else:
        odd_count += 1

# Le CPU ne peut pas prédire -> Mauvaises prédictions -> LENT


# === OPTIMISATION : Éviter les branchements ===

# [X] MAUVAIS : Branchement dans la boucle

def count_positive(arr):
    count = 0
    for num in arr:
        if num > 0:  # Branchement à chaque itération
            count += 1
    return count

# [OK] BON : Sans branchement (branchless)

def count_positive(arr):
    count = 0
    for num in arr:
        count += (num > 0)  # True = 1, False = 0 -> pas de branchement
    return count

# Ou avec NumPy (vectorisé) :
import numpy as np
count = np.sum(arr > 0)  # Très rapide, pas de branchement


[OK] PARTIE 2 : LA MÉMOIRE


# === HIÉRARCHIE MÉMOIRE COMPLÈTE ===

┌──────────────────────────────────────────────────────────────┐
│                    PYRAMIDE DE MÉMOIRE                        │
│                                                              │
│                      [BLACK_UP-POINTING_TRIANGLE] Vitesse                               │
│                      │                                       │
│                 [Registres]        1 cycle   ~1 KB          │
│                    /   \                                     │
│              [Cache L1]            ~4 cycles  ~64 KB        │
│                 /       \                                    │
│           [Cache L2]              ~12 cycles  ~512 KB       │
│              /            \                                  │
│        [Cache L3]                 ~40 cycles  ~16 MB        │
│           /                 \                                │
│      [RAM]                        ~200 cycles ~16 GB        │
│        /                       \                             │
│   [SSD]                           ~100,000 cycles ~1 TB     │
│     /                              \                         │
│ [HDD]                               ~10,000,000 cycles ~4TB │
│                                                              │
│                      [BLACK_DOWN-POINTING_TRIANGLE] Capacité                              │
└──────────────────────────────────────────────────────────────┘


# === LA RAM (Random Access Memory) ===

# POURQUOI "Random Access" ?

# On peut accéder à n'importe quelle adresse en même temps
# Contrairement à une cassette où il faut défiler séquentiellement

┌──────────────────────────────────────────────────────────────┐
│                      STRUCTURE RAM                           │
│                                                              │
│  Adresse      Données                                        │
│  ──────────────────────────────────────────                 │
│  0x00000000   [00001010]  <- Byte 0                          │
│  0x00000001   [11110000]  <- Byte 1                          │
│  0x00000002   [01010101]  <- Byte 2                          │
│  0x00000003   [10101010]  <- Byte 3                          │
│  ...                                                         │
│  0xFFFFFFFF   [00000000]  <- Dernier byte (4 GB)            │
│                                                              │
│  Chaque adresse contient 1 byte (8 bits)                   │
└──────────────────────────────────────────────────────────────┘


# === ADRESSAGE MÉMOIRE ===

# Chaque variable en Python a une adresse en mémoire

x = 42
print(id(x))  # Exemple : 140234567890123 (adresse mémoire)

# En mémoire :
# Adresse      Valeur
# 0x7F8B12340  00000000 00000000 00000000 00101010  (42 en binaire)
#                                          ^^^^^^^^
#                                          42 en décimal


# === TYPES DE DONNÉES ET TAILLE MÉMOIRE ===

import sys

# Python
x = 42              # int
f = 3.14            # float
s = "Hello"         # string
l = [1, 2, 3]       # list

print(f"int:    {sys.getsizeof(x)} bytes")      # 28 bytes (overhead Python)
print(f"float:  {sys.getsizeof(f)} bytes")      # 24 bytes
print(f"string: {sys.getsizeof(s)} bytes")      # 54 bytes (5 chars + overhead)
print(f"list:   {sys.getsizeof(l)} bytes")      # 80 bytes (3 items + overhead)

# En C (sans overhead) :
# int:    4 bytes
# float:  4 bytes
# double: 8 bytes
# char:   1 byte


# === ALIGNMENT MÉMOIRE ===

# Le CPU accède à la mémoire par blocs (généralement 4 ou 8 bytes)

# SANS alignment :
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 0  │ 1  │ 2  │ 3  │ 4  │ 5  │ 6  │ 7  │  Adresses
├────┼────┼────┼────┼────┼────┼────┼────┤
│ A  │ A  │ A  │ A  │ B  │ B  │ B  │ B  │  Données
└────┴────┴────┴────┴────┴────┴────┴────┘
  └─── Bloc 1 ────┘└─── Bloc 2 ────┘

Variable A : adresses 0-3 (aligné)     -> 1 accès mémoire [OK]
Variable B : adresses 4-7 (aligné)     -> 1 accès mémoire [OK]

# AVEC misalignment :
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 0  │ 1  │ 2  │ 3  │ 4  │ 5  │ 6  │ 7  │
├────┼────┼────┼────┼────┼────┼────┼────┤
│ X  │ C  │ C  │ C  │ C  │ D  │ D  │ D  │
└────┴────┴────┴────┴────┴────┴────┴────┘
  └─── Bloc 1 ────┘└─── Bloc 2 ────┘

Variable C : adresses 1-4 (misaligned) -> 2 accès mémoire [X] LENT


# === EXEMPLE PRATIQUE : Padding ===

# En C, les structures sont paddées pour l'alignment

struct Person {
    char  name;     // 1 byte
    int   age;      // 4 bytes
    char  gender;   // 1 byte
};

# Taille attendue : 1 + 4 + 1 = 6 bytes
# Taille réelle : 12 bytes ! Pourquoi ?

┌──────────────────────────────────────────────────────────────┐
│                      PADDING                                 │
│                                                              │
│  Adresse  0   1   2   3   4   5   6   7   8   9  10  11    │
│          ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐│
│          │ N │ P │ P │ P │ A │ A │ A │ A │ G │ P │ P │ P ││
│          └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘│
│           ^   └───────┘   ^───────────┘   ^   └───────┘   │
│          name  padding    age (4 bytes)  gender padding    │
│                                                              │
│  - 'age' doit être aligné sur 4 bytes -> padding de 3 bytes │
│  - Struct doit être multiple de 4 -> padding final de 3     │
└──────────────────────────────────────────────────────────────┘

# OPTIMISATION : Réorganiser les champs

struct PersonOptimized {
    int   age;      // 4 bytes
    char  name;     // 1 byte
    char  gender;   // 1 byte
    // Padding automatique : 2 bytes
};

# Taille : 8 bytes (au lieu de 12) -> 33% d'économie !


# === ENDIANNESS ===

# L'ordre dans lequel les bytes sont stockés en mémoire

# Nombre : 0x12345678 (4 bytes)

# BIG ENDIAN (byte le plus significatif en premier) :
┌────┬────┬────┬────┐
│ 12 │ 34 │ 56 │ 78 │  Adresses : 0x1000, 0x1001, 0x1002, 0x1003
└────┴────┴────┴────┘
Utilisé par : Réseau (Network Byte Order), certains CPU (SPARC, PowerPC)

# LITTLE ENDIAN (byte le moins significatif en premier) :
┌────┬────┬────┬────┐
│ 78 │ 56 │ 34 │ 12 │  Adresses : 0x1000, 0x1001, 0x1002, 0x1003
└────┴────┴────┴────┘
Utilisé par : x86, x64 (Intel, AMD)


# Vérifier l'endianness en Python :

import sys
print(sys.byteorder)  # 'little' sur x86/x64

# Exemple pratique :
import struct

# Pack un int en bytes
num = 0x12345678
bytes_le = struct.pack('<I', num)  # Little endian
bytes_be = struct.pack('>I', num)  # Big endian

print(bytes_le.hex())  # '78563412'
print(bytes_be.hex())  # '12345678'


# === STACK vs HEAP ===

La mémoire est divisée en plusieurs régions :

┌──────────────────────────────────────────────────────────────┐
│                   ORGANISATION MÉMOIRE                       │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              CODE (Text Segment)                        │ │
│  │  Instructions du programme                              │ │
│  │  Read-only                                              │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              DATA                                       │ │
│  │  Variables globales et statiques                        │ │
│  │  Initialisées                                           │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              BSS                                        │ │
│  │  Variables globales non initialisées                    │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              HEAP  v                                    │ │
│  │  Allocation dynamique (malloc, new, list, dict, etc.)  │ │
│  │  Grandit vers le haut                                   │ │
│  │                                                          │ │
│  │  ... espace libre ...                                   │ │
│  │                                                          │ │
│  │              STACK  ^                                   │ │
│  │  Variables locales, paramètres, adresses de retour     │ │
│  │  Grandit vers le bas                                    │ │
│  └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘


# === LA STACK (Pile) ===

# CARACTÉRISTIQUES :
# - LIFO (Last In, First Out)
# - Allocation/désallocation automatique
# - Très rapide
# - Taille limitée (généralement 1-8 MB)

# Exemple en Python :

def function_a():
    x = 10  # Variable locale -> sur la stack
    function_b()

def function_b():
    y = 20  # Variable locale -> sur la stack
    function_c()

def function_c():
    z = 30  # Variable locale -> sur la stack

function_a()

# État de la stack pendant l'exécution :

┌──────────────────────────────────────────────────────────────┐
│                      CALL STACK                              │
│                                                              │
│  function_a() appelée :                                      │
│  ┌─────────────┐                                            │
│  │ x = 10      │  <- Stack frame de function_a               │
│  │ return addr │                                            │
│  └─────────────┘                                            │
│                                                              │
│  function_b() appelée :                                      │
│  ┌─────────────┐                                            │
│  │ y = 20      │  <- Stack frame de function_b               │
│  │ return addr │                                            │
│  ├─────────────┤                                            │
│  │ x = 10      │                                            │
│  │ return addr │                                            │
│  └─────────────┘                                            │
│                                                              │
│  function_c() appelée :                                      │
│  ┌─────────────┐                                            │
│  │ z = 30      │  <- Stack frame de function_c (TOP)         │
│  │ return addr │                                            │
│  ├─────────────┤                                            │
│  │ y = 20      │                                            │
│  │ return addr │                                            │
│  ├─────────────┤                                            │
│  │ x = 10      │                                            │
│  │ return addr │                                            │
│  └─────────────┘                                            │
│                                                              │
│  function_c() retourne :                                     │
│  ┌─────────────┐                                            │
│  │ y = 20      │  <- TOP (z est dépilé)                     │
│  │ return addr │                                            │
│  ├─────────────┤                                            │
│  │ x = 10      │                                            │
│  │ return addr │                                            │
│  └─────────────┘                                            │
└──────────────────────────────────────────────────────────────┘


# === STACK OVERFLOW ===

# Si la stack est pleine (récursion infinie, trop de variables locales)

def infinite_recursion():
    x = [0] * 1000  # Alloue beaucoup sur la stack
    infinite_recursion()  # Appel récursif

# infinite_recursion()  # <- RecursionError: maximum recursion depth exceeded


# === LE HEAP (Tas) ===

# CARACTÉRISTIQUES :
# - Allocation/désallocation manuelle (ou garbage collected)
# - Plus lent que la stack
# - Taille limitée par la RAM
# - Fragmentation possible

# En Python, tout objet complexe va sur le heap :

x = 42          # Petit int -> peut être sur stack ou interné
lst = [1, 2, 3] # List -> TOUJOURS sur le heap
d = {}          # Dict -> sur le heap
s = "Hello"     # String -> sur le heap

# Visualisation :

┌──────────────────────────────────────────────────────────────┐
│                       STACK                                  │
├──────────────────────────────────────────────────────────────┤
│  x        = 42     (valeur directe ou pointeur)             │
│  lst_ptr  = 0x7F... (pointeur vers le heap)                 │
│  d_ptr    = 0x7F... (pointeur vers le heap)                 │
│  s_ptr    = 0x7F... (pointeur vers le heap)                 │
└────────────────────────┬─────────────────────────────────────┘
                         │
                         v
┌──────────────────────────────────────────────────────────────┐
│                       HEAP                                   │
├──────────────────────────────────────────────────────────────┤
│  0x7F1234:  [List object]                                   │
│             - size: 3                                        │
│             - items: [1, 2, 3]                              │
│                                                              │
│  0x7F5678:  [Dict object]                                   │
│             - size: 0                                        │
│             - buckets: []                                    │
│                                                              │
│  0x7F9ABC:  [String object]                                 │
│             - length: 5                                      │
│             - data: "Hello"                                  │
└──────────────────────────────────────────────────────────────┘


# === FRAGMENTATION DU HEAP ===

# PROBLÈME : Allocations/désallocations répétées fragmentent la mémoire

┌──────────────────────────────────────────────────────────────┐
│                    HEAP FRAGMENTÉ                            │
│                                                              │
│  Initialement :                                              │
│  ┌──────────────────────────────────────────────────────┐   │
│  │                    64 KB libre                        │   │
│  └──────────────────────────────────────────────────────┘   │
│                                                              │
│  Après allocations :                                         │
│  ┌───┬───────┬───┬─────┬───┬─────────┬───┬───────────┐   │
│  │ A │ Libre │ B │Libre│ C │  Libre  │ D │   Libre   │   │
│  │10K│  5K   │8K │ 3K  │6K │  12K    │7K │    13K    │   │
│  └───┴───────┴───┴─────┴───┴─────────┴───┴───────────┘   │
│                                                              │
│  Total libre : 5+3+12+13 = 33 KB                            │
│  Mais impossible d'allouer un bloc de 20 KB continu !      │
│  -> FRAGMENTATION                                             │
└──────────────────────────────────────────────────────────────┘

# SOLUTION : Garbage collector compacte la mémoire


# === POINTEURS ===

# Un pointeur est une variable qui contient une ADRESSE mémoire

# En C :
# int x = 42;
# int *ptr = &x;  // ptr contient l'adresse de x
# 
# printf("Valeur: %d\n", x);      // 42
# printf("Adresse: %p\n", &x);    // 0x7ffc1234
# printf("Pointeur: %p\n", ptr);  // 0x7ffc1234
# printf("Valeur via pointeur: %d\n", *ptr);  // 42

# En Python (pointeurs cachés) :

x = 42
y = x  # y pointe vers le MÊME objet que x (pour les int immuables)

print(id(x))  # 140234567890123
print(id(y))  # 140234567890123 (même adresse!)

# Mais pour les objets mutables :

lst1 = [1, 2, 3]
lst2 = lst1  # lst2 pointe vers le MÊME objet

lst1.append(4)
print(lst2)  # [1, 2, 3, 4] <- Modifié aussi !

print(id(lst1))  # 140234567890456
print(id(lst2))  # 140234567890456 (même adresse!)


# === GARBAGE COLLECTION ===

# Python gère automatiquement la mémoire avec un garbage collector

# 1. REFERENCE COUNTING

x = [1, 2, 3]  # Crée une liste, ref count = 1
y = x          # Même liste, ref count = 2
z = x          # ref count = 3

del y          # ref count = 2
del z          # ref count = 1
del x          # ref count = 0 -> Liste détruite

# 2. CYCLE DETECTION

# Problème : Références circulaires

class Node:
    def __init__(self):
        self.next = None

a = Node()
b = Node()
a.next = b  # a -> b
b.next = a  # b -> a (cycle!)

# Même si on fait :
del a
del b

# Les objets ne sont pas détruits (ref count > 0) !
# -> Le garbage collector détecte le cycle et les détruit


# === MEMORY LEAKS ===

# Même avec garbage collection, on peut avoir des fuites mémoire

# Exemple 1 : Variables globales non nettoyées

cache = {}  # Global

def process(data):
    cache[data] = expensive_computation(data)
    # Si 'cache' n'est jamais nettoyé -> MEMORY LEAK

# Solution : Limiter la taille du cache
from functools import lru_cache

@lru_cache(maxsize=1000)  # Cache limité à 1000 entrées
def process(data):
    return expensive_computation(data)


# Exemple 2 : Callbacks/Events non désenregistrés

class EventEmitter:
    def __init__(self):
        self.listeners = []
    
    def on(self, callback):
        self.listeners.append(callback)

emitter = EventEmitter()

def my_callback():
    pass

emitter.on(my_callback)  # my_callback est référencé

# Si on ne retire jamais my_callback -> MEMORY LEAK

# Solution :
def off(self, callback):
    self.listeners.remove(callback)


# === PROFILING MÉMOIRE ===

# Mesurer l'utilisation mémoire en Python

import tracemalloc

# Démarrer le tracking
tracemalloc.start()

# Code à profiler
data = [i for i in range(1000000)]

# Snapshot actuel
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')

print("Top 10 allocations:")
for stat in top_stats[:10]:
    print(stat)

# Arrêter le tracking
tracemalloc.stop()

# Exemple de sortie :
# Top 10 allocations:
# <...>/test.py:6: size=8001 KiB, count=1, average=8001 KiB


# === OPTIMISATION MÉMOIRE ===

# [X] MAUVAIS : Créer des copies inutiles

def process_large_list(lst):
    new_lst = lst.copy()  # Copie inutile !
    for i in range(len(new_lst)):
        new_lst[i] *= 2
    return new_lst

# [OK] BON : Modifier en place

def process_large_list(lst):
    for i in range(len(lst)):
        lst[i] *= 2
    return lst

# [OK] ENCORE MIEUX : Utiliser NumPy (vectorisé)

import numpy as np

def process_large_array(arr):
    return arr * 2  # Pas de boucle, très rapide


# [X] MAUVAIS : Stocker trop de données en mémoire

def read_large_file(filename):
    with open(filename) as f:
        lines = f.readlines()  # Charge TOUT en mémoire
    return lines

# [OK] BON : Utiliser un générateur

def read_large_file(filename):
    with open(filename) as f:
        for line in f:  # Lit ligne par ligne
            yield line.strip()


# === SLOTS EN PYTHON ===

# Optimiser la mémoire des objets Python avec __slots__

# Sans __slots__ :
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(1, 2)
print(sys.getsizeof(p))  # ~56 bytes (avec __dict__)

# Avec __slots__ :
class PointOptimized:
    __slots__ = ['x', 'y']  # Pas de __dict__
    
    def __init__(self, x, y):
        self.x = x
        self.y = y

p = PointOptimized(1, 2)
print(sys.getsizeof(p))  # ~40 bytes (économie de 30%)

# QUAND utiliser __slots__ ?
# - Classes avec beaucoup d'instances
# - Attributs fixes et connus à l'avance
# - Besoin d'optimisation mémoire


[OK] PARTIE 3 : LE STOCKAGE (Disques)


# === TYPES DE STOCKAGE ===

┌──────────────────────────────────────────────────────────────┐
│                    COMPARAISON STOCKAGE                      │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ Type      Vitesse   Durabilité  Coût    Capacité            │
│ ────────────────────────────────────────────────────────────│
│ HDD       Lent      Moyenne     Faible  Très grande (10TB+) │
│           ~100 MB/s             $0.02/GB                     │
│                                                              │
│ SSD       Rapide    Bonne       Moyen   Grande (4TB)        │
│ (SATA)    ~550 MB/s             $0.10/GB                     │
│                                                              │
│ NVMe      Très      Bonne       Élevé   Moyenne (2TB)       │
│ SSD       rapide                $0.15/GB                     │
│           ~3500 MB/s                                         │
│                                                              │
│ RAM       Ultra     Volatile    Très    Petite (64GB)       │
│           rapide    (perte      élevé   $5/GB               │
│           ~50 GB/s  si coupure) │                           │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === COMMENT FONCTIONNE UN HDD ? ===

┌──────────────────────────────────────────────────────────────┐
│                    DISQUE DUR (HDD)                          │
│                                                              │
│        Têtes de lecture                                      │
│           v                                                  │
│      ╔════╧════╗                                            │
│      ║         ║                                            │
│      ║ ┌───────┼───────┐ <- Plateau magnétique              │
│      ║ │ ∙ ∙ ∙ │ ∙ ∙ ∙ │   (spinning à 7200 RPM)          │
│      ║ │ ∙ ∙ ∙ │ ∙ ∙ ∙ │                                   │
│      ║ │ ∙ ∙ ∙ │ ∙ ∙ ∙ │ <- Pistes (tracks)                │
│      ║ │ ∙ ∙ ∙ │ ∙ ∙ ∙ │                                   │
│      ║ └───────┼───────┘                                    │
│      ║         ║                                            │
│      ╚════╤════╝                                            │
│           ^                                                  │
│       Moteur                                                 │
│                                                              │
│  Temps d'accès = Seek time + Rotation delay + Transfer time│
│                  ~5-10ms     ~2-4ms          ~0.1ms         │
│                                                              │
│  Total : ~10-15ms par accès aléatoire                       │
└──────────────────────────────────────────────────────────────┘


# === COMMENT FONCTIONNE UN SSD ? ===

┌──────────────────────────────────────────────────────────────┐
│                  SSD (Solid State Drive)                     │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              Contrôleur SSD                             │ │
│  │  - Gère l'usure des cellules                           │ │
│  │  - Wear leveling                                        │ │
│  │  - Garbage collection                                   │ │
│  │  - Cache DRAM                                           │ │
│  └──────────────┬─────────────────────────────────────────┘ │
│                 │                                            │
│  ┌──────────────[BLACK_DOWN-POINTING_TRIANGLE]──┬────────────┬────────────┬────────────┐│
│  │  Flash NAND 1   │ NAND 2     │ NAND 3     │ NAND 4     ││
│  │  (cellules      │            │            │            ││
│  │   mémoire)      │            │            │            ││
│  └─────────────────┴────────────┴────────────┴────────────┘│
│                                                              │
│  Pas de pièces mobiles -> Très rapide (~0.1ms accès)        │
│  Limité en écritures (cellules s'usent)                    │
└──────────────────────────────────────────────────────────────┘


# === TYPES DE CELLULES SSD ===

┌──────────────────────────────────────────────────────────────┐
│                    TYPES CELLULES NAND                       │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ SLC (Single-Level Cell) - 1 bit par cellule                │
│   [OK] Le plus rapide                                          │
│   [OK] Le plus durable (~100,000 cycles d'écriture)           │
│   [X] Le plus cher                                            │
│   Usage : Enterprise, serveurs                              │
│                                                              │
│ MLC (Multi-Level Cell) - 2 bits par cellule                │
│   [OK] Bon compromis vitesse/prix                             │
│   [OK] Durable (~10,000 cycles)                               │
│   Usage : SSD grand public haut de gamme                    │
│                                                              │
│ TLC (Triple-Level Cell) - 3 bits par cellule               │
│   [OK] Bon marché                                              │
│   [X] Moins rapide                                            │
│   [X] Moins durable (~1,000-3,000 cycles)                    │
│   Usage : SSD grand public standard                         │
│                                                              │
│ QLC (Quad-Level Cell) - 4 bits par cellule                 │
│   [OK] Très bon marché                                         │
│   [OK] Grande capacité                                         │
│   [X] Plus lent                                               │
│   [X] Moins durable (~500-1,000 cycles)                      │
│   Usage : Stockage de masse                                 │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === IMPACT SUR LA PERFORMANCE ===

# Exemple : Lecture séquentielle vs aléatoire

import time

# Test avec fichier
filename = "test_file.bin"

# Créer un fichier de 1 GB
with open(filename, "wb") as f:
    f.write(b'\x00' * (1024 * 1024 * 1024))

# Test 1 : Lecture séquentielle
with open(filename, "rb") as f:
    start = time.time()
    while f.read(4096):  # Lire par blocs de 4 KB
        pass
    sequential_time = time.time() - start

# Test 2 : Lecture aléatoire
import random
with open(filename, "rb") as f:
    start = time.time()
    for _ in range(10000):
        pos = random.randint(0, 1024 * 1024 * 1024 - 4096)
        f.seek(pos)
        f.read(4096)
    random_time = time.time() - start

print(f"Séquentiel : {sequential_time:.2f}s")
print(f"Aléatoire  : {random_time:.2f}s")

# Résultats typiques :
# HDD :
#   Séquentiel : 10s  (~100 MB/s)
#   Aléatoire  : 100s (~10 MB/s) - 10x plus lent !
#
# SSD :
#   Séquentiel : 2s   (~500 MB/s)
#   Aléatoire  : 3s   (~350 MB/s) - seulement 1.5x plus lent


# === SYSTÈMES DE FICHIERS ===

# Le système de fichiers organise les données sur le disque

┌──────────────────────────────────────────────────────────────┐
│                  SYSTÈMES DE FICHIERS                        │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ NTFS (Windows)                                              │
│   - Journalisé (protection contre corruption)               │
│   - Permissions avancées                                     │
│   - Compression, encryption                                  │
│   - Taille fichier max : 16 EB                              │
│                                                              │
│ ext4 (Linux)                                                │
│   - Journalisé                                              │
│   - Très performant                                          │
│   - Taille fichier max : 16 TB                              │
│                                                              │
│ APFS (macOS)                                                │
│   - Optimisé pour SSD                                        │
│   - Snapshots                                               │
│   - Encryption native                                        │
│                                                              │
│ FAT32                                                        │
│   - Compatible partout                                       │
│   - Simple                                                   │
│   - Taille fichier max : 4 GB (limitation!)                 │
│   - Pas de permissions                                       │
│                                                              │
│ exFAT                                                        │
│   - Compatible Windows/Mac/Linux                             │
│   - Pas de limite 4 GB                                       │
│   - Bon pour clés USB/cartes SD                             │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === STRUCTURE D'UN SYSTÈME DE FICHIERS ===

┌──────────────────────────────────────────────────────────────┐
│                    DISQUE PHYSIQUE                           │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  Boot Sector                                           │ │
│  │  - Informations de démarrage                           │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  Superblock / Master File Table                        │ │
│  │  - Métadonnées du système de fichiers                  │ │
│  │  - Taille, nombre de fichiers, etc.                    │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  Inodes / File Entries                                 │ │
│  │  - Métadonnées des fichiers                            │ │
│  │  - Permissions, dates, pointeurs vers données          │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  Data Blocks                                           │ │
│  │  - Contenu réel des fichiers                           │ │
│  │  ▓▓▓▓▓▓▓░░░░░▓▓▓░░░░░░░░▓▓▓▓▓▓░░░░░░░░░░░░░░░        │ │
│  │  (▓ = utilisé, ░ = libre)                             │ │
│  └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘


# === INODE (Unix/Linux) ===

# Un inode contient les métadonnées d'un fichier

┌──────────────────────────────────────────────────────────────┐
│                        INODE                                 │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  Numéro inode : 12345                                        │
│  Type         : fichier régulier                             │
│  Permissions  : rw-r--r-- (644)                             │
│  Propriétaire : user_id = 1000                               │
│  Groupe       : group_id = 1000                              │
│  Taille       : 4096 bytes                                   │
│  Dates        :                                              │
│    - Création    : 2024-01-15 10:30:00                      │
│    - Modification: 2024-01-16 14:20:00                      │
│    - Accès       : 2024-01-17 09:15:00                      │
│  Liens        : 1 (hard links count)                        │
│  Blocs        : 8 (blocs de 512 bytes utilisés)            │
│                                                              │
│  Pointeurs vers blocs de données :                          │
│    Direct[0]  -> Bloc 1000                                   │
│    Direct[1]  -> Bloc 1001                                   │
│    Direct[2]  -> Bloc 1002                                   │
│    ...                                                       │
│    Direct[11] -> Bloc 1011                                   │
│    Indirect   -> Bloc 2000 (pointe vers autres blocs)       │
│    Double indirect -> ...                                     │
│    Triple indirect -> ...                                     │
│                                                              │
└──────────────────────────────────────────────────────────────┘

# Voir les inodes en Linux :
# ls -i filename      # Affiche le numéro d'inode
# stat filename       # Affiche toutes les infos de l'inode


# === FRAGMENTATION DU DISQUE ===

┌──────────────────────────────────────────────────────────────┐
│                  FRAGMENTATION                               │
│                                                              │
│  Fichier continu (bon) :                                     │
│  ┌───┬───┬───┬───┬───┬───┬───┬───┐                         │
│  │ A │ A │ A │ A │ A │ A │ A │ A │                         │
│  └───┴───┴───┴───┴───┴───┴───┴───┘                         │
│  1 seek -> lecture rapide                                     │
│                                                              │
│  Fichier fragmenté (mauvais) :                               │
│  ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐                │
│  │ A │ B │ A │ C │ A │ D │ A │ E │ A │ F │                │
│  └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘                │
│  5 seeks -> lecture LENTE (surtout HDD)                      │
│                                                              │
└──────────────────────────────────────────────────────────────┘

# POURQUOI la fragmentation se produit ?

# 1. Fichier créé
write_file("document.txt", "Hello")  # Blocs 1-2

# 2. Autre fichier créé
write_file("image.png", large_data)  # Blocs 3-100

# 3. Premier fichier agrandi
append_file("document.txt", " World")  # Blocs 101-102 (pas consécutifs!)

# Solution : Défragmentation (réorganise les blocs)


[OK] PARTIE 4 : BUS ET INTERCONNEXIONS


# === QU'EST-CE QU'UN BUS ? ===

Un bus est un ensemble de fils électriques qui permettent aux composants
de communiquer entre eux.

┌──────────────────────────────────────────────────────────────┐
│                      BUS SYSTÈME                             │
│                                                              │
│        CPU <-──────────────-> RAM                             │
│         ^v                    ^v                               │
│         └────────┬───────────┘                               │
│                  │                                            │
│                  v                                            │
│            ┌─────────────┐                                   │
│            │  Northbridge│ (Memory Controller Hub)           │
│            │  / Chipset  │                                   │
│            └──────┬──────┘                                   │
│                   │                                           │
│                   v                                           │
│            ┌─────────────┐                                   │
│            │ Southbridge │ (I/O Controller Hub)              │
│            └──────┬──────┘                                   │
│                   │                                           │
│         ┌─────────┼─────────┬──────────┬──────────┐        │
│         v         v         v          v          v         │
│       GPU       USB      SATA       Audio      Network      │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === TYPES DE BUS ===

┌──────────────────────────────────────────────────────────────┐
│                     TYPES DE BUS                             │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ 1. BUS DE DONNÉES (Data Bus)                                │
│    - Transporte les données entre composants                │
│    - Largeur : 32 bits (x86) ou 64 bits (x64)              │
│    - Bidirectionnel                                          │
│                                                              │
│ 2. BUS D'ADRESSE (Address Bus)                              │
│    - Transporte les adresses mémoire                         │
│    - Unidirectionnel (CPU -> Mémoire)                        │
│    - Largeur détermine l'espace adressable                   │
│      32 bits -> 2^32 = 4 GB max                              │
│      64 bits -> 2^64 = 16 EB max                             │
│                                                              │
│ 3. BUS DE CONTRÔLE (Control Bus)                            │
│    - Signaux de contrôle (read, write, interrupt, etc.)    │
│    - Synchronisation                                         │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === STANDARDS DE BUS ===

┌──────────────────────────────────────────────────────────────┐
│               BUS D'EXTENSION (I/O)                          │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ PCI (Peripheral Component Interconnect)                     │
│   - Ancien standard (années 90)                              │
│   - 32/64 bits, 33/66 MHz                                   │
│   - Débit : ~133-533 MB/s                                   │
│                                                              │
│ PCIe (PCI Express)                                          │
│   - Standard moderne                                         │
│   - Lanes : x1, x4, x8, x16                                 │
│   - PCIe 3.0 x16 : ~16 GB/s                                 │
│   - PCIe 4.0 x16 : ~32 GB/s                                 │
│   - PCIe 5.0 x16 : ~64 GB/s                                 │
│   Usage : GPU, SSD NVMe, cartes réseau                      │
│                                                              │
│ USB (Universal Serial Bus)                                  │
│   - USB 2.0 : 480 Mbps (~60 MB/s)                          │
│   - USB 3.0 : 5 Gbps (~625 MB/s)                           │
│   - USB 3.1 : 10 Gbps (~1.25 GB/s)                         │
│   - USB 3.2 : 20 Gbps (~2.5 GB/s)                          │
│   - USB 4   : 40 Gbps (~5 GB/s)                            │
│   Usage : Périphériques externes                            │
│                                                              │
│ SATA (Serial ATA)                                           │
│   - SATA II  : 3 Gbps (~300 MB/s)                          │
│   - SATA III : 6 Gbps (~600 MB/s)                          │
│   Usage : Disques durs, SSD                                 │
│                                                              │
│ NVMe (Non-Volatile Memory Express)                          │
│   - Utilise PCIe directement                                │
│   - Beaucoup plus rapide que SATA                           │
│   - NVMe PCIe 3.0 x4 : ~3.5 GB/s                           │
│   - NVMe PCIe 4.0 x4 : ~7 GB/s                             │
│   Usage : SSD haute performance                             │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === EXEMPLE : Impact du bus sur la performance ===

# Copier 10 GB de données

# USB 2.0 :  10 GB / 60 MB/s  = 170 secondes (~3 minutes)
# USB 3.0 :  10 GB / 625 MB/s = 16 secondes
# SATA III : 10 GB / 600 MB/s = 17 secondes
# NVMe PCIe 4.0 : 10 GB / 7000 MB/s = 1.4 secondes

# Différence : USB 2.0 est 120x plus lent que NVMe !


[OK] PARTIE 5 : ENTRÉES/SORTIES (I/O)


# === PÉRIPHÉRIQUES D'ENTRÉE/SORTIE ===

┌──────────────────────────────────────────────────────────────┐
│                  PÉRIPHÉRIQUES I/O                           │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ ENTRÉE (Input)                                              │
│   - Clavier                                                  │
│   - Souris                                                   │
│   - Microphone                                               │
│   - Caméra                                                   │
│   - Scanner                                                  │
│   - Capteurs (température, accéléromètre, etc.)            │
│                                                              │
│ SORTIE (Output)                                             │
│   - Écran                                                    │
│   - Imprimante                                               │
│   - Haut-parleurs                                            │
│   - LED                                                      │
│                                                              │
│ ENTRÉE/SORTIE (Stockage)                                    │
│   - Disque dur                                               │
│   - SSD                                                      │
│   - Clé USB                                                  │
│   - Carte SD                                                 │
│                                                              │
│ COMMUNICATION                                                │
│   - Carte réseau (Ethernet, WiFi)                           │
│   - Bluetooth                                                │
│   - Modem                                                    │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === MÉTHODES D'I/O ===

# 1. I/O PROGRAMMÉ (Polling)

┌──────────────────────────────────────────────────────────────┐
│                      POLLING                                 │
│                                                              │
│  CPU vérifie constamment si le périphérique est prêt        │
│                                                              │
│  while True:                                                 │
│      if device.is_ready():  # Vérification constante        │
│          data = device.read()                                │
│          break                                               │
│                                                              │
│  [X] INCONVÉNIENT : CPU gaspille du temps à attendre         │
│  [OK] AVANTAGE : Simple à implémenter                          │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# 2. INTERRUPTIONS

┌──────────────────────────────────────────────────────────────┐
│                     INTERRUPTIONS                            │
│                                                              │
│  Le périphérique INTERROMPT le CPU quand il est prêt        │
│                                                              │
│  1. CPU exécute programme principal                          │
│  2. Périphérique envoie signal d'interruption (IRQ)         │
│  3. CPU sauvegarde son état                                  │
│  4. CPU exécute le gestionnaire d'interruption (ISR)        │
│  5. CPU reprend le programme principal                       │
│                                                              │
│  [OK] AVANTAGE : CPU peut faire autre chose en attendant      │
│  [X] INCONVÉNIENT : Overhead du changement de contexte       │
│                                                              │
└──────────────────────────────────────────────────────────────┘

# Exemple en Python (simulé) :

import signal

def interrupt_handler(signum, frame):
    print("Interruption reçue ! Traitement des données...")
    # Traiter les données du périphérique

# Enregistrer le gestionnaire d'interruption
signal.signal(signal.SIGUSR1, interrupt_handler)

# Programme principal continue normalement
while True:
    # Faire autre chose...
    pass


# 3. DMA (Direct Memory Access)

┌──────────────────────────────────────────────────────────────┐
│                         DMA                                  │
│                                                              │
│  Le périphérique transfère directement vers la RAM          │
│  SANS passer par le CPU                                      │
│                                                              │
│  ┌─────────┐          ┌─────────┐         ┌─────────┐      │
│  │   CPU   │          │   DMA   │         │   RAM   │      │
│  │         │          │Controller│        │         │      │
│  └────┬────┘          └────┬────┘         └────┬────┘      │
│       │                    │                    │           │
│       │ 1. Setup DMA       │                    │           │
│       │───────────────────>│                    │           │
│       │                    │                    │           │
│       │ (CPU fait          │ 2. Transfert       │           │
│       │  autre chose)      │ Direct ───────────>│           │
│       │                    │                    │           │
│       │ 3. Interruption    │                    │           │
│       │<───────────────────│                    │           │
│       │   (transfert fini) │                    │           │
│                                                              │
│  [OK] AVANTAGE : CPU libéré pendant le transfert               │
│  [OK] AVANTAGE : Très rapide pour gros transferts              │
│                                                              │
└──────────────────────────────────────────────────────────────┘

# Exemple : Copie de fichier avec DMA

# SANS DMA :
with open("source.bin", "rb") as src:
    with open("dest.bin", "wb") as dst:
        while True:
            chunk = src.read(4096)  # CPU lit
            if not chunk:
                break
            dst.write(chunk)  # CPU écrit
        # CPU occupé tout le temps !

# AVEC DMA (niveau système) :
# Le contrôleur DMA copie directement du disque vers la RAM
# Le CPU lance juste l'opération et est notifié à la fin


# === DRIVERS (Pilotes) ===

# Un driver est un logiciel qui permet au système d'exploitation
# de communiquer avec un périphérique

┌──────────────────────────────────────────────────────────────┐
│                    ARCHITECTURE DRIVER                       │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │           APPLICATION                                   │ │
│  │  (utilise le périphérique via API standard)            │ │
│  └──────────────────────┬─────────────────────────────────┘ │
│                         │                                    │
│                         v System calls                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │     SYSTÈME D'EXPLOITATION                            │   │
│  │  ┌─────────────────────────────────────────────────┐ │   │
│  │  │  Interface générique (VFS, Block Layer, etc.)   │ │   │
│  │  └───────────────────┬─────────────────────────────┘ │   │
│  │                      │                                 │   │
│  │                      v Driver API                      │   │
│  │  ┌─────────────────────────────────────────────────┐ │   │
│  │  │         DRIVER (pilote spécifique)              │ │   │
│  │  │  - Traduction commandes                          │ │   │
│  │  │  - Gestion interruptions                         │ │   │
│  │  │  - Gestion erreurs                               │ │   │
│  │  └───────────────────┬─────────────────────────────┘ │   │
│  └──────────────────────┼───────────────────────────────┘   │
│                         │                                    │
│                         v Commandes hardware                 │
│  ┌──────────────────────────────────────────────────────┐   │
│  │           PÉRIPHÉRIQUE HARDWARE                       │   │
│  │  (disque, imprimante, carte réseau, etc.)            │   │
│  └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘


# === MEMORY-MAPPED I/O ===

# Les périphériques sont accessibles via des adresses mémoire

┌──────────────────────────────────────────────────────────────┐
│                  MEMORY-MAPPED I/O                           │
│                                                              │
│  ESPACE D'ADRESSAGE :                                        │
│                                                              │
│  0x00000000 ─┬─────────────────────────────────────────     │
│              │  RAM (données programme)                      │
│  0x7FFFFFFF ─┤                                               │
│              │  (réservé)                                    │
│  0x80000000 ─┬─────────────────────────────────────────     │
│              │  PÉRIPHÉRIQUES (Memory-mapped)                │
│              │                                               │
│  0xA0000000  │  <- GPU (frame buffer)                        │
│  0xB0000000  │  <- Carte réseau                              │
│  0xC0000000  │  <- Contrôleur disque                         │
│              │  ...                                          │
│  0xFFFFFFFF ─┴─────────────────────────────────────────     │
│                                                              │
│  Écrire à l'adresse 0xA0000000 -> Modifier l'affichage      │
│  Lire depuis 0xB0000000 -> Recevoir données réseau          │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple (simplifié, en C) :
# 
# // Adresse du contrôleur série
# #define SERIAL_PORT 0x3F8
# 
# // Envoyer un caractère
# void serial_putchar(char c) {
#     *((char*)SERIAL_PORT) = c;  // Écrire à l'adresse I/O
# }
# 
# // Recevoir un caractère
# char serial_getchar() {
#     return *((char*)SERIAL_PORT);  // Lire depuis l'adresse I/O
# }


[OK] PARTIE 6 : PERFORMANCES ET OPTIMISATION


# === MÉTRIQUES DE PERFORMANCE ===

┌──────────────────────────────────────────────────────────────┐
│                  MÉTRIQUES CLÉS                              │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ 1. THROUGHPUT (Débit)                                       │
│    Quantité de travail effectué par unité de temps          │
│    Exemple : 1000 requêtes/seconde, 500 MB/s               │
│                                                              │
│ 2. LATENCY (Latence)                                        │
│    Temps pour compléter une opération                       │
│    Exemple : 5ms par requête, 100ns accès RAM              │
│                                                              │
│ 3. BANDWIDTH (Bande passante)                               │
│    Quantité de données transférées par seconde              │
│    Exemple : 10 Gbps réseau, 64 GB/s RAM                   │
│                                                              │
│ 4. UTILISATION                                              │
│    Pourcentage du temps où la ressource est utilisée        │
│    Exemple : CPU à 80%, RAM à 60%                           │
│                                                              │
│ 5. IPC (Instructions Per Cycle)                            │
│    Nombre d'instructions exécutées par cycle CPU            │
│    Exemple : IPC = 2.5 -> CPU très efficace                 │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === LOI D'AMDAHL ===

# La loi d'Amdahl détermine le gain de performance maximal
# d'une optimisation

# Formule :
# Speedup = 1 / ((1 - P) + P/S)
#
# P = Portion du code optimisée (0 à 1)
# S = Speedup de cette portion

# Exemple :

# Cas 1 : Optimiser 50% du code avec speedup de 10x
P = 0.5
S = 10
speedup = 1 / ((1 - P) + P/S)
print(f"Speedup total : {speedup:.2f}x")  # 1.82x

# Cas 2 : Optimiser 90% du code avec speedup de 10x
P = 0.9
S = 10
speedup = 1 / ((1 - P) + P/S)
print(f"Speedup total : {speedup:.2f}x")  # 5.26x

# Cas 3 : Optimiser 50% du code avec speedup de 100x
P = 0.5
S = 100
speedup = 1 / ((1 - P) + P/S)
print(f"Speedup total : {speedup:.2f}x")  # 1.98x

# LEÇON : Il vaut mieux optimiser une grande portion du code
# qu'optimiser énormément une petite portion


# === PROFILING ===

# Identifier les goulots d'étranglement (bottlenecks)

import cProfile
import pstats

def slow_function():
    total = 0
    for i in range(1000000):
        total += i ** 2
    return total

def fast_function():
    return sum(i ** 2 for i in range(1000000))

# Profiler le code
cProfile.run('slow_function()', 'profile_stats')

# Analyser les résultats
stats = pstats.Stats('profile_stats')
stats.sort_stats('cumulative')
stats.print_stats(10)  # Top 10 fonctions les plus lentes

# Exemple de sortie :
#    ncalls  tottime  percall  cumtime  percall filename:lineno(function)
#         1    0.450    0.450    0.450    0.450 script.py:5(slow_function)
#   1000000    0.350    0.000    0.350    0.000 {built-in method builtins.pow}


# === BENCHMARKING ===

import timeit

# Comparer différentes approches

# Approche 1 : Liste en compréhension
time1 = timeit.timeit(
    '[i**2 for i in range(1000)]',
    number=10000
)

# Approche 2 : map()
time2 = timeit.timeit(
    'list(map(lambda x: x**2, range(1000)))',
    number=10000
)

# Approche 3 : Boucle for
time3 = timeit.timeit(
    '''
result = []
for i in range(1000):
    result.append(i**2)
''',
    number=10000
)

print(f"List comprehension : {time1:.3f}s")  # Le plus rapide
print(f"map()              : {time2:.3f}s")
print(f"Boucle for         : {time3:.3f}s")  # Le plus lent


# === OPTIMISATIONS CPU ===


# === VECTORISATION (SIMD) ===

# SIMD = Single Instruction, Multiple Data
# Une instruction traite plusieurs données en parallèle

# Sans SIMD (scalaire) :
┌──────────────────────────────────────────────────────────────┐
│              OPÉRATION SCALAIRE                              │
│                                                              │
│  Instruction : ADD                                           │
│                                                              │
│  Cycle 1:  A[0] + B[0] = C[0]                               │
│  Cycle 2:  A[1] + B[1] = C[1]                               │
│  Cycle 3:  A[2] + B[2] = C[2]                               │
│  Cycle 4:  A[3] + B[3] = C[3]                               │
│                                                              │
│  Total : 4 cycles                                            │
└──────────────────────────────────────────────────────────────┘

# Avec SIMD (vectorisé) :
┌──────────────────────────────────────────────────────────────┐
│              OPÉRATION SIMD                                  │
│                                                              │
│  Instruction : ADD_VEC (256 bits = 4 x 64 bits)             │
│                                                              │
│  Cycle 1:  [A[0], A[1], A[2], A[3]] + [B[0], B[1], B[2], B[3]]
│          = [C[0], C[1], C[2], C[3]]                         │
│                                                              │
│  Total : 1 cycle (4x plus rapide !)                         │
└──────────────────────────────────────────────────────────────┘


# Exemple pratique en Python avec NumPy :

import numpy as np
import time

# Données
size = 10_000_000
a = list(range(size))
b = list(range(size))

# Approche 1 : Boucle Python (scalaire)
start = time.time()
c = []
for i in range(size):
    c.append(a[i] + b[i])
python_time = time.time() - start

# Approche 2 : NumPy (vectorisé avec SIMD)
a_np = np.array(a)
b_np = np.array(b)

start = time.time()
c_np = a_np + b_np  # Opération vectorisée !
numpy_time = time.time() - start

print(f"Python loop : {python_time:.3f}s")
print(f"NumPy (SIMD): {numpy_time:.3f}s")
print(f"Speedup     : {python_time/numpy_time:.1f}x")

# Résultat typique :
# Python loop : 1.500s
# NumPy (SIMD): 0.015s
# Speedup     : 100x plus rapide !


# === EXTENSIONS SIMD ===

┌──────────────────────────────────────────────────────────────┐
│                  EXTENSIONS SIMD x86                         │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ MMX (1996)                                                   │
│   - 64 bits (8 x 8-bit ou 4 x 16-bit ou 2 x 32-bit)        │
│   - Entiers seulement                                        │
│   - Obsolète                                                 │
│                                                              │
│ SSE (Streaming SIMD Extensions, 1999)                       │
│   - 128 bits (4 x 32-bit floats)                            │
│   - 8 registres XMM (XMM0-XMM7)                             │
│                                                              │
│ SSE2 (2001)                                                 │
│   - Support doubles (2 x 64-bit)                            │
│   - Entiers 128 bits                                         │
│                                                              │
│ AVX (Advanced Vector Extensions, 2011)                      │
│   - 256 bits (8 x 32-bit floats ou 4 x 64-bit doubles)     │
│   - 16 registres YMM (YMM0-YMM15)                           │
│                                                              │
│ AVX2 (2013)                                                 │
│   - Opérations entières 256 bits                            │
│   - Fused Multiply-Add (FMA)                                │
│                                                              │
│ AVX-512 (2015+)                                             │
│   - 512 bits (16 x 32-bit ou 8 x 64-bit)                   │
│   - 32 registres ZMM (ZMM0-ZMM31)                           │
│   - Masking (opérations conditionnelles)                     │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Vérifier les extensions SIMD supportées :

import platform

# Linux
# cat /proc/cpuinfo | grep flags

# Python
def check_simd_support():
    try:
        import subprocess
        result = subprocess.run(
            ['lscpu'],
            capture_output=True,
            text=True
        )
        print(result.stdout)
    except:
        print(f"Platform: {platform.processor()}")

# check_simd_support()


# === PARALLÉLISME vs CONCURRENCE ===

┌──────────────────────────────────────────────────────────────┐
│           PARALLÉLISME vs CONCURRENCE                        │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ CONCURRENCE (1 core)                                        │
│   Plusieurs tâches progressent en alternant (time-sharing)  │
│                                                              │
│   Time ─────────────────────────────────────────────────->  │
│   Task A: ████░░░░████░░░░████░░░░                          │
│   Task B: ░░░░████░░░░████░░░░████                          │
│                                                              │
│   [OK] Donne l'illusion de simultanéité                        │
│   [X] Pas de gain de vitesse réel                             │
│                                                              │
│ PARALLÉLISME (multi-core)                                   │
│   Plusieurs tâches s'exécutent vraiment en même temps       │
│                                                              │
│   Time ─────────────────────────────────────────────────->  │
│   Core 1: ████████████████████████                          │
│   Core 2: ████████████████████████                          │
│   Core 3: ████████████████████████                          │
│   Core 4: ████████████████████████                          │
│                                                              │
│   [OK] Gain de vitesse réel (4 cores = ~4x speedup)           │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === MULTI-THREADING vs MULTI-PROCESSING ===

# En Python :

# 1. MULTI-THREADING (threads)
import threading
import time

def worker(num):
    print(f"Thread {num} started")
    time.sleep(1)
    print(f"Thread {num} finished")

# Créer plusieurs threads
threads = []
for i in range(4):
    t = threading.Thread(target=worker, args=(i,))
    threads.append(t)
    t.start()

# Attendre la fin
for t in threads:
    t.join()

# PROBLÈME : GIL (Global Interpreter Lock) en Python
# Un seul thread Python peut exécuter du code à la fois
# -> Pas de parallélisme réel pour du calcul intensif
# [OK] Utile pour I/O (réseau, fichiers)
# [X] Inutile pour calcul CPU


# 2. MULTI-PROCESSING (processus)
from multiprocessing import Pool
import time

def compute_square(n):
    return n * n

if __name__ == '__main__':
    # Créer un pool de 4 processus
    with Pool(processes=4) as pool:
        numbers = range(1000000)
        
        start = time.time()
        results = pool.map(compute_square, numbers)
        parallel_time = time.time() - start
    
    # Comparaison séquentielle
    start = time.time()
    results_seq = [compute_square(n) for n in numbers]
    sequential_time = time.time() - start
    
    print(f"Séquentiel : {sequential_time:.3f}s")
    print(f"Parallèle  : {parallel_time:.3f}s")
    print(f"Speedup    : {sequential_time/parallel_time:.1f}x")

# AVANTAGE : Vrai parallélisme (pas de GIL)
# INCONVÉNIENT : Overhead de création de processus


# === ARCHITECTURES MULTI-CORE ===

┌──────────────────────────────────────────────────────────────┐
│               CPU QUAD-CORE                                  │
│                                                              │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │  Core 0  │  │  Core 1  │  │  Core 2  │  │  Core 3  │   │
│  │          │  │          │  │          │  │          │   │
│  │ ┌──────┐ │  │ ┌──────┐ │  │ ┌──────┐ │  │ ┌──────┐ │   │
│  │ │ L1 I │ │  │ │ L1 I │ │  │ │ L1 I │ │  │ │ L1 I │ │   │
│  │ │ 32KB │ │  │ │ 32KB │ │  │ │ 32KB │ │  │ │ 32KB │ │   │
│  │ └──────┘ │  │ └──────┘ │  │ └──────┘ │  │ └──────┘ │   │
│  │ ┌──────┐ │  │ ┌──────┐ │  │ ┌──────┐ │  │ ┌──────┐ │   │
│  │ │ L1 D │ │  │ │ L1 D │ │  │ │ L1 D │ │  │ │ L1 D │ │   │
│  │ │ 32KB │ │  │ │ 32KB │ │  │ │ 32KB │ │  │ │ 32KB │ │   │
│  │ └──────┘ │  │ └──────┘ │  │ └──────┘ │  │ └──────┘ │   │
│  │ ┌──────┐ │  │ ┌──────┐ │  │ ┌──────┐ │  │ ┌──────┐ │   │
│  │ │  L2  │ │  │ │  L2  │ │  │ │  L2  │ │  │ │  L2  │ │   │
│  │ │256KB │ │  │ │256KB │ │  │ │256KB │ │  │ │256KB │ │   │
│  │ └──────┘ │  │ └──────┘ │  │ └──────┘ │  │ └──────┘ │   │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘   │
│       └─────────────┼─────────────┼─────────────┘           │
│                     │                                        │
│              ┌──────[BLACK_DOWN-POINTING_TRIANGLE]──────┐                                │
│              │   L3 Cache  │                                │
│              │    8 MB      │ (Partagé entre cores)        │
│              └──────┬──────┘                                │
│                     │                                        │
│              ┌──────[BLACK_DOWN-POINTING_TRIANGLE]──────┐                                │
│              │ Memory Ctrl │                                │
│              └──────┬──────┘                                │
│                     │                                        │
│                     v                                        │
│                   RAM                                        │
└──────────────────────────────────────────────────────────────┘


# === SCALING ===

┌──────────────────────────────────────────────────────────────┐
│                  TYPES DE SCALING                            │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ STRONG SCALING                                               │
│   Problème de taille fixe, augmenter le nombre de cores    │
│                                                              │
│   Speedup idéal :                                            │
│   1 core  : 100s                                             │
│   2 cores : 50s   (2x speedup)                              │
│   4 cores : 25s   (4x speedup)                              │
│   8 cores : 12.5s (8x speedup)                              │
│                                                              │
│   Speedup réel (avec overhead) :                            │
│   1 core  : 100s                                             │
│   2 cores : 55s   (1.8x speedup)                            │
│   4 cores : 30s   (3.3x speedup)                            │
│   8 cores : 18s   (5.5x speedup) <- Diminishing returns     │
│                                                              │
│ WEAK SCALING                                                 │
│   Augmenter problème ET nombre de cores proportionnellement│
│                                                              │
│   1 core  : 100 items -> 10s                                 │
│   2 cores : 200 items -> 10s (idéal)                         │
│   4 cores : 400 items -> 10s (idéal)                         │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === EXEMPLE : Parallélisation efficace ===

import multiprocessing as mp
import numpy as np
import time

def process_chunk(data_chunk):
    """Traitement CPU-intensif"""
    return np.sum(data_chunk ** 2)

def parallel_sum_of_squares(data, num_processes=4):
    """Diviser le travail entre plusieurs processus"""
    # Diviser les données en chunks
    chunk_size = len(data) // num_processes
    chunks = [
        data[i:i + chunk_size]
        for i in range(0, len(data), chunk_size)
    ]
    
    # Traiter en parallèle
    with mp.Pool(processes=num_processes) as pool:
        results = pool.map(process_chunk, chunks)
    
    return sum(results)

# Test
if __name__ == '__main__':
    data = np.random.rand(10_000_000)
    
    # Séquentiel
    start = time.time()
    result_seq = np.sum(data ** 2)
    seq_time = time.time() - start
    
    # Parallèle
    start = time.time()
    result_par = parallel_sum_of_squares(data, num_processes=4)
    par_time = time.time() - start
    
    print(f"Séquentiel : {seq_time:.3f}s")
    print(f"Parallèle  : {par_time:.3f}s")
    print(f"Speedup    : {seq_time/par_time:.1f}x")


# === HYPERTHREADING (SMT) ===

# Hyperthreading = Simultaneous Multithreading
# Un core physique apparaît comme 2 cores logiques

┌──────────────────────────────────────────────────────────────┐
│                    HYPERTHREADING                            │
│                                                              │
│  Core physique :                                             │
│  ┌────────────────────────────────────────────────────────┐ │
│  │                                                         │ │
│  │  Thread 1 : ████░░░░████░░░░████  <- Utilise ALU       │ │
│  │  Thread 2 : ░░░░████░░░░████░░░░  <- Utilise FPU       │ │
│  │                                                         │ │
│  │  Les 2 threads partagent les ressources mais peuvent  │ │
│  │  s'exécuter en parallèle si elles utilisent des       │ │
│  │  unités différentes (ALU, FPU, Load/Store)            │ │
│  │                                                         │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  Gain typique : 1.2-1.3x (pas 2x)                          │
│                                                              │
│  4 cores physiques + HT = 8 cores logiques                  │
│  Performance ≈ 5-6 cores physiques                          │
│                                                              │
└──────────────────────────────────────────────────────────────┘

# Vérifier en Python :
import os
print(f"Cores logiques : {os.cpu_count()}")  # Ex: 8
print(f"Cores physiques: {os.cpu_count() // 2}")  # Ex: 4 (si HT)


[OK] PARTIE 7 : ARCHITECTURE MODERNE


# === ARCHITECTURES CPU ===

┌──────────────────────────────────────────────────────────────┐
│              CISC vs RISC                                    │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ CISC (Complex Instruction Set Computer)                     │
│   Exemple : x86, x86-64 (Intel, AMD)                        │
│                                                              │
│   [OK] Instructions complexes (une instruction = plusieurs ops)│
│   [OK] Code compact (moins d'instructions)                     │
│   [X] Instructions de longueur variable                       │
│   [X] Décodage complexe                                       │
│                                                              │
│   Exemple d'instruction CISC :                               │
│   MOVS - Copie bloc mémoire (fait beaucoup en 1 instruction)│
│                                                              │
│ RISC (Reduced Instruction Set Computer)                     │
│   Exemple : ARM, RISC-V, MIPS                               │
│                                                              │
│   [OK] Instructions simples et uniformes                       │
│   [OK] Décodage rapide                                         │
│   [OK] Pipeline efficace                                       │
│   [X] Plus d'instructions nécessaires                         │
│                                                              │
│   Exemple d'instruction RISC :                               │
│   LOAD, ADD, STORE (3 instructions pour une opération)     │
│                                                              │
│ TENDANCE MODERNE : Les CPU CISC (x86) utilisent            │
│ micro-ops RISC en interne !                                 │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === ARM vs x86 ===

┌──────────────────────────────────────────────────────────────┐
│                    ARM vs x86                                │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ ARM (Advanced RISC Machine)                                 │
│   [OK] Faible consommation énergétique                         │
│   [OK] Génère moins de chaleur                                 │
│   [OK] Prix moins élevé                                        │
│   [OK] Excellent pour mobile                                   │
│   [X] Moins de performance brute (mais en progression)        │
│                                                              │
│   Utilisé dans :                                            │
│   - Smartphones (iPhone, Android)                           │
│   - Tablettes                                                │
│   - Raspberry Pi                                            │
│   - Apple Silicon (M1, M2, M3)                              │
│   - Serveurs AWS Graviton                                   │
│                                                              │
│ x86 / x86-64 (Intel, AMD)                                   │
│   [OK] Performance maximale                                    │
│   [OK] Écosystème logiciel mature                             │
│   [OK] Compatibilité backward                                  │
│   [X] Consommation élevée                                     │
│   [X] Chaleur importante                                      │
│                                                              │
│   Utilisé dans :                                            │
│   - PC Desktop                                               │
│   - Laptops                                                  │
│   - Serveurs datacenter                                      │
│   - Workstations                                            │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === ARCHITECTURE HÉTÉROGÈNE ===

# CPU + GPU + Accélérateurs spécialisés

┌──────────────────────────────────────────────────────────────┐
│            ARCHITECTURE HÉTÉROGÈNE                           │
│                                                              │
│  ┌─────────────────────────────────────────────────────┐    │
│  │                   CPU                                │    │
│  │  - Tâches générales                                 │    │
│  │  - Logique complexe                                  │    │
│  │  - Contrôle                                          │    │
│  └──────────────────┬──────────────────────────────────┘    │
│                     │                                        │
│         ┌───────────┼───────────┬───────────┐              │
│         │           │           │           │               │
│         v           v           v           v               │
│  ┌──────────┐ ┌──────────┐ ┌─────────┐ ┌─────────┐        │
│  │   GPU    │ │   NPU    │ │   DSP   │ │   FPGA  │        │
│  │          │ │ (Neural  │ │ (Signal │ │ (Custom)│        │
│  │ Graphisme│ │ Process.)│ │ Process)│ │         │        │
│  │ Calcul // │ │ IA/ML    │ │Audio/Vid│ │ Logic   │        │
│  └──────────┘ └──────────┘ └─────────┘ └─────────┘        │
│                                                              │
│  Chaque composant est optimisé pour un type de tâche        │
└──────────────────────────────────────────────────────────────┘


# === GPU (Graphics Processing Unit) ===

# Le GPU est conçu pour le parallélisme massif

┌──────────────────────────────────────────────────────────────┐
│                   CPU vs GPU                                 │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ CPU (4-16 cores puissants)                                  │
│  ┌────┐ ┌────┐ ┌────┐ ┌────┐                              │
│  │ C1 │ │ C2 │ │ C3 │ │ C4 │  Chaque core très puissant   │
│  └────┘ └────┘ └────┘ └────┘                              │
│                                                              │
│  Bon pour : Logique complexe, branches, latence faible     │
│                                                              │
│ GPU (1000s de cores simples)                                │
│  ┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐        │
│  └─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘        │
│  ┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐        │
│  └─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘        │
│  ... (des milliers)                                          │
│                                                              │
│  Bon pour : Calculs massivement parallèles, matrices,      │
│             graphisme, machine learning                      │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple : Calcul GPU avec CUDA (Python)

# Sans GPU (NumPy CPU)
import numpy as np
import time

size = 10000
A = np.random.rand(size, size)
B = np.random.rand(size, size)

start = time.time()
C = np.dot(A, B)  # Multiplication matricielle
cpu_time = time.time() - start

print(f"CPU : {cpu_time:.3f}s")

# Avec GPU (CuPy - CUDA pour Python)
try:
    import cupy as cp
    
    A_gpu = cp.array(A)  # Transférer vers GPU
    B_gpu = cp.array(B)
    
    start = time.time()
    C_gpu = cp.dot(A_gpu, B_gpu)  # Calcul sur GPU
    cp.cuda.Stream.null.synchronize()  # Attendre fin
    gpu_time = time.time() - start
    
    print(f"GPU : {gpu_time:.3f}s")
    print(f"Speedup : {cpu_time/gpu_time:.1f}x")
    
    # Résultat typique sur NVIDIA RTX 3080 :
    # CPU : 15.234s
    # GPU : 0.156s
    # Speedup : 97.7x !
except:
    print("CuPy non installé (nécessite CUDA)")


# === MÉMOIRE GPU ===

┌──────────────────────────────────────────────────────────────┐
│                 HIÉRARCHIE MÉMOIRE GPU                       │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │            Registres (par thread)                       │ │
│  │            Très rapides, limités                        │ │
│  └────────────────────────────────────────────────────────┘ │
│                            v                                 │
│  ┌────────────────────────────────────────────────────────┐ │
│  │         Shared Memory (par bloc)                        │ │
│  │         Partagée entre threads d'un bloc               │ │
│  │         Très rapide, ~48 KB                            │ │
│  └────────────────────────────────────────────────────────┘ │
│                            v                                 │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              L1 Cache                                   │ │
│  │              Automatique                                │ │
│  └────────────────────────────────────────────────────────┘ │
│                            v                                 │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              L2 Cache                                   │ │
│  │              Partagé, plusieurs MB                      │ │
│  └────────────────────────────────────────────────────────┘ │
│                            v                                 │
│  ┌────────────────────────────────────────────────────────┐ │
│  │           Global Memory (VRAM)                          │ │
│  │           Accessible partout, 8-24 GB                   │ │
│  │           Latence élevée                                │ │
│  └────────────────────────────────────────────────────────┘ │
│                            v                                 │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              RAM Système                                │ │
│  │              Via PCIe (très lent)                       │ │
│  └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘


[OK] PARTIE 8 : VIRTUALISATION


# === QU'EST-CE QUE LA VIRTUALISATION ? ===

# Créer des ordinateurs "virtuels" sur un ordinateur physique

┌──────────────────────────────────────────────────────────────┐
│              MACHINE PHYSIQUE                                │
│  ┌────────────────────────────────────────────────────────┐ │
│  │                 Hardware                                │ │
│  │  (CPU, RAM, Disque, Réseau)                            │ │
│  └──────────────────┬─────────────────────────────────────┘ │
│                     │                                        │
│  ┌──────────────────[BLACK_DOWN-POINTING_TRIANGLE]─────────────────────────────────────┐ │
│  │              Hyperviseur                                │ │
│  │  (VMware, VirtualBox, KVM, Hyper-V)                    │ │
│  └──────┬───────────┬───────────┬──────────────────────────┘ │
│         │           │           │                            │
│  ┌──────[BLACK_DOWN-POINTING_TRIANGLE]─────┐ ┌──[BLACK_DOWN-POINTING_TRIANGLE]─────┐ ┌──[BLACK_DOWN-POINTING_TRIANGLE]─────┐                      │
│  │   VM 1     │ │  VM 2  │ │  VM 3  │                      │
│  │            │ │        │ │        │                      │
│  │ ┌────────┐ │ │┌──────┐│ │┌──────┐│                      │
│  │ │ Linux  │ │ ││Windows││ ││ macOS││                      │
│  │ └────────┘ │ │└──────┘│ │└──────┘│                      │
│  │ ┌────────┐ │ │┌──────┐│ │┌──────┐│                      │
│  │ │  Apps  │ │ ││ Apps ││ ││ Apps ││                      │
│  │ └────────┘ │ │└──────┘│ │└──────┘│                      │
│  └────────────┘ └────────┘ └────────┘                      │
│                                                              │
│  Chaque VM a son propre OS et applications                  │
└──────────────────────────────────────────────────────────────┘


# === TYPES D'HYPERVISEURS ===

┌──────────────────────────────────────────────────────────────┐
│                   HYPERVISEURS                               │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ TYPE 1 (Bare Metal) - Directement sur hardware             │
│                                                              │
│  ┌────────────┐ ┌────────────┐ ┌────────────┐              │
│  │    VM 1    │ │    VM 2    │ │    VM 3    │              │
│  └──────┬─────┘ └──────┬─────┘ └──────┬─────┘              │
│         └──────────────┼────────────────┘                    │
│  ┌─────────────────────[BLACK_DOWN-POINTING_TRIANGLE]────────────────────┐               │
│  │         Hyperviseur (VMware ESXi,        │               │
│  │         Xen, Hyper-V, KVM)               │               │
│  └─────────────────────┬────────────────────┘               │
│  ┌─────────────────────[BLACK_DOWN-POINTING_TRIANGLE]────────────────────┐               │
│  │            Hardware                       │               │
│  └───────────────────────────────────────────┘               │
│                                                              │
│  [OK] Meilleures performances                                  │
│  [OK] Utilisé dans datacenters                                 │
│                                                              │
│ TYPE 2 (Hosted) - Sur un OS existant                       │
│                                                              │
│  ┌────────────┐ ┌────────────┐                              │
│  │    VM 1    │ │    VM 2    │                              │
│  └──────┬─────┘ └──────┬─────┘                              │
│         └──────────────┼────────────────┐                    │
│  ┌─────────────────────[BLACK_DOWN-POINTING_TRIANGLE]───────────────┐│                   │
│  │  Hyperviseur (VirtualBox, VMware    ││                   │
│  │  Workstation, Parallels)            ││                   │
│  └─────────────────────┬───────────────┘│                   │
│  ┌─────────────────────[BLACK_DOWN-POINTING_TRIANGLE]────────────────[BLACK_DOWN-POINTING_TRIANGLE]┐                  │
│  │    OS Hôte (Windows, Linux, macOS)    │                  │
│  └─────────────────────┬───────────────────┘                │
│  ┌─────────────────────[BLACK_DOWN-POINTING_TRIANGLE]────────────────┐                   │
│  │            Hardware                   │                   │
│  └───────────────────────────────────────┘                   │
│                                                              │
│  [OK] Plus facile à utiliser                                   │
│  [X] Moins performant                                         │
│  Usage : Développement, tests                               │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === CONTENEURS vs VMs ===

┌──────────────────────────────────────────────────────────────┐
│               MACHINES VIRTUELLES                            │
│  ┌────────┐ ┌────────┐ ┌────────┐                          │
│  │  App A │ │  App B │ │  App C │                          │
│  ├────────┤ ├────────┤ ├────────┤                          │
│  │ Libs   │ │ Libs   │ │ Libs   │                          │
│  ├────────┤ ├────────┤ ├────────┤                          │
│  │  OS    │ │  OS    │ │  OS    │  <- OS complet dans chaque│
│  │(1-2GB) │ │(1-2GB) │ │(1-2GB) │    VM (lourd)           │
│  └───┬────┘ └───┬────┘ └───┬────┘                          │
│      └──────────┼───────────┘                                │
│  ┌──────────────[BLACK_DOWN-POINTING_TRIANGLE]──────────────┐                            │
│  │       Hyperviseur            │                            │
│  └──────────────┬───────────────┘                            │
│  ┌──────────────[BLACK_DOWN-POINTING_TRIANGLE]───────────────┐                            │
│  │       OS Hôte / Hardware     │                            │
│  └──────────────────────────────┘                            │
│                                                              │
│               CONTENEURS (Docker)                            │
│  ┌────────┐ ┌────────┐ ┌────────┐                          │
│  │  App A │ │  App B │ │  App C │                          │
│  ├────────┤ ├────────┤ ├────────┤                          │
│  │ Libs   │ │ Libs   │ │ Libs   │  <- Seulement les libs    │
│  └───┬────┘ └───┬────┘ └───┬────┘    nécessaires (léger)  │
│      └──────────┼───────────┘                                │
│  ┌──────────────[BLACK_DOWN-POINTING_TRIANGLE]──────────────┐                            │
│  │    Docker Engine (Runtime)   │                            │
│  └──────────────┬───────────────┘                            │
│  ┌──────────────[BLACK_DOWN-POINTING_TRIANGLE]───────────────┐                            │
│  │       OS Hôte (Linux)        │  <- Un seul OS partagé     │
│  └──────────────┬───────────────┘                            │
│  ┌──────────────[BLACK_DOWN-POINTING_TRIANGLE]───────────────┐                            │
│  │          Hardware             │                            │
│  └──────────────────────────────┘                            │
│                                                              │
│  Conteneurs : Plus légers, démarrent en secondes            │
│  VMs : Isolation complète, démarrent en minutes             │
└──────────────────────────────────────────────────────────────┘


[OK] PARTIE 9 : SÉCURITÉ MATÉRIELLE


# === NIVEAUX DE PRIVILÈGE (RINGS) ===

┌──────────────────────────────────────────────────────────────┐
│                  PROTECTION RINGS x86                        │
│                                                              │
│                     ┌──────────┐                            │
│                     │  Ring 3  │  <- Applications utilisateur│
│                     │   (User  │    (navigateur, jeux,     │
│                     │    Mode) │     Python, etc.)         │
│                 ┌───┴──────────┴───┐                        │
│                 │     Ring 2        │  <- (Rarement utilisé) │
│             ┌───┴──────────────────┴───┐                    │
│             │        Ring 1             │  <- (Drivers)      │
│         ┌───┴──────────────────────────┴───┐                │
│         │         Ring 0                    │  <- Kernel OS  │
│         │    (Kernel Mode / Supervisor)    │    Accès total│
│         └───────────────────────────────────┘    hardware   │
│                                                              │
│  Ring 0 : Privilèges maximaux (accès direct hardware)      │
│  Ring 3 : Privilèges limités (protégé)                     │
│                                                              │
│  Passage Ring 3 -> Ring 0 : System Call (syscall)           │
└──────────────────────────────────────────────────────────────┘


# Exemple en Python :

# Code utilisateur (Ring 3)
with open("file.txt", "r") as f:
    data = f.read()  # Appel système !

# Ce qui se passe :
# 1. Python appelle la bibliothèque C
# 2. Bibliothèque C fait un system call (syscall)
# 3. CPU bascule en Ring 0 (kernel mode)
# 4. Kernel exécute l'opération (lire fichier)
# 5. Kernel retourne en Ring 3 avec les données


# === MMU (Memory Management Unit) ===

# La MMU traduit adresses virtuelles -> physiques

┌──────────────────────────────────────────────────────────────┐
│                 MÉMOIRE VIRTUELLE                            │
│                                                              │
│  Processus A voit :         Processus B voit :               │
│  ┌──────────────┐          ┌──────────────┐                │
│  │ 0x00000000   │          │ 0x00000000   │                │
│  │ ...          │          │ ...          │                │
│  │ 0x7FFFFFFF   │          │ 0x7FFFFFFF   │                │
│  └──────┬───────┘          └──────┬───────┘                │
│         │                          │                         │
│         │    MMU Translation       │                         │
│         v                          v                         │
│  ┌──────────────────────────────────────────┐               │
│  │        RAM PHYSIQUE                       │               │
│  ├──────────────────────────────────────────┤               │
│  │ 0x10000000 <- Processus A                 │               │
│  │ ...                                       │               │
│  │ 0x20000000 <- Processus B                 │               │
│  │ ...                                       │               │
│  │ 0x30000000 <- Kernel                      │               │
│  └──────────────────────────────────────────┘               │
│                                                              │
│  Chaque processus pense avoir toute la mémoire !            │
│  La MMU traduit et isole les processus                      │
└──────────────────────────────────────────────────────────────┘


# AVANTAGES :
# 1. Isolation - Un processus ne peut pas accéder à la mémoire d'un autre
# 2. Simplicité - Chaque processus voit un espace d'adressage linéaire
# 3. Swapping - Mémoire peut être sur disque (swap)


# === PAGE TABLE ===

# La MMU utilise une table de pages pour la traduction

┌──────────────────────────────────────────────────────────────┐
│                    PAGE TABLE                                │
│                                                              │
│  Adresse virtuelle : 0x12345678                             │
│                                                              │
│  Décomposition :                                             │
│  ┌─────────────┬──────────────┐                            │
│  │ Page Number │   Offset     │                            │
│  │  0x12345    │    0x678     │                            │
│  └──────┬──────┴──────┬───────┘                            │
│         │             │                                      │
│         v             │                                      │
│  ┌──────────────┐    │                                      │
│  │  Page Table  │    │                                      │
│  ├──────────────┤    │                                      │
│  │ 0x12345 -> F7 │────┘ Physical Page                       │
│  ├──────────────┤                                            │
│  │ ...          │                                            │
│  └──────────────┘                                            │
│         │                                                     │
│         v                                                     │
│  Physical Address : 0xF7000678                              │
│                      └───┬───┘└──┬──┘                       │
│                      Page   Offset                           │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === TLB (Translation Lookaside Buffer) ===

# Cache pour les translations d'adresses

# SANS TLB :
# Chaque accès mémoire nécessite 2 accès :
# 1. Lire la page table
# 2. Lire la donnée
# -> TRÈS LENT

# AVEC TLB :
# Les translations récentes sont cachées
# TLB hit : 1 cycle
# TLB miss : ~100 cycles
# Hit rate typique : 99%


# === SPECTRE & MELTDOWN ===

# Vulnérabilités hardware découvertes en 2018

┌──────────────────────────────────────────────────────────────┐
│                   SPECTRE & MELTDOWN                         │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ Exploitent l'exécution spéculative du CPU                   │
│                                                              │
│ MELTDOWN :                                                   │
│   Permet à un processus user de lire la mémoire kernel     │
│   Affecte : Intel (principalement)                          │
│                                                              │
│ SPECTRE :                                                    │
│   Permet de lire la mémoire d'autres processus             │
│   Affecte : Intel, AMD, ARM (tous)                          │
│                                                              │
│ Principe :                                                   │
│   1. Déclencher exécution spéculative vers code interdit   │
│   2. Code spéculatif laisse traces dans cache              │
│   3. Mesurer temps d'accès cache pour extraire données     │
│                                                              │
│ MITIGATIONS :                                                │
│   - Patches OS (KPTI, retpoline)                            │
│   - Microcode updates                                        │
│   - Impact performance : 5-30%                              │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === TPM (Trusted Platform Module) ===

# Puce de sécurité dédiée

┌──────────────────────────────────────────────────────────────┐
│                         TPM                                  │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ Fonctions :                                                  │
│   - Génération clés cryptographiques                        │
│   - Stockage sécurisé de clés                               │
│   - Mesure de l'intégrité du système (boot)                │
│   - Attestation à distance                                   │
│                                                              │
│ Usage :                                                      │
│   - BitLocker (Windows)                                      │
│   - FileVault (macOS)                                        │
│   - LUKS (Linux)                                             │
│   - Windows 11 (requis)                                      │
│                                                              │
└──────────────────────────────────────────────────────────────┘


[OK] RÉSUMÉ ET BONNES PRATIQUES


# === PRINCIPES CLÉS POUR DÉVELOPPEURS ===

┌──────────────────────────────────────────────────────────────┐
│          BONNES PRATIQUES ARCHITECTURE                       │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ 1. LOCALITÉ DES DONNÉES                                     │
│    [OK] Accéder aux données séquentiellement (cache-friendly) │
│    [OK] Utiliser structures contigües en mémoire              │
│    [X] Éviter accès aléatoires                                │
│                                                              │
│ 2. VECTORISATION                                             │
│    [OK] Utiliser NumPy, pandas (vectorisé)                    │
│    [OK] Éviter boucles Python                                  │
│    [OK] Profiter de SIMD automatiquement                       │
│                                                              │
│ 3. PARALLÉLISME                                              │
│    [OK] multiprocessing pour calculs CPU                       │
│    [OK] threading pour I/O                                      │
│    [OK] GPU pour calculs massivement parallèles               │
│                                                              │
│ 4. MÉMOIRE                                                   │
│    [OK] Libérer ressources (close files, connections)         │
│    [OK] Utiliser générateurs pour gros datasets               │
│    [OK] Profiler utilisation mémoire                           │
│                                                              │
│ 5. I/O                                                       │
│    [OK] Async I/O pour réseau                                  │
│    [OK] Buffering pour fichiers                                │
│    [OK] Compression pour gros transferts                       │
│                                                              │
│ 6. OPTIMISATION PRÉMATURÉE                                  │
│    [X] "Premature optimization is the root of all evil"      │
│    [OK] Profiler D'ABORD, optimiser ENSUITE                   │
│    [OK] Optimiser les 20% qui prennent 80% du temps           │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === OUTILS DE DIAGNOSTIC ===

# Monitorer les ressources système

import psutil

# CPU
print(f"CPU cores : {psutil.cpu_count()}")
print(f"CPU usage : {psutil.cpu_percent(interval=1)}%")
print(f"CPU freq  : {psutil.cpu_freq().current} MHz")

# Mémoire
mem = psutil.virtual_memory()
print(f"RAM total : {mem.total / (1024**3):.1f} GB")
print(f"RAM used  : {mem.used / (1024**3):.1f} GB ({mem.percent}%)")
print(f"RAM free  : {mem.available / (1024**3):.1f} GB")

# Disque
disk = psutil.disk_usage('/')
print(f"Disk total: {disk.total / (1024**3):.1f} GB")
print(f"Disk used : {disk.used / (1024**3):.1f} GB ({disk.percent}%)")

# I/O
io = psutil.disk_io_counters()
print(f"Disk read : {io.read_bytes / (1024**3):.1f} GB")
print(f"Disk write: {io.write_bytes / (1024**3):.1f} GB")

# Réseau
net = psutil.net_io_counters()
print(f"Net sent  : {net.bytes_sent / (1024**3):.1f} GB")
print(f"Net recv  : {net.bytes_recv / (1024**3):.1f} GB")


# === CHECKLIST D'OPTIMISATION ===

┌──────────────────────────────────────────────────────────────┐
│           CHECKLIST OPTIMISATION PERFORMANCE                 │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ [WHITE_SQUARE] Profiler le code (cProfile, line_profiler)               │
│ [WHITE_SQUARE] Identifier les bottlenecks (CPU, RAM, I/O, Réseau)       │
│ [WHITE_SQUARE] Optimiser les algorithmes (O(n²) -> O(n log n))           │
│ [WHITE_SQUARE] Utiliser structures de données appropriées                │
│ [WHITE_SQUARE] Vectoriser avec NumPy/pandas                              │
│ [WHITE_SQUARE] Paralléliser les calculs indépendants                     │
│ [WHITE_SQUARE] Utiliser le caching (functools.lru_cache)                │
│ [WHITE_SQUARE] Optimiser accès mémoire (localité)                        │
│ [WHITE_SQUARE] Utiliser générateurs pour gros datasets                   │
│ [WHITE_SQUARE] Compresser données si possible                            │
│ [WHITE_SQUARE] Async I/O pour opérations réseau                          │
│ [WHITE_SQUARE] Éviter allocations mémoire inutiles                       │
│ [WHITE_SQUARE] Benchmarker avant/après optimisation                      │
│ [WHITE_SQUARE] Documenter les optimisations                              │
│                                                              │
└──────────────────────────────────────────────────────────────┘


[OK] FIN DU GUIDE

Ce guide couvre les aspects fondamentaux de l'architecture des ordinateurs
essentiels pour un développeur :

[OK] CPU et exécution d'instructions
[OK] Hiérarchie mémoire (registres, cache, RAM, disque)
[OK] Bus et interconnexions
[OK] I/O et périphériques
[OK] Parallélisme et optimisation
[OK] Architectures modernes (ARM, GPU, etc.)
[OK] Virtualisation et conteneurs
[OK] Sécurité matérielle

Pour aller plus loin :
- Assembleur (x86, ARM)
- Conception de CPU (VHDL, Verilog)
- Systèmes d'exploitation
- Architecture distribuée
- Calcul quantique
```

```
[OK] PARTIE 10 : ARCHITECTURE DISTRIBUÉE


# === QU'EST-CE QU'UN SYSTÈME DISTRIBUÉ ? ===

Un système distribué est composé de plusieurs ordinateurs qui travaillent
ensemble comme un seul système.

┌──────────────────────────────────────────────────────────────┐
│              SYSTÈME CENTRALISÉ                              │
│                                                              │
│         Client 1  ────┐                                      │
│         Client 2  ────┤                                      │
│         Client 3  ────┼───->  ┌──────────────┐              │
│         Client 4  ────┤      │   Serveur    │              │
│         Client 5  ────┘      │   Unique     │              │
│                              └──────────────┘              │
│                                                              │
│  [X] Point unique de défaillance (SPOF)                      │
│  [X] Limite de scalabilité                                    │
│  [OK] Simple à gérer                                           │
│                                                              │
└──────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────┐
│              SYSTÈME DISTRIBUÉ                               │
│                                                              │
│  Client 1 ──┐     ┌─────────┐     ┌─────────┐             │
│  Client 2 ──┼────->│ Server 1│<-───->│ Server 2│             │
│  Client 3 ──┤     └────┬────┘     └────┬────┘             │
│  Client 4 ──┤          │               │                    │
│  Client 5 ──┘          │    ┌─────────┐│                    │
│                        └───->│ Server 3│<-                    │
│                             └─────────┘                     │
│                                                              │
│  [OK] Tolérance aux pannes                                     │
│  [OK] Scalabilité horizontale                                  │
│  [X] Complexité accrue                                        │
│  [X] Problèmes de cohérence                                   │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === THÉORÈME CAP ===

# Le théorème CAP stipule qu'un système distribué ne peut garantir
# que 2 des 3 propriétés suivantes simultanément :

┌──────────────────────────────────────────────────────────────┐
│                    THÉORÈME CAP                              │
│                                                              │
│                       ┌─────────┐                           │
│                       │    C    │                           │
│                       │Cohérence│                           │
│                       └────┬────┘                           │
│                            │                                 │
│                ┌───────────┴───────────┐                    │
│                │                       │                    │
│         ┌──────[BLACK_DOWN-POINTING_TRIANGLE]──────┐         ┌─────[BLACK_DOWN-POINTING_TRIANGLE]──────┐            │
│         │      A      │         │      P     │            │
│         │Disponibilité│         │ Partition  │            │
│         │ (Availability)         │ Tolerance  │            │
│         └─────────────┘         └────────────┘            │
│                                                              │
│ C (Consistency) : Tous les nœuds voient les mêmes données  │
│ A (Availability): Le système répond toujours               │
│ P (Partition Tolerance): Fonctionne malgré coupures réseau│
│                                                              │
│ CHOIX POSSIBLES :                                           │
│   CA : Cohérence + Disponibilité (ex: RDBMS classique)     │
│        -> Impossible en cas de partition réseau !            │
│                                                              │
│   CP : Cohérence + Tolérance aux partitions                │
│        (ex: MongoDB, HBase, Redis)                          │
│        -> Peut refuser requêtes pour garantir cohérence      │
│                                                              │
│   AP : Disponibilité + Tolérance aux partitions            │
│        (ex: Cassandra, DynamoDB, CouchDB)                   │
│        -> Cohérence éventuelle (eventual consistency)        │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple : Incohérence dans un système AP

# Situation :
# - 3 serveurs : S1, S2, S3
# - Partition réseau : S1 isolé de S2 et S3

# Client A écrit sur S1 : user.balance = 100
# Client B lit depuis S2 : user.balance = 50 (ancienne valeur)

# Le système est DISPONIBLE mais INCOHÉRENT
# Après réparation de la partition, la cohérence est restaurée


# === CONSENSUS DISTRIBUÉ ===

# Comment plusieurs machines se mettent d'accord ?

┌──────────────────────────────────────────────────────────────┐
│                ALGORITHMES DE CONSENSUS                      │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ PAXOS (1989)                                                │
│   [OK] Prouvé mathématiquement correct                         │
│   [X] Très complexe à implémenter                             │
│   [X] Difficile à comprendre                                  │
│                                                              │
│ RAFT (2014)                                                 │
│   [OK] Plus simple que Paxos                                   │
│   [OK] Facile à comprendre                                     │
│   [OK] Largement utilisé                                       │
│   Usage : etcd, Consul, CockroachDB                         │
│                                                              │
│ PROTOCOLE 2PC (Two-Phase Commit)                            │
│   Phase 1: Préparation                                      │
│     - Coordinateur demande à tous : "Prêt ?"               │
│     - Participants répondent : Oui/Non                      │
│   Phase 2: Commit                                           │
│     - Si tous Oui : Commit                                  │
│     - Si un Non : Abort                                     │
│                                                              │
│   [X] Problème : Coordinateur = SPOF                          │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple : RAFT simplifié

┌──────────────────────────────────────────────────────────────┐
│                    RAFT - ÉLECTION LEADER                    │
│                                                              │
│  Initialement : 3 nœuds (S1, S2, S3)                        │
│                                                              │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                     │
│  │   S1    │  │   S2    │  │   S3    │                     │
│  │Follower │  │Follower │  │Follower │                     │
│  └─────────┘  └─────────┘  └─────────┘                     │
│                                                              │
│  Timeout -> S1 devient candidat                               │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                     │
│  │   S1    │  │   S2    │  │   S3    │                     │
│  │Candidate│-> │Follower │  │Follower │                     │
│  └─────────┘  └─────────┘  └─────────┘                     │
│       │           v             v                            │
│       └──── Vote Request ───────┘                            │
│                                                              │
│  S2 et S3 votent pour S1                                    │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                     │
│  │   S1    │  │   S2    │  │   S3    │                     │
│  │ LEADER  │<-─│Follower │  │Follower │                     │
│  └─────────┘  └─────────┘  └─────────┘                     │
│       │           │             │                            │
│       └─── Heartbeat ───────────┘                            │
│                                                              │
│  S1 envoie des heartbeats réguliers                         │
│  Si S1 meurt, nouvelle élection                             │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === LOAD BALANCING ===

# Répartir la charge entre plusieurs serveurs

┌──────────────────────────────────────────────────────────────┐
│                   LOAD BALANCER                              │
│                                                              │
│   Clients                                                    │
│      │                                                       │
│      v                                                       │
│  ┌───────────────┐                                          │
│  │     Load      │  Algorithmes :                           │
│  │   Balancer    │  - Round Robin (tour à tour)             │
│  │  (HAProxy,    │  - Least Connections (moins chargé)     │
│  │   Nginx)      │  - IP Hash (même client -> même serveur) │
│  └───┬───┬───┬───┘  - Weighted (pondéré par capacité)      │
│      │   │   │                                               │
│  ┌───[BLACK_DOWN-POINTING_TRIANGLE]┐ ┌[BLACK_DOWN-POINTING_TRIANGLE]──┐ ┌[BLACK_DOWN-POINTING_TRIANGLE]───┐                                        │
│  │ S1 │ │S2 │ │ S3 │  Serveurs backend                     │
│  └────┘ └───┘ └────┘                                        │
│                                                              │
│  Health Checks : Le LB vérifie que les serveurs sont up    │
│  Si S2 tombe, le trafic va vers S1 et S3                    │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple en Python avec Flask + nginx

# app.py (serveur Flask)
from flask import Flask
import socket

app = Flask(__name__)

@app.route('/')
def hello():
    hostname = socket.gethostname()
    return f"Hello from {hostname}!"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)


# nginx.conf (load balancer)
# 
# upstream backend {
#     server 192.168.1.10:5000;  # Serveur 1
#     server 192.168.1.11:5000;  # Serveur 2
#     server 192.168.1.12:5000;  # Serveur 3
# }
# 
# server {
#     listen 80;
#     
#     location / {
#         proxy_pass http://backend;
#         proxy_set_header Host $host;
#         proxy_set_header X-Real-IP $remote_addr;
#     }
# }


# === SHARDING (PARTITIONNEMENT) ===

# Diviser les données entre plusieurs serveurs

┌──────────────────────────────────────────────────────────────┐
│                    SHARDING                                  │
│                                                              │
│  Base de données trop grosse pour un serveur                │
│  -> Diviser en shards (fragments)                            │
│                                                              │
│  MÉTHODES DE SHARDING :                                     │
│                                                              │
│  1. RANGE-BASED (par plage)                                 │
│     Users A-M  -> Shard 1                                    │
│     Users N-Z  -> Shard 2                                    │
│                                                              │
│     [OK] Simple                                                 │
│     [X] Distribution peut être inégale                         │
│                                                              │
│  2. HASH-BASED (par hash)                                   │
│     hash(user_id) % 3                                        │
│       0 -> Shard 1                                            │
│       1 -> Shard 2                                            │
│       2 -> Shard 3                                            │
│                                                              │
│     [OK] Distribution uniforme                                 │
│     [X] Difficile d'ajouter/retirer shards                    │
│                                                              │
│  3. CONSISTENT HASHING                                       │
│     Utilise un anneau de hash                               │
│     [OK] Facile d'ajouter/retirer nœuds                        │
│     [OK] Distribution uniforme                                 │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple : Sharding en Python

class ShardedDatabase:
    def __init__(self, num_shards=3):
        self.num_shards = num_shards
        # Simuler 3 bases de données
        self.shards = [dict() for _ in range(num_shards)]
    
    def _get_shard(self, key):
        """Déterminer quel shard utiliser"""
        shard_id = hash(key) % self.num_shards
        return self.shards[shard_id]
    
    def set(self, key, value):
        """Écrire dans le bon shard"""
        shard = self._get_shard(key)
        shard[key] = value
        print(f"Stored '{key}' in shard {hash(key) % self.num_shards}")
    
    def get(self, key):
        """Lire depuis le bon shard"""
        shard = self._get_shard(key)
        return shard.get(key)

# Utilisation
db = ShardedDatabase(num_shards=3)

db.set("user_1", {"name": "Alice", "age": 30})
db.set("user_2", {"name": "Bob", "age": 25})
db.set("user_3", {"name": "Charlie", "age": 35})

print(db.get("user_1"))  # Récupère depuis le bon shard

# Affichage des shards
for i, shard in enumerate(db.shards):
    print(f"Shard {i}: {len(shard)} entries")


# === RÉPLICATION ===

# Copier les données sur plusieurs serveurs

┌──────────────────────────────────────────────────────────────┐
│                     RÉPLICATION                              │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ MASTER-SLAVE (Primary-Replica)                              │
│                                                              │
│   Write ──-> ┌────────┐                                      │
│             │ Master │                                       │
│             └───┬────┘                                       │
│                 │ Replication                                │
│        ┌────────┼────────┐                                  │
│        v        v        v                                   │
│    ┌──────┐ ┌──────┐ ┌──────┐                              │
│    │Slave1│ │Slave2│ │Slave3│                              │
│    └───┬──┘ └───┬──┘ └───┬──┘                              │
│        ^        ^        ^                                   │
│        └────────┴────────┘                                   │
│              Reads                                           │
│                                                              │
│   [OK] Écritures sur Master uniquement                         │
│   [OK] Lectures réparties sur Slaves (scalabilité lecture)    │
│   [X] Master = SPOF pour les écritures                        │
│                                                              │
│ MULTI-MASTER                                                │
│                                                              │
│   Writes  ┌────────┐  Writes                                │
│      ────->│Master 1│<-────                                   │
│           └───┬────┘                                         │
│               │ ^v Sync                                       │
│   Writes  ┌───[BLACK_DOWN-POINTING_TRIANGLE]────┐  Writes                                │
│      ────->│Master 2│<-────                                   │
│           └────────┘                                         │
│                                                              │
│   [OK] Pas de SPOF                                             │
│   [OK] Haute disponibilité                                     │
│   [X] Conflits d'écriture possibles                           │
│   [X] Plus complexe                                           │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === COHÉRENCE ÉVENTUELLE ===

# Les réplicas finissent par converger

# Exemple : Panier d'achat Amazon

# Temps T0 : User ajoute "Laptop" au panier
# - Écrit sur Serveur US-East

# Temps T1 : User refresh depuis Europe
# - Lit depuis Serveur EU-West
# - Panier VIDE (réplication pas encore propagée)

# Temps T2 : Réplication terminée
# - Panier contient "Laptop" partout

# STRATÉGIES :
# - Read Your Writes : Garantit que l'utilisateur voit ses propres écritures
# - Session Consistency : Cohérence pendant la session
# - Causal Consistency : Respecte l'ordre causal


# === MESSAGE QUEUES ===

# Communication asynchrone entre services

┌──────────────────────────────────────────────────────────────┐
│                   MESSAGE QUEUE                              │
│                                                              │
│  Producer 1 ──┐                                              │
│  Producer 2 ──┼──-> ┌──────────────┐ ──-> Consumer 1         │
│  Producer 3 ──┘    │    Queue     │ ──-> Consumer 2         │
│                    │ (RabbitMQ,   │ ──-> Consumer 3         │
│                    │  Kafka,      │                         │
│                    │  Redis)      │                         │
│                    └──────────────┘                         │
│                                                              │
│  AVANTAGES :                                                 │
│    [OK] Découplage (producer/consumer indépendants)           │
│    [OK] Résilience (messages persistés)                        │
│    [OK] Scalabilité (ajouter consumers)                        │
│    [OK] Load leveling (lissage de charge)                      │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple avec Redis (queue simple)

import redis
import json
import time

# Connecter à Redis
r = redis.Redis(host='localhost', port=6379, decode_responses=True)

# PRODUCER
def produce_message(task_data):
    """Ajouter une tâche à la queue"""
    message = json.dumps(task_data)
    r.lpush('task_queue', message)
    print(f"Produced: {task_data}")

# CONSUMER
def consume_messages():
    """Traiter les tâches de la queue"""
    while True:
        # Attendre un message (bloquant)
        message = r.brpop('task_queue', timeout=5)
        
        if message:
            task = json.loads(message[1])
            print(f"Processing: {task}")
            # Traiter la tâche...
            time.sleep(1)  # Simuler traitement
            print(f"Completed: {task}")
        else:
            print("No messages, waiting...")

# Utilisation
# Terminal 1 (producer):
# produce_message({"task": "send_email", "to": "user@example.com"})
# produce_message({"task": "resize_image", "image_id": 123})

# Terminal 2 (consumer):
# consume_messages()


# === MICROSERVICES ===

# Architecture où l'application est divisée en petits services

┌──────────────────────────────────────────────────────────────┐
│              MONOLITHE vs MICROSERVICES                      │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ MONOLITHE :                                                  │
│  ┌────────────────────────────────────────┐                 │
│  │         Application Unique             │                 │
│  │  ┌──────────┬──────────┬──────────┐   │                 │
│  │  │   Auth   │ Products │ Orders   │   │                 │
│  │  └──────────┴──────────┴──────────┘   │                 │
│  │  ┌──────────────────────────────────┐ │                 │
│  │  │    Database (PostgreSQL)         │ │                 │
│  │  └──────────────────────────────────┘ │                 │
│  └────────────────────────────────────────┘                 │
│                                                              │
│  [OK] Simple à développer initialement                         │
│  [OK] Simple à déployer                                        │
│  [X] Scaling : tout ou rien                                   │
│  [X] Un bug peut tout casser                                  │
│  [X] Difficile à maintenir quand gros                         │
│                                                              │
│ MICROSERVICES :                                              │
│  ┌─────────┐  ┌──────────┐  ┌─────────┐                    │
│  │  Auth   │  │ Products │  │ Orders  │                    │
│  │ Service │  │ Service  │  │ Service │                    │
│  ├─────────┤  ├──────────┤  ├─────────┤                    │
│  │ Auth DB │  │ Prod DB  │  │Order DB │                    │
│  └────┬────┘  └────┬─────┘  └────┬────┘                    │
│       └────────────┼─────────────┘                           │
│                    │ API Gateway / Service Mesh              │
│                                                              │
│  [OK] Scaling indépendant par service                          │
│  [OK] Isolation des pannes                                     │
│  [OK] Technologies différentes par service                     │
│  [X] Complexité opérationnelle                                │
│  [X] Latence réseau entre services                            │
│  [X] Debugging plus difficile                                 │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple : Architecture microservices avec Flask

# service_auth.py
from flask import Flask, request, jsonify
import jwt

app = Flask(__name__)
SECRET = "secret_key"

@app.route('/login', methods=['POST'])
def login():
    data = request.json
    # Vérifier credentials...
    token = jwt.encode({'user_id': 123}, SECRET, algorithm='HS256')
    return jsonify({'token': token})

@app.route('/verify', methods=['POST'])
def verify():
    token = request.json['token']
    try:
        payload = jwt.decode(token, SECRET, algorithms=['HS256'])
        return jsonify({'valid': True, 'user_id': payload['user_id']})
    except:
        return jsonify({'valid': False}), 401

if __name__ == '__main__':
    app.run(port=5001)


# service_products.py
from flask import Flask, jsonify
import requests

app = Flask(__name__)
AUTH_SERVICE = 'http://localhost:5001'

def verify_token(token):
    """Vérifier le token via le service d'auth"""
    response = requests.post(
        f'{AUTH_SERVICE}/verify',
        json={'token': token}
    )
    return response.json().get('valid', False)

@app.route('/products')
def get_products():
    # Vérifier authentification
    token = request.headers.get('Authorization')
    if not verify_token(token):
        return jsonify({'error': 'Unauthorized'}), 401
    
    # Retourner produits
    return jsonify({
        'products': [
            {'id': 1, 'name': 'Laptop', 'price': 1299},
            {'id': 2, 'name': 'Mouse', 'price': 29}
        ]
    })

if __name__ == '__main__':
    app.run(port=5002)


# === API GATEWAY ===

# Point d'entrée unique pour tous les microservices

┌──────────────────────────────────────────────────────────────┐
│                    API GATEWAY                               │
│                                                              │
│   Client (Mobile/Web)                                        │
│          │                                                    │
│          v                                                    │
│   ┌──────────────┐                                           │
│   │ API Gateway  │  Fonctions :                              │
│   │  (Kong,      │  - Routing                                │
│   │   Nginx)     │  - Rate Limiting                          │
│   │              │  - Authentication                          │
│   └──────┬───────┘  - Load Balancing                         │
│          │          - Caching                                │
│    ┌─────┼─────┬──────────┬──────────┐                      │
│    v     v     v          v          v                      │
│  Auth Products Orders   Users     Payment                    │
│  Service Service Service Service  Service                    │
│                                                              │
│  Au lieu de N endpoints, client n'a qu'un seul point d'entrée│
└──────────────────────────────────────────────────────────────┘


# === SERVICE MESH ===

# Infrastructure layer pour gérer la communication entre microservices

┌──────────────────────────────────────────────────────────────┐
│                   SERVICE MESH (Istio, Linkerd)              │
│                                                              │
│  Chaque service a un "sidecar proxy"                        │
│                                                              │
│  ┌────────────────┐       ┌────────────────┐               │
│  │   Service A    │       │   Service B    │               │
│  │  ┌──────────┐  │       │  ┌──────────┐  │               │
│  │  │   App    │  │       │  │   App    │  │               │
│  │  └────┬─────┘  │       │  └────┬─────┘  │               │
│  │       │        │       │       │        │               │
│  │  ┌────[BLACK_DOWN-POINTING_TRIANGLE]─────┐  │       │  ┌────[BLACK_DOWN-POINTING_TRIANGLE]─────┐  │               │
│  │  │  Proxy   │──┼──────->│──│  Proxy   │  │               │
│  │  │ (Envoy)  │  │       │  │ (Envoy)  │  │               │
│  │  └──────────┘  │       │  └──────────┘  │               │
│  └────────────────┘       └────────────────┘               │
│                                                              │
│  Le proxy gère :                                             │
│    - Load balancing                                          │
│    - Circuit breaking                                        │
│    - Retries                                                 │
│    - Timeouts                                                │
│    - Metrics & tracing                                       │
│    - Mutual TLS                                              │
│                                                              │
└──────────────────────────────────────────────────────────────┘


[OK] PARTIE 11 : INTERNET DES OBJETS (IoT)


# === ARCHITECTURE IoT ===

┌──────────────────────────────────────────────────────────────┐
│                  STACK IoT TYPIQUE                           │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              DEVICES (Capteurs/Actionneurs)            │ │
│  │  Température, Humidité, Caméras, Moteurs, etc.        │ │
│  └───────────────────┬────────────────────────────────────┘ │
│                      │ MQTT, CoAP, LoRaWAN                  │
│  ┌───────────────────[BLACK_DOWN-POINTING_TRIANGLE]────────────────────────────────────┐ │
│  │            EDGE (Gateway)                              │ │
│  │  - Agrégation données                                  │ │
│  │  - Preprocessing                                        │ │
│  │  │  - Buffering                                        │ │
│  └───────────────────┬────────────────────────────────────┘ │
│                      │ HTTPS, WebSocket                     │
│  ┌───────────────────[BLACK_DOWN-POINTING_TRIANGLE]────────────────────────────────────┐ │
│  │         CLOUD (Backend)                                │ │
│  │  - Stockage (Time-series DB)                          │ │
│  │  - Analytics                                            │ │
│  │  - Machine Learning                                     │ │
│  └───────────────────┬────────────────────────────────────┘ │
│                      │ REST API, WebSocket                  │
│  ┌───────────────────[BLACK_DOWN-POINTING_TRIANGLE]────────────────────────────────────┐ │
│  │        APPLICATION (Dashboard, Mobile App)             │ │
│  │  - Visualisation                                        │ │
│  │  - Contrôle                                             │ │
│  │  - Alertes                                              │ │
│  └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘


# === CONTRAINTES IoT ===

┌──────────────────────────────────────────────────────────────┐
│               CONTRAINTES DES DEVICES IoT                    │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ 1. ÉNERGIE LIMITÉE                                          │
│    - Batterie de quelques mAh à quelques Ah                │
│    - Durée de vie visée : mois/années                       │
│    -> Optimiser consommation CPU, radio                      │
│                                                              │
│ 2. MÉMOIRE LIMITÉE                                          │
│    - RAM : 2KB - 512KB                                      │
│    - Flash : 32KB - 4MB                                     │
│    -> Code compact, pas de frameworks lourds                 │
│                                                              │
│ 3. CPU LIMITÉ                                               │
│    - 8-bit à 32-bit                                         │
│    - 1 MHz - 200MHz                                        │
│    -> Calculs simples, pas de ML complexe                    │
│                                                              │
│ 4. CONNECTIVITÉ INTERMITTENTE                               │
│    - Réseau peut être indisponible                          │
│    -> Buffering, retry logic                                 │
│                                                              │
│ 5. SÉCURITÉ                                                  │
│    - Risque de compromise physique                          │
│    - Attaques DDoS (Mirai botnet)                          │
│    -> Encryption, secure boot, OTA updates                   │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple : Code pour Arduino (C++)

// Capteur température DHT22 + WiFi
#include <ESP8266WiFi.h>
#include <DHT.h>
#include <PubSubClient.h>  // MQTT

#define DHTPIN 2        // GPIO2
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);
WiFiClient espClient;
PubSubClient mqtt(espClient);

const char* ssid = "YOUR_WIFI";
const char* password = "YOUR_PASSWORD";
const char* mqtt_server = "broker.hivemq.com";

void setup() {
    Serial.begin(115200);
    dht.begin();
    
    // Connecter WiFi
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    
    // Connecter MQTT
    mqtt.setServer(mqtt_server, 1883);
}

void loop() {
    if (!mqtt.connected()) {
        mqtt.connect("ESP8266Client");
    }
    mqtt.loop();
    
    // Lire capteur
    float temp = dht.readTemperature();
    float humidity = dht.readHumidity();
    
    // Publier via MQTT
    char msg[50];
    snprintf(msg, 50, "{\"temp\":%.1f,\"hum\":%.1f}", temp, humidity);
    mqtt.publish("home/sensors/bedroom", msg);
    
    // Sleep pour économiser batterie
    delay(60000);  // 1 minute
}


# === PROTOCOLES IoT ===

┌──────────────────────────────────────────────────────────────┐
│                  PROTOCOLES IoT                              │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ MQTT (Message Queue Telemetry Transport)                    │
│   - Léger, pub/sub                                          │
│   - QoS 0, 1, 2 (qualité de service)                        │
│   - Idéal pour contraintes réseau                           │
│   - Port : 1883 (8883 avec TLS)                             │
│                                                              │
│ CoAP (Constrained Application Protocol)                     │
│   - Similaire HTTP mais pour IoT                            │
│   - UDP au lieu de TCP                                       │
│   - Très léger                                               │
│   - Port : 5683                                              │
│                                                              │
│ LoRaWAN (Long Range WAN)                                    │
│   - Longue portée (2-15 km)                                 │
│   - Très basse consommation                                 │
│   - Faible débit (0.3-50 kbps)                             │
│   - Idéal pour capteurs extérieurs                          │
│                                                              │
│ Zigbee / Z-Wave                                             │
│   - Mesh network                                             │
│   - Courte portée (10-100m)                                 │
│   - Idéal pour domotique                                    │
│                                                              │
│ BLE (Bluetooth Low Energy)                                  │
│   - Très basse consommation                                 │
│   - Courte portée (10-100m)                                 │
│   - Idéal pour wearables                                    │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple : Client MQTT en Python

import paho.mqtt.client as mqtt
import json
import time

# Callbacks
def on_connect(client, userdata, flags, rc):
    print(f"Connected with result code {rc}")
    # S'abonner aux topics
    client.subscribe("home/sensors/#")  # # = wildcard

def on_message(client, userdata, msg):
    print(f"Topic: {msg.topic}")
    data = json.loads(msg.payload.decode())
    print(f"Data: {data}")
    
    # Traiter les données
    if 'temp' in data:
        temp = data['temp']
        if temp > 25:
            print("[ATTENTION]  Temperature élevée!")

# Créer client
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

# Connecter au broker
client.connect("broker.hivemq.com", 1883, 60)

# Loop pour recevoir messages
client.loop_forever()


[OK] PARTIE 12 : ARCHITECTURE QUANTIQUE


# === QU'EST-CE QU'UN ORDINATEUR QUANTIQUE ? ===

# Un ordinateur quantique utilise les propriétés de la mécanique quantique

┌──────────────────────────────────────────────────────────────┐
│          ORDINATEUR CLASSIQUE vs QUANTIQUE                   │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ BIT CLASSIQUE                                                │
│   État : 0 OU 1                                             │
│   ┌───┐   ┌───┐                                             │
│   │ 0 │   │ 1 │                                             │
│   └───┘   └───┘                                             │
│                                                              │
│ QUBIT (Bit Quantique)                                        │
│   État : 0 ET 1 simultanément (superposition)              │
│   ┌─────────────┐                                           │
│   │  α|0⟩ + β|1⟩│  où |α|² + |β|² = 1                      │
│   └─────────────┘                                           │
│                                                              │
│   Exemple : α=0.7, β=0.7                                    │
│   -> 50% chance de mesurer 0, 50% chance de mesurer 1       │
│                                                              │
│ INTRICATION (Entanglement)                                   │
│   2 qubits intriqués sont liés, mesurer l'un affecte l'autre│
│   même à distance                                            │
│                                                              │
│ SCALING :                                                    │
│   N bits classiques : 2^N états possibles (un à la fois)   │
│   N qubits : 2^N états EN MÊME TEMPS (superposition)       │
│                                                              │
│   3 bits : 000, 001, 010, ..., 111 (8 états, un seul actif)│
│   3 qubits : TOUS les 8 états simultanément !              │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === AVANTAGES ET LIMITES ===

┌──────────────────────────────────────────────────────────────┐
│            ORDINATEURS QUANTIQUES                            │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ EXCEL À :                                                    │
│   [OK] Factorisation (casser RSA)                              │
│   [OK] Recherche dans bases non triées (algorithme de Grover) │
│   [OK] Simulation quantique (chimie, matériaux)               │
│   [OK] Optimisation                                             │
│   [OK] Machine Learning (certains algorithmes)                │
│                                                              │
│ MAUVAIS POUR :                                               │
│   [X] Calculs classiques                                      │
│   [X] Stockage de données                                     │
│   [X] Applications générales                                  │
│                                                              │
│ DÉFIS :                                                      │
│   - Décohérence (qubits perdent leur état rapidement)      │
│   - Besoin de températures extrêmes (~15 mK)               │
│   - Taux d'erreur élevé                                     │
│   - Nombre limité de qubits (~1000 actuellement)           │
│   - Coût astronomique                                        │
│                                                              │
│ HORIZON :                                                    │
│   - Ordinateurs quantiques universels : 10-20 ans          │
│   - Applications pratiques : progresse graduellement        │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple : Code quantique (Qiskit - IBM)

from qiskit import QuantumCircuit, transpile
from qiskit_aer import Aer
from qiskit.visualization import plot_histogram

# Créer un circuit quantique avec 2 qubits
qc = QuantumCircuit(2, 2)  # 2 qubits, 2 bits classiques

# Créer une superposition sur le premier qubit
qc.h(0)  # Hadamard gate : |0⟩ -> (|0⟩ + |1⟩)/√2

# Intriquer les 2 qubits
qc.cx(0, 1)  # CNOT gate : intrication

# Mesurer
qc.measure([0, 1], [0, 1])

# Visualiser le circuit
print(qc.draw())

# Simuler
simulator = Aer.get_backend('qasm_simulator')
compiled_circuit = transpile(qc, simulator)
result = simulator.run(compiled_circuit, shots=1000).result()
counts = result.get_counts()

print(f"Résultats : {counts}")
# Output typique : {'00': 500, '11': 500}
# Les qubits sont intriqués : toujours 00 ou 11, jamais 01 ou 10

# plot_histogram(counts)  # Visualiser


[OK] FIN COMPLÈTE DU GUIDE

Ce guide exhaustif couvre TOUS les aspects de l'architecture des ordinateurs
pour un développeur :

PARTIE 1-5 : Fondamentaux
- CPU, mémoire, stockage, bus, I/O

PARTIE 6-9 : Performance et Modern
- Optimisation, multi-core, GPU, sécurité

PARTIE 10-12 : Avancé
- Systèmes distribués, IoT, quantique

POUR ALLER PLUS LOIN :
- Computer Architecture: A Quantitative Approach (Hennessy & Patterson)
- Designing Data-Intensive Applications (Martin Kleppmann)
- Computer Organization and Design (Patterson & Hennessy)
- The Art of Multiprocessor Programming (Herlihy & Shavit)
```

```
[OK] PARTIE 13 : ARCHITECTURE NEUROMORPHIQUE


# === QU'EST-CE QUE L'ARCHITECTURE NEUROMORPHIQUE ? ===

# Architecture inspirée du cerveau humain pour le calcul

┌──────────────────────────────────────────────────────────────┐
│        ARCHITECTURE VON NEUMANN vs NEUROMORPHIQUE            │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ VON NEUMANN (architecture traditionnelle)                    │
│                                                              │
│  ┌──────────┐  ┌──────────┐                                │
│  │   CPU    │<-->│ Mémoire  │  <- Séparation CPU/Mémoire      │
│  │          │  │          │    (Bottleneck de von Neumann) │
│  └──────────┘  └──────────┘                                │
│       ^v             ^v                                        │
│   Bus (limité)                                               │
│                                                              │
│   [X] Goulot d'étranglement mémoire                           │
│   [X] Consommation élevée pour IA                             │
│   [OK] Programmation flexible                                  │
│                                                              │
│ NEUROMORPHIQUE (inspiré du cerveau)                          │
│                                                              │
│  Neurones   Synapses   Neurones                             │
│  ┌────┐    ─────────->   ┌────┐                             │
│  │ N1 │─────────────────->│ N3 │                             │
│  └────┘    ─────────->   └────┘                             │
│  ┌────┐    ─────────->   ┌────┐                             │
│  │ N2 │─────────────────->│ N4 │                             │
│  └────┘                 └────┘                             │
│                                                              │
│  Calcul ET mémoire co-localisés (synapses = mémoire)       │
│                                                              │
│   [OK] Pas de bottleneck mémoire                               │
│   [OK] Très basse consommation (milliwatts)                   │
│   [OK] Massivement parallèle                                   │
│   [X] Programmation difficile                                 │
│   [X] Applications limitées (surtout IA)                      │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === COMPARAISON CERVEAU vs ORDINATEUR ===

┌──────────────────────────────────────────────────────────────┐
│              CERVEAU HUMAIN vs SUPERORDINATEUR               │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ CERVEAU HUMAIN                                               │
│   Neurones : ~86 milliards                                  │
│   Synapses : ~100 trillions                                 │
│   Vitesse : ~200 Hz (lent!)                                 │
│   Consommation : ~20 watts                                   │
│   Parallélisme : Massif                                      │
│   Calculs/s : ~1 exaFLOP (estimé)                          │
│                                                              │
│ SUPERORDINATEUR (Fugaku)                                     │
│   Cores : ~7.3 millions                                      │
│   Mémoire : ~5 pétabytes                                    │
│   Vitesse : ~2 GHz par core                                 │
│   Consommation : ~30 MEGAWATTS (1.5 million x plus!)       │
│   Calculs/s : ~442 pétaFLOPS                                │
│                                                              │
│ EFFICACITÉ ÉNERGÉTIQUE :                                     │
│   Cerveau : 50 pétaFLOPS/watt (estimé)                     │
│   Fugaku : 14.7 gigaFLOPS/watt                             │
│   -> Cerveau est ~3 MILLIONS de fois plus efficace !        │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === PUCES NEUROMORPHIQUES ===

┌──────────────────────────────────────────────────────────────┐
│                PUCES NEUROMORPHIQUES                         │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ INTEL LOIHI 2 (2021)                                        │
│   Neurones : 1 million                                       │
│   Synapses : 120 millions                                    │
│   Consommation : ~100 mW                                     │
│   Usage : Vision, robotique                                  │
│                                                              │
│ IBM TRUENORTH (2014)                                         │
│   Neurones : 1 million                                       │
│   Synapses : 256 millions                                    │
│   Consommation : 70 mW                                       │
│   Événementiel (spiking neural network)                     │
│                                                              │
│ BRAINCHIP AKIDA (2020)                                       │
│   Commercial, pour edge AI                                   │
│   Très basse consommation                                    │
│                                                              │
│ SPINNAKER (Université Manchester)                            │
│   Simulation cerveau à grande échelle                        │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === SPIKING NEURAL NETWORKS (SNN) ===

# Les SNN utilisent des "spikes" (impulsions) comme le cerveau

┌──────────────────────────────────────────────────────────────┐
│         NEURAL NETWORK vs SPIKING NEURAL NETWORK             │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ NEURAL NETWORK CLASSIQUE                                     │
│   Neurone reçoit : valeurs continues (ex: 0.7, 0.3, 0.9)   │
│   Neurone émet : valeur continue (ex: 0.8)                  │
│   Temps : synchrone (tous calculs en même temps)            │
│                                                              │
│   Input -> [0.7, 0.3, 0.9] -> Neurone -> 0.8 -> Output         │
│                                                              │
│ SPIKING NEURAL NETWORK                                       │
│   Neurone reçoit : impulsions temporelles                    │
│   Neurone émet : impulsion SI seuil atteint                 │
│   Temps : asynchrone (événementiel)                         │
│                                                              │
│   Timeline :                                                 │
│   t=0ms  : Spike de N1                                      │
│   t=5ms  : Spike de N2                                      │
│   t=12ms : Spike de N3 (N1 + N2 -> seuil atteint)           │
│                                                              │
│   [OK] Plus biologique                                         │
│   [OK] Très économe en énergie (calculs uniquement sur spikes)│
│   [X] Plus difficile à entraîner                              │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple : SNN simple avec snnTorch (Python)

import torch
import snntorch as snn
from snntorch import spikegen

# Créer un neurone LIF (Leaky Integrate-and-Fire)
beta = 0.9  # Decay rate
lif1 = snn.Leaky(beta=beta)

# Générer des spikes depuis données continues
data = torch.tensor([0.2, 0.5, 0.8, 0.3, 0.1])
spike_data = spikegen.rate(data, num_steps=100)

# Simuler le neurone sur le temps
mem = torch.zeros(1)  # Potentiel membranaire
spk_out = []

for step in range(100):
    spk, mem = lif1(spike_data[step], mem)
    spk_out.append(spk)

# Visualiser
import matplotlib.pyplot as plt
plt.plot(spk_out)
plt.title("Spike output over time")
plt.xlabel("Time step")
plt.ylabel("Spike (0 or 1)")
# plt.show()


# === APPLICATIONS NEUROMORPHIQUES ===

┌──────────────────────────────────────────────────────────────┐
│         APPLICATIONS NEUROMORPHIQUES                         │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ 1. VISION PAR ORDINATEUR (Event-based)                      │
│    Caméras neuromorphiques (DVS - Dynamic Vision Sensor)    │
│    -> Détecte CHANGEMENTS, pas frames complètes              │
│    -> 1000x moins de données                                  │
│    -> Latence ultra-faible (microseconde)                    │
│    Usage : Drones, voitures autonomes                        │
│                                                              │
│ 2. ROBOTIQUE                                                 │
│    Contrôle moteur en temps réel                            │
│    Navigation autonome                                       │
│    Basse consommation pour robots mobiles                   │
│                                                              │
│ 3. EDGE AI                                                   │
│    Inférence locale sur appareils IoT                       │
│    Reconnaissance vocale                                     │
│    Détection d'anomalies                                     │
│                                                              │
│ 4. INTERFACES CERVEAU-MACHINE (BCI)                         │
│    Prothèses neuronales                                      │
│    Contrôle d'appareils par la pensée                       │
│                                                              │
└──────────────────────────────────────────────────────────────┘


[OK] PARTIE 14 : ARCHITECTURE DE CLOUD COMPUTING


# === MODÈLES DE CLOUD ===

┌──────────────────────────────────────────────────────────────┐
│                 MODÈLES DE CLOUD                             │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ IaaS (Infrastructure as a Service)                          │
│   Vous gérez : OS, Runtime, Apps                            │
│   Provider gère : Hardware, Réseau, Stockage, Virtualisation│
│   Exemples : AWS EC2, Azure VMs, Google Compute Engine      │
│                                                              │
│   ┌────────────────────────────────────┐                    │
│   │         Vos Applications           │ <- Vous             │
│   ├────────────────────────────────────┤                    │
│   │         OS / Runtime               │ <- Vous             │
│   ├────────────────────────────────────┤                    │
│   │  Virtualisation / Storage / Network│ <- Provider         │
│   ├────────────────────────────────────┤                    │
│   │         Hardware                   │ <- Provider         │
│   └────────────────────────────────────┘                    │
│                                                              │
│ PaaS (Platform as a Service)                                │
│   Vous gérez : Apps, Données                                │
│   Provider gère : OS, Runtime, Middleware                   │
│   Exemples : Heroku, Google App Engine, Azure App Service  │
│                                                              │
│   ┌────────────────────────────────────┐                    │
│   │         Vos Applications           │ <- Vous             │
│   ├────────────────────────────────────┤                    │
│   │   Runtime / Middleware / OS        │ <- Provider         │
│   ├────────────────────────────────────┤                    │
│   │  Virtualisation / Storage / Network│ <- Provider         │
│   ├────────────────────────────────────┤                    │
│   │         Hardware                   │ <- Provider         │
│   └────────────────────────────────────┘                    │
│                                                              │
│ SaaS (Software as a Service)                                │
│   Vous gérez : Configuration, Données                       │
│   Provider gère : Tout le reste                             │
│   Exemples : Gmail, Salesforce, Dropbox, Office 365        │
│                                                              │
│   ┌────────────────────────────────────┐                    │
│   │      Application complète          │ <- Provider         │
│   │      (vous utilisez juste)         │                    │
│   └────────────────────────────────────┘                    │
│                                                              │
│ FaaS (Function as a Service) / Serverless                   │
│   Vous gérez : Code de vos fonctions                        │
│   Provider gère : TOUT (scaling, infra, etc.)              │
│   Exemples : AWS Lambda, Azure Functions, Google Functions │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === DATACENTER ===

# Architecture physique d'un datacenter cloud

┌──────────────────────────────────────────────────────────────┐
│                   DATACENTER                                 │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │              RÉGION (ex: us-east-1)                    │ │
│  │                                                         │ │
│  │  ┌───────────────┐  ┌───────────────┐  ┌────────────┐│ │
│  │  │ ZONE A        │  │ ZONE B        │  │ ZONE C     ││ │
│  │  │               │  │               │  │            ││ │
│  │  │ ┌───────────┐ │  │ ┌───────────┐ │  │┌──────────┐││ │
│  │  │ │Datacenter │ │  │ │Datacenter │ │  ││Datacenter│││ │
│  │  │ │   1       │ │  │ │   2       │ │  ││    3     │││ │
│  │  │ └───────────┘ │  │ └───────────┘ │  │└──────────┘││ │
│  │  │               │  │               │  │            ││ │
│  │  └───────────────┘  └───────────────┘  └────────────┘│ │
│  │                                                         │ │
│  │  Zones séparées physiquement                           │ │
│  │  -> Tolérance aux pannes (earthquake, power outage)    │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  DANS CHAQUE DATACENTER :                                   │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  Racks de serveurs                                     │ │
│  │  ┌────┐ ┌────┐ ┌────┐ ┌────┐                          │ │
│  │  │Rack│ │Rack│ │Rack│ │Rack│  ...                     │ │
│  │  │ 1  │ │ 2  │ │ 3  │ │ 4  │                          │ │
│  │  └────┘ └────┘ └────┘ └────┘                          │ │
│  │                                                         │ │
│  │  Dans chaque rack :                                     │ │
│  │  - 40-50 serveurs 1U/2U                                │ │
│  │  - Switch réseau (Top of Rack)                         │ │
│  │  - PDU (Power Distribution Unit)                       │ │
│  └────────────────────────────────────────────────────────┘ │
│                                                              │
│  INFRASTRUCTURE :                                            │
│  - Alimentation redondante (N+1, 2N)                        │
│  - Générateurs diesel de backup                             │
│  - UPS (batteries)                                           │
│  - Climatisation massive (PUE ~1.1-1.5)                    │
│  - Sécurité physique (gardes, biométrie)                   │
│  - Connectivité : 100+ Gbps vers internet                  │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === SCALING DANS LE CLOUD ===

┌──────────────────────────────────────────────────────────────┐
│                    SCALING STRATEGIES                        │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ VERTICAL SCALING (Scale Up)                                 │
│   Augmenter ressources d'une machine                        │
│                                                              │
│   Avant :  ┌────────┐                                       │
│            │ 2 vCPU │                                       │
│            │ 4 GB   │                                       │
│            └────────┘                                       │
│                                                              │
│   Après :  ┌────────┐                                       │
│            │ 8 vCPU │                                       │
│            │ 32 GB  │                                       │
│            └────────┘                                       │
│                                                              │
│   [OK] Simple (pas de changement code)                        │
│   [X] Limite physique                                         │
│   [X] Downtime pour upgrade                                   │
│   [X] Coûteux                                                 │
│                                                              │
│ HORIZONTAL SCALING (Scale Out)                              │
│   Ajouter plus de machines                                  │
│                                                              │
│   Avant :  ┌────────┐                                       │
│            │Server 1│                                       │
│            └────────┘                                       │
│                                                              │
│   Après :  ┌────────┐ ┌────────┐ ┌────────┐               │
│            │Server 1│ │Server 2│ │Server 3│               │
│            └────────┘ └────────┘ └────────┘               │
│                                                              │
│   [OK] Pas de limite théorique                                │
│   [OK] Tolérance aux pannes                                   │
│   [OK] Pas de downtime                                         │
│   [X] Complexité (load balancing, state)                     │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === AUTO-SCALING ===

# Ajuster automatiquement les ressources selon la charge

┌──────────────────────────────────────────────────────────────┐
│                    AUTO-SCALING                              │
│                                                              │
│  Métriques surveillées :                                     │
│  - CPU utilization                                           │
│  - Memory utilization                                        │
│  - Request count                                             │
│  - Response time                                             │
│  - Queue length                                              │
│                                                              │
│  Politiques :                                                │
│                                                              │
│  Target Tracking:                                            │
│    Si CPU > 70% -> Ajouter instance                          │
│    Si CPU < 30% -> Retirer instance                          │
│                                                              │
│  Schedule-based:                                             │
│    9h-17h (heures bureau) -> 10 instances                    │
│    17h-9h (nuit) -> 2 instances                              │
│                                                              │
│  Predictive:                                                 │
│    ML prédit charge future                                   │
│    Scale AVANT le pic                                        │
│                                                              │
│  Example timeline:                                           │
│                                                              │
│  Charge                                                      │
│  │        ╱╲                                                 │
│  │       ╱  ╲                                                │
│  │      ╱    ╲___                                            │
│  │_____╱          ╲___                                       │
│  └─────────────────────-> Temps                              │
│                                                              │
│  Instances                                                   │
│  │   ┌──┐┌──┐┌──┐                                          │
│  │   │  ││  ││  │                                          │
│  │┌──┤  ││  ││  │┌──┐                                      │
│  ││  │  ││  ││  ││  │                                      │
│  └─────────────────────-> Temps                              │
│    2   5   5   5   2  <- Nombre d'instances                 │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple : Auto-scaling avec AWS (boto3)

import boto3

# Client Auto Scaling
autoscaling = boto3.client('autoscaling', region_name='us-east-1')

# Créer un Auto Scaling Group
autoscaling.create_auto_scaling_group(
    AutoScalingGroupName='my-asg',
    LaunchTemplate={
        'LaunchTemplateId': 'lt-1234567890',
        'Version': '$Latest'
    },
    MinSize=2,          # Minimum 2 instances
    MaxSize=10,         # Maximum 10 instances
    DesiredCapacity=2,  # Commencer avec 2
    VPCZoneIdentifier='subnet-12345,subnet-67890',
    HealthCheckType='ELB',
    HealthCheckGracePeriod=300
)

# Politique de scaling basée sur CPU
autoscaling.put_scaling_policy(
    AutoScalingGroupName='my-asg',
    PolicyName='scale-on-cpu',
    PolicyType='TargetTrackingScaling',
    TargetTrackingConfiguration={
        'PredefinedMetricSpecification': {
            'PredefinedMetricType': 'ASGAverageCPUUtilization'
        },
        'TargetValue': 70.0  # Maintenir CPU à 70%
    }
)


# === SERVERLESS ARCHITECTURE ===

# Architecture où vous ne gérez aucun serveur

┌──────────────────────────────────────────────────────────────┐
│              SERVERLESS ARCHITECTURE                         │
│                                                              │
│  Requête HTTP                                                │
│       │                                                       │
│       v                                                       │
│  ┌──────────────┐                                            │
│  │ API Gateway  │  Routing, Auth, Rate limiting             │
│  └──────┬───────┘                                            │
│         │                                                     │
│    ┌────┼────┬────────┬────────┐                            │
│    v    v    v        v        v                            │
│  ┌────┐┌────┐┌────┐┌────┐┌────┐                            │
│  │λ1  ││λ2  ││λ3  ││λ4  ││λ5  │  Functions (AWS Lambda)    │
│  └────┘└────┘└────┘└────┘└────┘                            │
│    │    │    │     │     │                                   │
│    v    v    v     v     v                                   │
│  ┌──────────────────────────┐                                │
│  │     DynamoDB / S3        │  Storage                       │
│  └──────────────────────────┘                                │
│                                                              │
│  CARACTÉRISTIQUES :                                          │
│    [OK] Pas de serveurs à gérer                                │
│    [OK] Scaling automatique (0 -> ∞)                            │
│    [OK] Pay per execution (pas de coût si inactif)            │
│    [OK] High availability built-in                              │
│    [X] Cold start (latence première invocation)               │
│    [X] Timeout limité (15 min AWS Lambda)                     │
│    [X] Stateless (pas de mémoire entre invocations)          │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# Exemple : AWS Lambda function (Python)

import json
import boto3

# S3 client
s3 = boto3.client('s3')

def lambda_handler(event, context):
    """
    Fonction Lambda déclenchée par upload S3
    Génère une miniature d'image
    """
    # Récupérer info du fichier uploadé
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = event['Records'][0]['s3']['object']['key']
    
    print(f"Processing {key} from {bucket}")
    
    # Télécharger l'image
    download_path = f'/tmp/{key}'
    s3.download_file(bucket, key, download_path)
    
    # Générer miniature (avec PIL)
    from PIL import Image
    img = Image.open(download_path)
    img.thumbnail((200, 200))
    
    # Upload miniature
    thumbnail_path = f'/tmp/thumb_{key}'
    img.save(thumbnail_path)
    
    thumbnail_key = f'thumbnails/{key}'
    s3.upload_file(thumbnail_path, bucket, thumbnail_key)
    
    return {
        'statusCode': 200,
        'body': json.dumps(f'Thumbnail created: {thumbnail_key}')
    }

# Déploiement :
# 1. Zipper le code + dépendances
# 2. Upload vers Lambda
# 3. Configurer trigger (S3 upload event)
# 4. Done ! Scaling automatique, pas de serveur à gérer


# === EDGE COMPUTING ===

# Calculer près des utilisateurs (pas dans datacenter centralisé)

┌──────────────────────────────────────────────────────────────┐
│                   EDGE COMPUTING                             │
│                                                              │
│  CLOUD CENTRALISÉ (traditionnel)                            │
│    Users ───-> Long distance ───-> Datacenter                 │
│    (100-300 ms latence)                                      │
│                                                              │
│  EDGE COMPUTING                                              │
│    Users ───-> Edge Location ───-> Datacenter (si besoin)    │
│    (1-10 ms latence)                                         │
│                                                              │
│  ARCHITECTURE :                                              │
│                                                              │
│    ┌──────────┐  ┌──────────┐  ┌──────────┐               │
│    │ Users    │  │ Users    │  │ Users    │               │
│    │ (Paris)  │  │ (Tokyo)  │  │ (NYC)    │               │
│    └────┬─────┘  └────┬─────┘  └────┬─────┘               │
│         │             │              │                       │
│         v             v              v                       │
│    ┌────────┐    ┌────────┐    ┌────────┐                 │
│    │  Edge  │    │  Edge  │    │  Edge  │                 │
│    │Location│    │Location│    │Location│                 │
│    └────┬───┘    └────┬───┘    └────┬───┘                 │
│         │             │              │                       │
│         └─────────────┼──────────────┘                       │
│                       v                                       │
│                ┌─────────────┐                               │
│                │ Cloud Core  │                               │
│                │ (Virginia)  │                               │
│                └─────────────┘                               │
│                                                              │
│  USE CASES :                                                 │
│    - CDN (Content Delivery Network) - CloudFlare, Akamai   │
│    - Video streaming - Netflix, YouTube                     │
│    - Gaming - Google Stadia, Xbox Cloud                     │
│    - IoT processing                                          │
│    - Autonomous vehicles                                     │
│    - AR/VR                                                   │
│                                                              │
└──────────────────────────────────────────────────────────────┘


[OK] PARTIE 15 : TENDANCES FUTURES


# === COMPUTING IN-MEMORY ===

# Faire les calculs directement dans la mémoire (pas dans CPU)

┌──────────────────────────────────────────────────────────────┐
│              PROCESSING-IN-MEMORY (PIM)                      │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ TRADITIONNEL :                                               │
│  RAM -> Bus -> CPU -> Calcul -> Bus -> RAM                       │
│  Bottleneck : Bande passante mémoire                        │
│                                                              │
│ PIM :                                                        │
│  RAM avec logique de calcul intégrée                        │
│  Calcul DANS la mémoire                                      │
│                                                              │
│  ┌──────────────────────────────────────┐                   │
│  │         Mémoire + Calcul             │                   │
│  │  ┌────────┐  ┌────────┐  ┌────────┐ │                   │
│  │  │ Data + │  │ Data + │  │ Data + │ │                   │
│  │  │  ALU   │  │  ALU   │  │  ALU   │ │                   │
│  │  └────────┘  └────────┘  └────────┘ │                   │
│  └──────────────────────────────────────┘                   │
│                                                              │
│  AVANTAGES :                                                 │
│    [OK] Pas de bottleneck mémoire                              │
│    [OK] Bande passante massive                                 │
│    [OK] Consommation réduite                                   │
│                                                              │
│  TECHNOLOGIES :                                              │
│    - HBM-PIM (Samsung)                                       │
│    - ReRAM avec calcul                                       │
│    - Memristor arrays                                        │
│                                                              │
│  APPLICATIONS :                                              │
│    - Machine Learning                                        │
│    - Base de données                                         │
│    - Analytics big data                                      │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === DNA COMPUTING ===

# Utiliser l'ADN pour stocker et calculer

┌──────────────────────────────────────────────────────────────┐
│                   DNA COMPUTING                              │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ STOCKAGE ADN :                                               │
│   1 gramme d'ADN = 215 pétabytes                            │
│   Dure des millénaires                                       │
│   Mammouth laineux : ADN vieux de 1.2 million d'années !   │
│                                                              │
│ ENCODAGE :                                                   │
│   Binaire -> ADN                                             │
│   00 -> A (Adénine)                                          │
│   01 -> C (Cytosine)                                         │
│   10 -> G (Guanine)                                          │
│   11 -> T (Thymine)                                          │
│                                                              │
│   Exemple :                                                  │
│   "Hello" = 01001000 01100101 01101100 01101100 01101111   │
│           = CGACGC...                                       │
│                                                              │
│ CALCUL ADN :                                                 │
│   Utilise réactions biochimiques                            │
│   Massivement parallèle (milliards de molécules)           │
│   Résout problèmes NP (ex: Hamiltonian Path)               │
│                                                              │
│ DÉFIS :                                                      │
│   [X] Très lent (heures/jours)                               │
│   [X] Taux d'erreur                                           │
│   [X] Coût élevé lecture/écriture                            │
│   [X] Pas pratique pour usage général                         │
│                                                              │
│ STATUT : Recherche académique principalement                │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === OPTICAL COMPUTING ===

# Utiliser la lumière au lieu d'électricité

┌──────────────────────────────────────────────────────────────┐
│                 OPTICAL COMPUTING                            │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ PRINCIPES :                                                  │
│   Photons (lumière) au lieu d'électrons                     │
│   Interférence optique pour calculs                         │
│                                                              │
│ AVANTAGES :                                                  │
│   [OK] Vitesse de la lumière (300,000 km/s)                   │
│   [OK] Pas de chaleur                                          │
│   [OK] Bande passante massive                                  │
│   [OK] Parallélisme naturel                                    │
│                                                              │
│ TECHNOLOGIES :                                               │
│   - Photonic chips (Intel, IBM)                             │
│   - Optique intégrée sur silicium                           │
│   - Interconnects optiques                                   │
│                                                              │
│ STATUT ACTUEL :                                              │
│   - Interconnects optiques : Production (datacenters)       │
│   - Calcul optique : Recherche                              │
│   - Hybrid électro-optique : En développement               │
│                                                              │
│ APPLICATIONS :                                               │
│   - IA/ML (matrix multiplications)                          │
│   - Télécommunications                                       │
│   - Crypto                                                   │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === TENDANCES ARCHITECTURALES ===

┌──────────────────────────────────────────────────────────────┐
│            TENDANCES 2025-2035                               │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ 1. HÉTÉROGÉNÉITÉ ACCRUE                                     │
│    CPU + GPU + NPU + FPGA + Accélérateurs spécialisés      │
│    -> Chaque tâche sur le meilleur hardware                  │
│                                                              │
│ 2. EDGE + CLOUD HYBRIDE                                     │
│    Calculs distribués intelligemment                        │
│    -> Edge pour latence, Cloud pour puissance                │
│                                                              │
│ 3. NEUROMORPHIQUE MAINSTREAM                                 │
│    Puces neuromorphiques dans smartphones                    │
│    -> Inférence IA ultra-efficace                            │
│                                                              │
│ 4. QUANTIQUE PRATIQUE                                        │
│    Premiers algos quantiques utiles                         │
│    -> Chimie, crypto, optimisation                           │
│                                                              │
│ 5. MÉMOIRE NON-VOLATILE UNIVERSELLE                         │
│    Remplace RAM + SSD (PCM, ReRAM, MRAM)                   │
│    -> Démarrage instantané, pas de perte données             │
│                                                              │
│ 6. COMPUTING IN-MEMORY                                       │
│    Calculs dans la mémoire                                   │
│    -> Fin du bottleneck von Neumann                          │
│                                                              │
│ 7. CHIPLETS                                                  │
│    Assemblage de petits dies                                │
│    -> Flexibilité, rendement, hétérogénéité                  │
│                                                              │
│ 8. 3D STACKING                                               │
│    Puces empilées verticalement                             │
│    -> Bande passante massive, form factor réduit            │
│                                                              │
│ 9. CARBON NANOTUBE / GRAPHENE                               │
│    Remplacer le silicium                                     │
│    -> Plus rapide, moins de consommation                     │
│                                                              │
│ 10. SUSTAINABLE COMPUTING                                    │
│     Efficacité énergétique prioritaire                      │
│     -> Green datacenters, chips basse consommation           │
│                                                              │
└──────────────────────────────────────────────────────────────┘


# === LOI DE MOORE : EST-ELLE MORTE ? ===

┌──────────────────────────────────────────────────────────────┐
│                    LOI DE MOORE                              │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ ÉNONCÉ (1965) :                                             │
│   "Le nombre de transistors double tous les 2 ans"          │
│                                                              │
│ HISTORIQUE :                                                 │
│   1971 : Intel 4004 - 2,300 transistors (10 µm)            │
│   1985 : Intel 386 - 275,000 transistors (1.5 µm)          │
│   2000 : Pentium 4 - 42M transistors (180 nm)              │
│   2010 : Core i7 - 1.17B transistors (32 nm)               │
│   2020 : Apple M1 - 16B transistors (5 nm)                 │
│   2023 : Apple M3 - 25B transistors (3 nm)                 │
│                                                              │
│ LIMITES PHYSIQUES :                                          │
│   - Taille atome : ~0.1 nm                                  │
│   - Transistor actuel : ~3 nm (30 atomes!)                 │
│   - Effets quantiques (tunneling)                           │
│   - Chaleur dissipée                                         │
│   - Coût des fabs (usines) : $20+ milliards                │
│                                                              │
│ APRÈS MOORE :                                                │
│   [OK] 3D stacking                                             │
│   [OK] Architectures spécialisées                             │
│   [OK] Nouveaux matériaux                                      │
│   [OK] Quantique pour certains problèmes                       │
│                                                              │
│ CONCLUSION :                                                 │
│   La loi de Moore ralentit mais l'innovation continue !     │
│                                                              │
└──────────────────────────────────────────────────────────────┘


[OK] CONCLUSION GÉNÉRALE


# === RÉSUMÉ COMPLET ===

Ce guide exhaustif a couvert :

FONDAMENTAUX (Parties 1-5)
├─ CPU : Architecture, pipeline, registres, cache
├─ Mémoire : Hiérarchie, RAM, stack, heap
├─ Stockage : HDD, SSD, systèmes de fichiers
├─ Bus : Interconnexions, PCIe, USB, SATA
└─ I/O : Périphériques, DMA, interruptions

PERFORMANCE (Parties 6-9)
├─ Optimisation : Cache, vectorisation, SIMD
├─ Parallélisme : Multi-core, threading, GPU
├─ Architecture moderne : ARM, x86, hétérogène
└─ Sécurité : Rings, MMU, TPM, Spectre/Meltdown

SYSTÈMES DISTRIBUÉS (Parties 10-12)
├─ Cloud : IaaS, PaaS, SaaS, serverless
├─ Distributed systems : CAP, consensus, sharding
├─ IoT : Edge computing, protocoles, contraintes
└─ Quantique : Qubits, superposition, applications

FUTUR (Parties 13-15)
├─ Neuromorphique : Spiking networks, efficacité
├─ Cloud avancé : Auto-scaling, edge, datacenter
└─ Tendances : PIM, DNA, optique, post-Moore


# === RESSOURCES POUR ALLER PLUS LOIN ===

LIVRES :
[DOCS] Computer Architecture (Hennessy & Patterson)
[DOCS] Computer Systems: A Programmer's Perspective (Bryant & O'Hallaron)
[DOCS] Designing Data-Intensive Applications (Martin Kleppmann)
[DOCS] The Art of Multiprocessor Programming (Herlihy & Shavit)

COURS EN LIGNE :
[COURS] Nand2Tetris (coursera.org)
[COURS] MIT 6.004 (Computation Structures)
[COURS] Berkeley CS61C (Great Ideas in Computer Architecture)
[COURS] Stanford CS143 (Compilers)

PRATIQUE :
[CODE] Écrire un émulateur CPU simple
[CODE] Profiler et optimiser du code
[CODE] Contribuer à projets open-source (Linux kernel, QEMU)
[CODE] Expérimenter avec AWS/Azure/GCP

COMMUNAUTÉS :
[UTILISATEURS] Stack Overflow
[UTILISATEURS] Reddit : r/programming, r/compsci
[UTILISATEURS] HackerNews
[UTILISATEURS] Discord/Slack de développeurs


# === PHILOSOPHIE FINALE ===

┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  "Premature optimization is the root of all evil"           │
│                                          - Donald Knuth      │
│                                                              │
│  1. Écrivez du code LISIBLE et CORRECT d'abord              │
│  2. PROFILEZ pour identifier les bottlenecks                │
│  3. Optimisez SEULEMENT ce qui compte (20/80)              │
│  4. Mesurez l'impact de chaque optimisation                 │
│                                                              │
│  "Make it work, make it right, make it fast"                │
│                                          - Kent Beck         │
│                                                              │
└──────────────────────────────────────────────────────────────┘


Merci d'avoir suivi ce guide complet sur l'architecture des ordinateurs ! [RAPIDE]

Vous avez maintenant les connaissances fondamentales pour :
[OK] Comprendre comment fonctionne réellement votre code
[OK] Écrire du code performant et optimisé
[OK] Débugger des problèmes complexes
[OK] Faire des choix architecturaux éclairés
[OK] Suivre les évolutions technologiques

Bon coding ! [CODE]*
```