σμ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 AcademyHojas de rutaRutas
Ctrl K
AO
+1,2 k estudiantes
Iniciar sesiónUnirse ↗
Hojas de rutaRutas
AO
+1,2 k estudiantes
Iniciar sesión
  • 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 AcademyHojas de rutaRutas
Ctrl K
AO
+1,2 k estudiantes
Iniciar sesiónUnirse ↗
Hojas de rutaRutas
AO
+1,2 k estudiantes
Iniciar sesión
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Ruta de Cache locality›Módulo 3 · La máquina en conjunto›Tema 3.1·~50 minAvanzado

Precarga

Posición en la rutaMódulo 3 de 3 · Tema 1 de 7
3.1 Precarga
—Puntuación del lab— / 100XP total—Racha—

6 min de lectura3 ejemplos de código

  1. 01Pedir antes de necesitar
  2. 02Predecir la línea siguiente: los pasos
  3. 03Lo que vale un precargador
  4. 04Tres formas de leer los cierres de SPY
  5. 05Lo que va a construir

Un fallo solo cuesta 80 ns si el programa tiene que esperarlo. Un precargador pide una línea antes que el programa, de modo que la espera ha terminado cuando llega la lectura. Esta lección construye dos precargadores, los puntúa con cobertura y precisión, y muestra dónde funcionan, en bucles con paso regular, y dónde no pueden, en lecturas en orden impredecible.

01

Pedir antes de necesitar

Hasta ahora la caché cargaba una línea cuando una lectura fallaba. Una precarga la carga antes. Si la apuesta es buena, la lectura que llega después encuentra la línea ya en la caché y acierta. Todos los procesadores modernos tienen precargadores de hardware que vigilan las direcciones de las lecturas y adivinan lo siguiente. La apuesta más simple: quien leyó la línea L querrá luego la línea L + 1. Nuestra caché dada tiene un método fill que carga una línea sin contar acierto ni fallo, que es exactamente una precarga.

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. 1Precargar la línea siguiente no cuesta nada aquí: fill no cuenta como acierto ni como fallo.

Al leer 800 valores en orden, una caché simple falla una vez por línea, 100 veces. Con el precargador de línea siguiente falla una sola vez en total: tras la primerísima lectura, la línea que hace falta a continuación ya está siempre allí. El segundo caso muestra el límite. Si el programa salta 4096 bytes cada vez, la línea que sigue a la actual es inútil y el precargador no ahorra nada: siguen siendo 50 fallos de 50 lecturas.

02

Predecir la línea siguiente: los pasos

Los precargadores reales buscan un patrón en las líneas que lee un programa. El más común es un paso constante: el programa lee las líneas 0, 3, 6, 9, saltando tres líneas cada vez. Un detector de pasos recuerda la última línea y el último salto. Cuando el nuevo salto iguala al anterior, es un patrón y la línea siguiente es la actual más el salto. Hacen falta dos saltos iguales para estar seguro, así que nunca adivina en las dos primeras lecturas.

  1. 1
    Ignorar una repeticiónLeer otra vez la misma línea no dice nada sobre un paso.
  2. 2
    Calcular el saltoLa línea nueva menos la última línea.
  3. 3
    Comparar con el último saltoSaltos iguales significan un patrón: prediga la línea nueva más el salto.
  4. 4
    RecordarGuarde el nuevo salto y la nueva línea para la siguiente lectura.
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. 1Dos saltos iguales seguidos: es un paso, así que la línea siguiente es la actual más el salto.

La primera secuencia es un paso de tres líneas. El detector no dice nada en las dos primeras lecturas y luego predice 9, 12 y 15, siempre un paso por delante. En la segunda secuencia se ignoran las lecturas repetidas de la línea 5 y el paso de 1 solo se confirma en la última lectura. Un buen detector es cauto: una predicción errónea tiene un precio, como veremos a continuación.

03

Lo que vale un precargador

Dos números puntúan a un precargador. La cobertura dice cuánto del problema resolvió. La precisión dice cuánto de su trabajo fue útil. Para medirlos pasamos la traza por la caché, hacemos una lectura, preguntamos al precargador qué cargar después, recordamos qué líneas se precargaron y contamos cuándo una lectura acierta en una de ellas.

coverage = 1 − misses with ÷ misses without accuracy = useful ÷ issued(1)la cobertura trata de los fallos del programa, la precisión del trabajo del propio precargador
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)

En la lectura en orden el precargador elimina el 98,8 % de los fallos y el 99,6 % de sus precargas se usan. En la lectura mezclada no hace nada: sin un paso repetido casi nunca emite una precarga (solo una), y por tanto tampoco hace daño. Ese es el comportamiento deseado. Un precargador que adivinara todo el tiempo llenaría la caché de líneas que nadie lee.

Una predicción errónea tiene un precio

Una precarga inútil consume ancho de banda de memoria y puede expulsar de la caché una línea que el programa aún necesita. Un precargador solo merece la pena cuando su precisión es alta. Nuestra caché aquí es lo bastante grande para ocultar el daño; en una caché pequeña o un sistema de memoria ocupado, un precargador que se equivoca hace un programa más lento que sin precargador.

04

Tres formas de leer los cierres de SPY

El laboratorio lee 2000 cierres de tres formas: guardados uno tras otro y leídos en orden, guardados dentro de filas de cinco valores (un paso de 40 bytes), y guardados uno tras otro pero leídos por volumen de negociación creciente. Las dos primeras tienen un patrón regular; la tercera visita los días en un orden que parece aleatorio, porque el volumen de un día no dice nada del volumen del siguiente.

Qué dicen los datos realesprimeros 2000 cierres de SPY, caché de 32 KB de 8 vías, precargador de pasos
En orden: fallos250 → 3cobertura 99 %, precisión 100 %
En filas de 5: fallos1,250 → 3también se encuentra un paso de 40 bytes
Por volumen creciente: fallos250 → 250cobertura 0 %: no hay patrón que encontrar
Precargas en el orden de volumen1se queda callado cuando no puede predecir
Cobertura del precargador de pasos, en %
En orden98.8
En filas de 599.8
Por volumen0

La pista está en la pregunta que responde el precargador: ¿qué viene después? Si la respuesta está en el patrón de las direcciones, el hardware la halla gratis. Si el orden depende de los datos, como cuando se visitan filas ordenadas por volumen, nada puede adivinarlo. La solución por software es cambiar la disposición de los datos para que el acceso vuelva a ser regular, por ejemplo ordenando las filas una vez y luego leyéndolas en orden.

05

Lo que va a construir

El laboratorio construye los dos precargadores, la simulación que los puntúa y el estudio sobre las tres formas de leer los cierres de SPY.

  • Función · preguntaSe apoya en
  • baseline_misses(trace)¿Cuántos fallos sin precarga?Cache
  • next_line_misses(trace)¿Cuántos con un precargador de línea siguiente?Cache.fill
  • StridePrefetcher().observe(line)¿Qué línea viene después?La última línea y el último salto
  • run_with_prefetcher(trace, prefetcher)¿Qué pasó: fallos, precargas, útiles?Cache
  • quality(trace)¿Qué cobertura y precisión alcanza?baseline_missesrun_with_prefetcher
  • study(bars)¿Dónde ayuda el precargador en los cierres de SPY?qualitynext_line_misses

Ideas clave

  • La precarga oculta un fallo. Pide una línea antes de la lectura, así que la lectura la encuentra en la caché y acierta; el fallo se paga igual, pero antes.
  • Necesita un patrón. Un detector de pasos predice saltos constantes entre líneas; las lecturas en un orden que depende de los datos no le dan nada que encontrar.
  • Puntúelo con dos números. La cobertura es la parte de fallos eliminados; la precisión es la parte de precargas usadas. Una precisión baja significa ancho de banda y espacio de caché desperdiciados.
Comprobación rápida
Un bucle lee una de cada tres líneas de un arreglo (un paso de 3 líneas). ¿Qué hace un precargador de línea siguiente por él?
Elige una respuesta.

Siguiente tema: hasta ahora una dirección era una línea y solo importaba un acierto de caché. En TLB y páginas grandes toda dirección debe traducirse primero de una página virtual a una física, y una pequeña caché de traducciones, el TLB, también puede fallar, de una forma que depende del tamaño de página.

Lab: qué se califica

6 tareas · 100 pts
  • Sin precarga10 pts
  • Un precargador de línea siguiente15 pts
  • Un precargador de pasos20 pts
  • Simular un precargador25 pts
  • Cobertura y precisión15 pts
  • El estudio con la tabla de SPY15 pts
Explorador · lab-cl-7
▾ lab-cl-7
▾ data
…
bash · en el navegador
learner@quantcraft:~/lab-cl-7$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

Todo lo que hay en lab-cl-7 vuelve a los archivos iniciales y se limpia el terminal. Tu solución actual se perderá: no se puede deshacer.

Se restablecerá
  • main.py → código inicial
  • Historial del terminal y salida de pruebas
  • Cambios sin enviar
Se conservará
  • Mejor puntuación del lab
  • Tu XP y tu racha
  • Progreso de la lección y notas