En el canal de Matt Godbolt hay unos cuantos vídeos interesantes, pero este dedicado a cómo las CPUs optimizan diversas tareas comunes me pareció especialmente llamativo por lo claro y didáctico. Código incluido.
En cinco ejemplos muestra con código en ensamblador cuáles son esas tareas de la CPU, algunas de las cuales se realizan sin «pedirlo expresamente» y sin que seamos muy conscientes de ellas – por decirlo de algún modo. Los ejemplos son para CPUs Intel pero en general son válidos para otras similares. Estas son esas cinco tareas:
- Encontrar patrones acerca de los datos de memoria a los que se accede. Esto permite ganar velocidad adelantando las lecturas de la caché (prefetching) tan pronto como se detecta un patrón repetitivo en la forma en que se accede a los datos.
- Convertir de CISC a RISC. Las operaciones complejas –propias de la arquitectura de procesadores CISC– se convierten a operaciones más simples (propias de la arquitectura RISC), una especie de micro operaciones que son más simples, rápidas y eficientes.
- Planificar la ejecución de código independiente. Si dos grupos de instrucciones son independientes (y a veces lo son, por ejemplo porque utilizan registros independientes y direcciones diferentes) la CPU puede comenzar a ejecutar el segundo grupo incluso antes de que el primero termine, ganando así tiempo en la ejecución total.
- Convertir a formato SSA. En el formato SSA la CPU convierte las instrucciones a una representación que emplea «registros imaginarios» (ojo: todo esto es una analogía) para comprobar si el código independiente de la técnica anterior es realmente independiente. Cuando se confirma que sí se pueden ejecutar los diversos grupos de instrucciones en paralelo, aumentando la eficiencia.
- Predecir el futuro. La CPU puede utilizar un predictor de saltos para «predecir» p «adivinar» en los saltos condicionales si se va a producir el salto o no, habiendo precalculado los resultados – marcándolos en cualquier caso como «especulativos», por si la predicción falla. En caso de acierto en la predicción, los cálculos ya estarían hechos; si se falla, simplemente se realizan normalmente, pero por lo general permite ahorrar tiempo.
Si esto te recuerda a cómo actúan Spectre y Meltdown, las famosas vulnerabilidades encontradas en los procesadores Intel, AMD y ARM a principios de año, es precisamente porque esos fallos tienen su origen en estas técnicas – o, más bien, en el hecho de que se pueden aprovechar estas técnicas para «extraer» cierta información de la memoria protegida del kernel y las cachés – debido a diversos problemas con el diseño original de los accesos a memoria de formas no contempladas originalmente.
Precisamente el propio Godbold grabó hace algún tiempo otro vídeo más largo, de casi una hora, explicando cómo actúan Meltdown y Spectre desde el punto de vista del código que se ejecuta y cómo funcionan las CPUs afectadas, que resultará interesante a quienes les gusten estos temas.