σμ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 3 · La machine au sens large›Sujet 3.1·~50 minAvancé

Préchargement

Position dans le parcoursModule 3 sur 3 · Sujet 1 sur 7
3.1 Préchargement
—Score du lab— / 100XP total—Série—

6 min de lecture3 exemples de code

  1. 01Demander avant d'en avoir besoin
  2. 02Prédire la ligne suivante : les pas
  3. 03Ce que vaut un préchargeur
  4. 04Trois façons de lire les clôtures de SPY
  5. 05Ce que vous allez construire

Un défaut ne coûte 80 ns que si le programme doit l'attendre. Un préchargeur demande une ligne avant le programme, de sorte que l'attente est terminée quand la lecture arrive. Ce cours construit deux préchargeurs, les note par couverture et précision, et montre où ils marchent, dans des boucles à pas régulier, et où ils ne peuvent rien, dans des lectures dans un ordre imprévisible.

01

Demander avant d'en avoir besoin

Jusqu'ici le cache chargeait une ligne quand une lecture échouait. Un préchargement la charge plus tôt. Si le pari est bon, la lecture qui vient plus tard trouve la ligne déjà dans le cache et réussit. Tous les processeurs modernes ont des préchargeurs matériels qui surveillent les adresses des lectures et devinent la suite. Le pari le plus simple : celui qui a lu la ligne L voudra ensuite la ligne L + 1. Notre cache fourni a une méthode fill qui charge une ligne sans compter ni succès ni défaut, ce qui est exactement un préchargement.

main.pyPython
def baseline_misses(trace):    cache = Cache()    for address in trace:        cache.access(address)    return cache.missesdef next_line_misses(trace):    cache = Cache()    for address in trace:        cache.access(address)        cache.fill((address // LINE_BYTES + 1) * LINE_BYTES)1    return cache.missestrace = [8 * i for i in range(800)]print("no prefetch:", baseline_misses(trace), "- next line:", next_line_misses(trace))jumps = [i * 4096 for i in range(50)]print("jumps of 4096 bytes:", baseline_misses(jumps), "- next line:", next_line_misses(jumps))
no prefetch: 100 - next line: 1
jumps of 4096 bytes: 50 - next line: 50
  1. 1Précharger la ligne suivante ne coûte rien ici : fill ne compte ni comme un succès ni comme un défaut.

En lisant 800 valeurs dans l'ordre, un cache simple échoue une fois par ligne, soit 100 fois. Avec le préchargeur de ligne suivante, il n'échoue qu'une fois au total : après la toute première lecture, la ligne nécessaire ensuite est toujours déjà là. Le second cas montre la limite. Si le programme saute de 4096 octets à chaque fois, la ligne qui suit la courante est inutile et le préchargeur n'économise rien : toujours 50 défauts sur 50 lectures.

02

Prédire la ligne suivante : les pas

Les vrais préchargeurs cherchent un motif dans les lignes qu'un programme lit. Le plus courant est un pas constant : le programme lit les lignes 0, 3, 6, 9, en sautant trois lignes à chaque fois. Un détecteur de pas retient la dernière ligne et le dernier écart. Quand le nouvel écart égale le précédent, c'est un motif et la ligne suivante est la courante plus l'écart. Il faut deux écarts égaux pour être sûr : il ne devine donc jamais aux deux premières lectures.

  1. 1
    Ignorer une répétitionRelire la même ligne ne dit rien sur un pas.
  2. 2
    Calculer l'écartLa nouvelle ligne moins la dernière ligne.
  3. 3
    Comparer avec le dernier écartDes écarts égaux signifient un motif : prédisez la nouvelle ligne plus l'écart.
  4. 4
    Se souvenirGardez le nouvel écart et la nouvelle ligne pour la lecture suivante.
main.pyPython
class StridePrefetcher:    def __init__(self):        self.last_line = None        self.last_delta = None    def observe(self, line):        if line == self.last_line:            return None        prediction = None        if self.last_line is not None:            delta = line - self.last_line            if delta == self.last_delta and line + delta >= 0:1                prediction = line + delta            self.last_delta = delta        self.last_line = line        return predictionp = StridePrefetcher()print([p.observe(line) for line in [0, 3, 6, 9, 12]])p = StridePrefetcher()print([p.observe(line) for line in [5, 5, 5, 6, 7]])
[None, None, 9, 12, 15]
[None, None, None, None, 8]
  1. 1Deux écarts égaux de suite : c'est un pas, donc la ligne suivante est la courante plus l'écart.

La première séquence est un pas de trois lignes. Le détecteur ne dit rien aux deux premières lectures, puis prédit 9, 12 et 15, toujours un pas devant. Dans la seconde séquence, les lectures répétées de la ligne 5 sont ignorées, et le pas de 1 n'est confirmé qu'à la dernière lecture. Un bon détecteur est prudent : une mauvaise prédiction a un prix, comme nous le verrons.

03

Ce que vaut un préchargeur

Deux nombres notent un préchargeur. La couverture dit quelle part du problème il a résolue. La précision dit quelle part de son travail était utile. Pour les mesurer, nous passons la trace dans le cache, faisons une lecture, demandons au préchargeur ce qu'il faut charger ensuite, retenons quelles lignes ont été préchargées et comptons quand une lecture réussit sur l'une d'elles.

coverage = 1 − misses with ÷ misses without accuracy = useful ÷ issued(1)la couverture concerne les défauts du programme, la précision le travail du préchargeur lui-même
main.pyPython
def run_with_prefetcher(trace, prefetcher):    cache = Cache()    marked = set()    prefetches = 0    useful = 0    for address in trace:        line = address // LINE_BYTES        if cache.access(address):            if line in marked:                useful += 1                marked.discard(line)        else:            marked.discard(line)        target = prefetcher.observe(line)        if target is not None and not cache.contains(target * LINE_BYTES):            cache.fill(target * LINE_BYTES)            prefetches += 1            marked.add(target)    return {"demand_misses": cache.misses, "prefetches": prefetches, "useful": useful}def quality(trace):    baseline = baseline_misses(trace)    run = run_with_prefetcher(trace, StridePrefetcher())    coverage = 1 - run["demand_misses"] / baseline    accuracy = run["useful"] / run["prefetches"] if run["prefetches"] else 0.0    return baseline, run, round(coverage, 3), round(accuracy, 3)import randomordered = [8 * i for i in range(2000)]shuffled = [8 * p for p in random.Random(1).sample(range(2000), 2000)]print("in order:", quality(ordered))print("shuffled:", quality(shuffled))
in order: (250, {'demand_misses': 3, 'prefetches': 248, 'useful': 247}, 0.988, 0.996)
shuffled: (250, {'demand_misses': 250, 'prefetches': 1, 'useful': 0}, 0.0, 0.0)

Sur la lecture dans l'ordre, le préchargeur supprime 98,8 % des défauts et 99,6 % de ses préchargements sont utilisés. Sur la lecture mélangée, il ne fait rien : sans pas répété il ne lance presque jamais de préchargement (un seul), et ne fait donc pas de mal non plus. C'est le comportement voulu. Un préchargeur qui devinerait tout le temps remplirait le cache de lignes que personne ne lit.

Une mauvaise prédiction a un prix

Un préchargement inutile consomme de la bande passante mémoire et peut chasser du cache une ligne dont le programme a encore besoin. Un préchargeur ne vaut la peine que si sa précision est élevée. Notre cache ici est assez grand pour cacher le dégât ; dans un petit cache ou un système mémoire chargé, un préchargeur qui se trompe ralentit un programme par rapport à l'absence de préchargeur.

04

Trois façons de lire les clôtures de SPY

Le labo lit 2 000 clôtures de trois façons : rangées les unes après les autres et lues dans l'ordre, rangées dans des lignes de cinq valeurs (un pas de 40 octets), et rangées les unes après les autres mais lues par volume d'échanges croissant. Les deux premières ont un motif régulier ; la troisième visite les jours dans un ordre qui paraît aléatoire, car le volume d'un jour ne dit rien du volume du suivant.

Ce que disent les vraies données2 000 premières clôtures de SPY, cache de 32 Ko à 8 voies, préchargeur de pas
Dans l'ordre : défauts250 → 3couverture 99 %, précision 100 %
Par lignes de 5 : défauts1,250 → 3un pas de 40 octets est aussi repéré
Par volume croissant : défauts250 → 250couverture 0 % : pas de motif à trouver
Préchargements dans l'ordre du volume1il reste silencieux quand il ne peut pas prédire
Couverture du préchargeur de pas, en %
Dans l'ordre98.8
Par lignes de 599.8
Par volume0

L'indice est dans la question à laquelle répond le préchargeur : que vient ensuite ? Si la réponse est dans le motif des adresses, le matériel la trouve gratuitement. Si l'ordre dépend des données, comme quand on visite des lignes triées par volume, rien ne peut le deviner. La correction côté logiciel consiste à changer la disposition des données pour que l'accès redevienne régulier, par exemple en triant les lignes une fois puis en les lisant dans l'ordre.

05

Ce que vous allez construire

Le labo construit les deux préchargeurs, la simulation qui les note et l'étude sur les trois façons de lire les clôtures de SPY.

  • Fonction · questionS'appuie sur
  • baseline_misses(trace)Combien de défauts sans préchargement ?Cache
  • next_line_misses(trace)Combien avec un préchargeur de ligne suivante ?Cache.fill
  • StridePrefetcher().observe(line)Quelle ligne vient ensuite ?La dernière ligne et le dernier écart
  • run_with_prefetcher(trace, prefetcher)Que s'est-il passé : défauts, préchargements, utiles ?Cache
  • quality(trace)Quelles couverture et précision atteint-il ?baseline_missesrun_with_prefetcher
  • study(bars)Où le préchargeur aide-t-il sur les clôtures de SPY ?qualitynext_line_misses

À retenir

  • Le préchargement masque un défaut. Il demande une ligne avant la lecture : la lecture la trouve dans le cache et réussit ; le défaut est toujours payé, mais plus tôt.
  • Il lui faut un motif. Un détecteur de pas prédit des écarts constants entre lignes ; des lectures dans un ordre dépendant des données ne lui donnent rien à trouver.
  • Notez-le avec deux nombres. La couverture est la part des défauts supprimés ; la précision est la part des préchargements utilisés. Une faible précision signifie bande passante et espace de cache gaspillés.
Vérification rapide
Une boucle lit une ligne sur trois d'un tableau (un pas de 3 lignes). Que fait un préchargeur de ligne suivante pour elle ?
Choisissez une réponse.

Sujet suivant : jusqu'ici une adresse était une ligne et seul comptait un succès de cache. Dans TLB et grandes pages, toute adresse doit d'abord être traduite d'une page virtuelle en page physique, et un petit cache de traductions, le TLB, peut aussi échouer, d'une manière qui dépend de la taille des pages.

Lab : ce qui est noté

6 tâches · 100 pts
  • Sans préchargement10 pts
  • Un préchargeur de ligne suivante15 pts
  • Un préchargeur de pas20 pts
  • Simuler un préchargeur25 pts
  • Couverture et précision15 pts
  • L'étude sur la table SPY15 pts
Explorateur · lab-cl-7
▾ lab-cl-7
▾ data
…
bash · dans le navigateur
learner@quantcraft:~/lab-cl-7$
Python pas encore chargéPythonLn 1, Col 1Spaces: 4UTF-8

Réinitialiser ce sujet ?

Tout le contenu de lab-cl-7 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