Annexe C — Estimer un temps de calcul

La notation O(n3)O(n^3) décrit comment le temps de calcul évolue avec la taille du problème, mais elle ne fournit pas directement un temps en secondes. Comment passer d'une complexité théorique à une estimation concrète du temps d'exécution ?

Cette annexe présente une méthode systématique en trois étapes, illustrée par un exemple concret.


Objectif

Étant donné :

  • un algorithme de complexité connue,
  • une taille de problème nn,

estimer le temps d'exécution sur un ordinateur réel.

Exemple : Résoudre un système linéaire de taille n=106n = 10^6 par factorisation LU.


Étape 1 : Compter les opérations

La première étape consiste à déterminer le nombre total d'opérations à effectuer.

La factorisation LU d'une matrice n×nn \times n nécessite environ :

2n33 opeˊrations flottantes\frac{2n^3}{3} \text{ opérations flottantes}

Pour n=106n = 10^6 :

2×(106)33=2×101836.7×1017 opeˊrations\frac{2 \times (10^6)^3}{3} = \frac{2 \times 10^{18}}{3} \approx 6.7 \times 10^{17} \text{ opérations}

Pour simplifier les calculs, on retient 6×10176 \times 10^{17} opérations.


Étape 2 : Estimer la vitesse du processeur

La deuxième étape consiste à estimer combien d'opérations le processeur peut effectuer par seconde.

Fréquence vs performance réelle

Un processeur moderne fonctionne à environ 3 GHz, soit 3 milliards de cycles par seconde. Cependant, la performance réelle dépend de nombreux facteurs :

FacteurImpact
Latence mémoireLes accès RAM prennent 100+ cycles
DépendancesLes instructions qui dépendent du résultat précédent bloquent le pipeline
Surcoût logicielPython, NumPy et les appels de fonctions ajoutent du temps

Hypothèse de travail

Pour du code scientifique standard (non optimisé à la main), une estimation réaliste est :

Performance effective109 ops/s par cœur\text{Performance effective} \approx 10^9 \text{ ops/s par cœur}
💡

Pourquoi 1 GHz et non 3 GHz ?

Cette valeur conservative tient compte des réalités pratiques. Un code optimisé avec des bibliothèques BLAS peut atteindre des performances 10 à 100 fois supérieures, mais pour une estimation « pire cas », 10910^9 ops/s est raisonnable.


Étape 3 : Calculer le temps

La formule fondamentale est simple :

Temps=Nombre d’opeˊrationsOpeˊrations par seconde\text{Temps} = \frac{\text{Nombre d'opérations}}{\text{Opérations par seconde}}

Pour notre exemple :

Temps=6×1017109=6×108 secondes\text{Temps} = \frac{6 \times 10^{17}}{10^9} = 6 \times 10^{8} \text{ secondes}

Conversion en unités usuelles

Le résultat en secondes n'est pas très parlant. Convertissons-le étape par étape :

ConversionCalculRésultat
Secondes → Minutes6×108÷606 \times 10^8 \div 6010710^7 minutes
Minutes → Heures107÷6010^7 \div 601.67×1051.67 \times 10^5 heures
Heures → Jours1.67×105÷241.67 \times 10^5 \div 24~6 944 jours
Jours → Années6944÷3656944 \div 365~19 ans

Conclusion : sur un seul cœur CPU, la factorisation LU d'une matrice 106×10610^6 \times 10^6 prendrait environ 19 ans.


Un raccourci utile

Pour éviter de refaire ces conversions à chaque fois, retenez cette approximation :

💡

Règle pratique

1 anπ×107 secondes3×107 s1 \text{ an} \approx \pi \times 10^7 \text{ secondes} \approx 3 \times 10^7 \text{ s}

(Valeur exacte : 365.25 × 24 × 3600 = 31 557 600 s)

Cette règle permet de convertir rapidement :

  • 10710^7 s ≈ 4 mois
  • 10810^8 s ≈ 3 ans
  • 10910^9 s ≈ 30 ans

Vérification : 6×1086 \times 10^8 s = 6 × 3 ans = 18 ans ✓


Accélération par parallélisation

Les 19 ans calculés supposent un seul cœur. Que se passe-t-il avec du matériel plus puissant ?

Avec 8 cœurs CPU

En théorie, 8 cœurs divisent le temps par 8 :

Temps8 cœurs=19 ans82.4 ans\text{Temps}_{8 \text{ cœurs}} = \frac{19 \text{ ans}}{8} \approx 2.4 \text{ ans}

En pratique, le gain est moindre à cause de :

  • Synchronisation : les cœurs doivent se coordonner
  • Contention mémoire : tous les cœurs accèdent à la même RAM
  • Loi d'Amdahl : certaines parties du code restent séquentielles

Estimation réaliste : 3-4 ans.

Avec un GPU

Les GPU modernes (NVIDIA A100, RTX 4090) possèdent des milliers de cœurs spécialisés dans le calcul matriciel. Les bibliothèques optimisées comme cuBLAS atteignent 101310^{13} à 101410^{14} ops/s.

Avec 101310^{13} ops/s :

Temps=6×10171013=6×104 s17 heures\text{Temps} = \frac{6 \times 10^{17}}{10^{13}} = 6 \times 10^{4} \text{ s} \approx 17 \text{ heures}

Avec 101410^{14} ops/s (GPU haut de gamme) :

Temps=6×10171014=6×103 s1.7 heures\text{Temps} = \frac{6 \times 10^{17}}{10^{14}} = 6 \times 10^{3} \text{ s} \approx 1.7 \text{ heures}

Limitations des GPU

Ces estimations sont théoriques. En pratique, plusieurs obstacles se posent :

LimitationExplication
Mémoire limitéeUn GPU dispose de 16-80 Go. Notre matrice 106×10610^6 \times 10^6 en double précision nécessite 8 To. Elle ne tient pas en mémoire GPU.
Transferts CPU ↔ GPUCopier les données vers le GPU prend du temps et peut devenir le goulot d'étranglement.
Algorithmes séquentielsTous les algorithmes ne se parallélisent pas efficacement sur GPU.

Pour une matrice de cette taille, il faudrait utiliser des techniques avancées : décomposition par blocs, calcul distribué sur plusieurs GPU, ou clusters de calcul.

Tableau récapitulatif

ConfigurationPerformanceTemps estimé
1 cœur CPU10910^9 ops/s~19 ans
8 cœurs CPU (théorique)8×1098 \times 10^9 ops/s~2.4 ans
8 cœurs CPU (réaliste)5×109\sim 5 \times 10^9 ops/s~3-4 ans
GPU standard101310^{13} ops/s~17 heures*
GPU haut de gamme101410^{14} ops/s~2 heures*

*Si la mémoire le permet — ce qui n'est pas le cas pour notre exemple.

💡

Observation

Le facteur d'accélération entre un cœur CPU et un GPU optimisé est de l'ordre de 10510^5. Cette différence explique pourquoi les GPU sont devenus incontournables en calcul scientifique et en apprentissage automatique.


Applications pratiques

Savoir estimer un temps de calcul permet de :

  1. Détecter les erreurs de raisonnement : « Mon algorithme O(n2)O(n^2) avec n=109n = 10^9 prendra 1 seconde » est impossible — cela représente 101810^{18} opérations, soit environ 30 ans.

  2. Choisir le bon algorithme : si un O(n3)O(n^3) prend 19 ans et qu'un O(nlogn)O(n \log n) prend 1 minute, le choix s'impose.

  3. Planifier les ressources : faut-il un GPU ? Un cluster ? Ou un simple laptop suffit-il ?

  4. Communiquer avec rigueur : « c'est faisable » doit reposer sur des chiffres, pas sur l'intuition.


Exercice

Énoncé : Vous devez multiplier deux matrices n×nn \times n avec n=104n = 10^4. La multiplication matricielle naïve a une complexité O(n3)O(n^3).

  1. Combien d'opérations cela représente-t-il ?
  2. Quel est le temps estimé sur 1 cœur à 10910^9 ops/s ?
  3. Ce calcul est-il réalisable en pratique ?
Solution
  1. Nombre d'opérations : (104)3=1012(10^4)^3 = 10^{12}

  2. Temps : 1012109=103\frac{10^{12}}{10^9} = 10^3 secondes ≈ 17 minutes

  3. Oui, ce calcul est tout à fait réalisable sur un ordinateur standard.

    Avec une bibliothèque optimisée (NumPy/BLAS), le temps réel serait de l'ordre de quelques secondes seulement.


Résumé

La méthode d'estimation en trois étapes :

ÉtapeActionExemple
1Compter les opérations2n33=6×1017\frac{2n^3}{3} = 6 \times 10^{17}
2Estimer la vitesse10910^9 ops/s (1 cœur)
3Diviser et convertir6×1086 \times 10^8 s ≈ 19 ans

Raccourci : 1 an3×1071 \text{ an} \approx 3 \times 10^7 secondes.

Cette compétence est fondamentale pour tout informaticien confronté à des questions de passage à l'échelle.