σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyFeuilles de routeParcours
Ctrl K
AO
+1,2 k apprenants
ConnexionRejoindre ↗
Feuilles de routeParcours
AO
+1,2 k apprenants
Connexion
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyFeuilles de routeParcours
Ctrl K
AO
+1,2 k apprenants
ConnexionRejoindre ↗
Feuilles de routeParcours
AO
+1,2 k apprenants
Connexion
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Parcours Cache locality›Module 1 · Les caches de zéro›Sujet 1.1·~40 minDébutant

La hiérarchie mémoire et les temps de latence

Position dans le parcoursModule 1 sur 3 · Sujet 1 sur 4
1.1 La hiérarchie mémoire et les temps de latence
—Score du lab— / 100XP total—Série—

6 min de lecture4 exemples de code

  1. 01Pourquoi la mémoire, et non l'arithmétique, fixe la vitesse
  2. 02Ce que coûte un accès
  3. 03Le temps d'accès moyen
  4. 04Qui répond, et qui coûte
  5. 05Lire une vraie table
  6. 06Ce que vous allez construire

Un processeur additionne deux nombres en une fraction de nanoseconde, mais aller chercher un nombre absent des caches peut prendre 80 ns. Ce cours transforme ces temps de latence en un seul chiffre, le coût moyen d'un accès mémoire, et montre quel niveau de mémoire dévore votre temps.

01

Pourquoi la mémoire, et non l'arithmétique, fixe la vitesse

Un programme de trading passe l'essentiel de sa vie à attendre des données : un prix, un ordre, une ligne de table. Le calcul sur ces données est presque gratuit, mais elles doivent d'abord voyager de la mémoire au processeur, et plus elles sont loin, plus c'est long. Pensez à un bureau, une étagère, l'étage d'une bibliothèque et un entrepôt à l'autre bout de la ville. Les quelques feuilles sur le bureau sont instantanées, l'étagère prend quelques secondes, la bibliothèque une minute et l'entrepôt un après-midi. Les ordinateurs copient les données les plus utilisées dans de petites mémoires rapides à côté du processeur, appelées caches, pour que la plupart des demandes soient servies sur le bureau.

DéfinitionLatence

Le temps entre la demande d'une valeur et sa réception, mesuré ici en nanosecondes (milliardièmes de seconde).

Un cœur de serveur typique a trois caches devant la mémoire principale. Nous les appelons L1, L2 et L3, et la mémoire principale RAM. Une demande servie par un cache est un succès ; une demande qui doit passer au niveau suivant est un défaut. Le tableau ci-dessous met les quatre latences côte à côte.

main.pyPython
LATENCY_NS = {"L1": 1.0, "L2": 4.0, "L3": 15.0, "RAM": 80.0}for level, ns in LATENCY_NS.items():    print(level, ns, "ns", ns / LATENCY_NS["L1"], "x L1")
L1 1.0 ns 1.0 x L1
L2 4.0 ns 4.0 x L1
L3 15.0 ns 15.0 x L1
RAM 80.0 ns 80.0 x L1

Chaque niveau est plusieurs fois plus lent que celui du dessus, et la RAM est 80 fois plus lente que L1. Toute cette compétence consiste à faire en sorte que la plupart des accès soient servis près du sommet.

02

Ce que coûte un accès

Un accès commence en L1. Si la valeur y est, l'accès coûte la latence de L1 et c'est fini. Sinon, le processeur interroge L2, puis L3, puis la RAM, qui a toujours la valeur. Chaque niveau interrogé coûte du temps, qu'il réussisse ou non : un accès trouvé en L3 a donc payé L1, L2 et L3.

  1. 1
    Interroger L1Payez 1 ns. Un succès termine l'accès.
  2. 2
    En cas de défaut, interroger L2Payez 4 ns de plus. Un succès termine l'accès.
  3. 3
    En cas de défaut, interroger L3Payez 15 ns de plus. Un succès termine l'accès.
  4. 4
    En cas de défaut, aller en RAMPayez 80 ns de plus. La RAM a toujours la valeur.
main.pyPython
LATENCY_NS = {"L1": 1.0, "L2": 4.0, "L3": 15.0, "RAM": 80.0}cost_found_in_l3 = LATENCY_NS["L1"] + LATENCY_NS["L2"] + LATENCY_NS["L3"]print(cost_found_in_l3, "ns")
20.0 ns

Un accès servi par L3 coûte 20 ns, pas 15 : les 1 ns et 4 ns dépensées pour les deux défauts précédents font partie de la note.

Les taux de succès sont locaux

Chaque taux de succès ne compte que les accès qui atteignent ce niveau. Un taux de succès L2 de 0,8 signifie 80 % des accès qui ont raté L1, pas 80 % de tous les accès. Confondre les deux est l'erreur la plus fréquente de ce sujet.

03

Le temps d'accès moyen

Aucun accès n'est typique, on demande donc la moyenne sur de nombreux accès. Pondérez le coût de chaque chemin par sa fréquence. Chaque accès paie la latence de L1 ; seule la part qui rate L1 paie L2 ; seule la part qui rate les deux paie L3 ; et ainsi de suite. Écrit en une expression, avec des parenthèses qui s'emboîtent comme les niveaux :

AMAT = t₁ + (1 − h₁) · (t₂ + (1 − h₂) · (t₃ + (1 − h₃) · t_RAM))(1)t₁, t₂, t₃ et t_RAM sont les latences ; h₁, h₂ et h₃ sont les taux de succès locaux de L1, L2 et L3

C'est le temps d'accès mémoire moyen. Lisez les parenthèses de l'intérieur vers l'extérieur : la plus intérieure est ce que coûte un défaut en L3, la suivante ajoute la visite de L3, et ainsi de suite jusqu'à la visite de L1 que tout accès paie.

main.pyPython
LATENCY_NS = {"L1": 1.0, "L2": 4.0, "L3": 15.0, "RAM": 80.0}h1, h2, h3 = 0.9, 0.8, 0.7t = LATENCY_NSamat = t["L1"] + (1 - h1) * (t["L2"] + (1 - h2) * (t["L3"] + (1 - h3) * t["RAM"]))1print(round(amat, 2), "ns")
2.18 ns
  1. 11 - h est la part des accès qui échouent, donc chaque parenthèse est multipliée par la part qui arrive jusque-là.

Avec 90 % des accès qui réussissent en L1, la moyenne reste de 2,18 ns, plus du double de la latence de L1. Les quelques accès qui vont en profondeur coûtent si cher qu'ils tirent la moyenne. C'est pourquoi un taux de succès qui paraît excellent peut cacher un programme lent.

Cycles ou nanosecondes ?

Les fabricants donnent la latence en cycles du processeur : 4 cycles à 4 GHz font 1 ns. Nous utilisons des nanosecondes pour comparer les niveaux d'un coup d'œil. Ces chiffres sont typiques, pas exacts : les vraies puces diffèrent d'un facteur deux dans un sens ou dans l'autre.

04

Qui répond, et qui coûte

Deux questions se ressemblent mais ont des réponses différentes. Quel niveau répond aux accès ? Et quel niveau prend le temps ? La première compte des accès, la seconde compte l'attente. Un niveau est atteint par une part des accès et chaque visite coûte sa latence : un niveau rarement atteint mais lent peut donc dominer l'attente.

main.pyPython
h1, h2, h3 = 0.9, 0.8, 0.7served = [h1, (1 - h1) * h2, (1 - h1) * (1 - h2) * h3, (1 - h1) * (1 - h2) * (1 - h3)]reach = [1.0, 1 - h1, (1 - h1) * (1 - h2), (1 - h1) * (1 - h2) * (1 - h3)]1cost = [r * ns for r, ns in zip(reach, [1.0, 4.0, 15.0, 80.0])]2print([round(x, 3) for x in served])print([round(c / sum(cost), 3) for c in cost])
[0.9, 0.08, 0.014, 0.006]
[0.459, 0.183, 0.138, 0.22]
  1. 1reach est la part des accès qui visitent chaque niveau : tous visitent L1.
  2. 2sum(cost) est le temps d'accès moyen : les mêmes 2,18 ns que précédemment.

La RAM ne répond qu'à 0,6 % des accès mais représente 22 % du temps d'attente, tandis que L1 répond à 90 % d'entre eux et prend 46 % du temps. C'est le fait clé derrière chaque optimisation de cette compétence : ne comptez pas les accès, comptez où va le temps.

05

Lire une vraie table

Quelle importance cela a-t-il pour une vraie table ? La table des barres quotidiennes de SPY du labo a 5 405 lignes et cinq colonnes (ouverture, plus haut, plus bas, clôture, volume), soit 27 025 valeurs. Lisez chaque valeur une fois dans trois conditions : caches chauds où presque tout réussit, caches tièdes, et caches froids où la moitié des accès échouent à chaque niveau.

Ce que disent les vraies donnéesBarres quotidiennes de SPY, 2005 à 2026
Valeurs dans la table27,0255 405 lignes × 5 colonnes
Froid contre chaud15.9×plus lent pour la même table
Accès moyen, caches chauds1.05nstaux de succès 0,99 · 0,95 · 0,90
Accès moyen, caches froids16.75nsla RAM fait 60 % de cette attente
Temps pour lire la table une fois, en microsecondes
Caches chauds28
Caches tièdes59
Caches froids453
06

Ce que vous allez construire

Le labo transforme ce cours en six petites fonctions, chacune construite sur les précédentes, et se termine par le chiffrage de la lecture de la vraie table SPY. Les voici avec la question à laquelle chacune répond.

  • Fonction · questionS'appuie sur
  • average_access_time(hit_rates)Combien coûte un accès en moyenne ?La table des latences
  • slowdown(hit_rates)Combien de fois plus lent que réussir toujours en L1 ?average_access_time
  • levels_served(hit_rates)Quel niveau répond aux accès ?Taux de succès locaux
  • time_shares(hit_rates)Quel niveau prend le temps ?average_access_time
  • scan_time_us(n_accesses, hit_rates)Combien de temps prennent n accès ?average_access_time
  • study(bars)Que coûte la lecture de toute la table SPY ?scan_time_ustime_shares

À retenir

  • Comptez où va le temps. La part des accès qu'un niveau sert et la part du temps qu'il coûte sont deux nombres différents, et un niveau rare mais lent peut dominer.
  • Les taux de succès sont locaux. Le taux de chaque niveau ne compte que les accès qui l'atteignent : la part qu'un niveau sert est le produit des défauts au-dessus et de son propre taux.
  • La moyenne est un emboîtement de parenthèses. AMAT = t₁ + défaut₁ × (t₂ + défaut₂ × (…)) est le nombre que chaque sujet suivant cherche à réduire.
Vérification rapide
Un taux de succès L1 de 0,95. Parmi les accès qui atteignent L2, la moitié réussit. Quelle part de tous les accès L2 sert-il ?
Choisissez une réponse.

Sujet suivant : ce cours a pris les taux de succès comme donnés. Dans Lignes de cache et localité spatiale, vous construisez le cache qui les produit et découvrez pourquoi lire une valeur voisine de celle qu'on vient de lire est presque gratuit.

Lab : ce qui est noté

6 tâches · 100 pts
  • Temps d'accès moyen20 pts
  • Ralentissement face à L110 pts
  • Qui répond aux accès15 pts
  • Qui prend le temps20 pts
  • Le temps de n accès15 pts
  • L'étude sur la table SPY20 pts
Explorateur · lab-cl-1
▾ lab-cl-1
▾ data
…
bash · dans le navigateur
learner@quantcraft:~/lab-cl-1$
Python pas encore chargéPythonLn 1, Col 1Spaces: 4UTF-8

Réinitialiser ce sujet ?

Tout le contenu de lab-cl-1 revient aux fichiers de départ et le terminal est vidé. Votre solution actuelle sera perdue : cette action est irréversible.

Sera réinitialisé
  • main.py → code de départ
  • Historique du terminal et sortie des tests
  • Modifications non soumises
Sera conservé
  • Meilleur score du lab
  • Votre XP et votre série
  • Progression du cours et notes