La respuesta simple: las CPU son como fábricas, que tienen “máquinas” que realizan diferentes tareas forman una “línea de producción”. Hay un “ritmo” común, el reloj central, pero como hacen cosas diferentes, es posible que pueda enviar múltiples instrucciones en la línea que se manejarán en caminos separados a través de la fábrica al mismo tiempo.
La respuesta técnica: esto se llama paralelismo a nivel de instrucción. En el caso más simple, explota el hecho de que necesita realizar múltiples operaciones para ejecutar una sola instrucción, pero todas esas operaciones son manejadas por circuitos separados; esto da lugar a la tubería de instrucciones:
(imagen de wikipedia)
- ¿Qué es un sistema operativo, cuáles son los tipos de sistemas operativos?
- ¿Está preparada la realidad virtual?
- ¿Cómo se aplica el aprendizaje automático en la fabricación?
- ¿Cómo puedo actualizar el BIOS de una computadora? ¿Cuáles son algunas indicaciones de que el BIOS necesita una actualización?
- ¿Es seguro que mi dispositivo de almacenamiento externo se expulse después de apagar mi PC?
Por lo tanto, ha quintuplicado su rendimiento para el caso promedio: en lugar de una instrucción por 5 ciclos de reloj, ahora está generando el resultado de una instrucción completa cada 1 ciclo de reloj.
Entonces, a continuación, ¿qué pasa si tuviera múltiples instrucciones para buscar y decodificar circuitos? ¿También múltiples ALU, líneas de recuperación de memoria, etc.? Esto se llama CPU Superscalar. Puede combinar esto con la canalización e intentar que el número máximo de operaciones de un tipo se ejecute al mismo tiempo, al tiempo que se ejecutan todos los diferentes tipos de operaciones en un solo ciclo de reloj. Alternativamente, podría poner este paralelismo en manos del programador, que se denomina CPU de palabra de instrucción muy larga; esto le permite tener instrucciones únicas que realizan múltiples acciones.
Ahora ha pasado de ejecutar una instrucción por 5 ciclos de reloj a ejecutar varias instrucciones completas por 1 ciclo de reloj. En el mejor de los casos, la CPU se ilumina como un árbol de Navidad: cada unidad activa al mismo tiempo, todo el tiempo.
Pero en todos esos enfoques, hay un gran problema: ¿qué pasa si la siguiente instrucción depende de la respuesta de la primera? Por ejemplo, ¿qué sucede si necesita realizar algunas operaciones aritméticas para determinar de dónde vendrán los datos para la segunda instrucción, que es algo muy común? Ingrese la ejecución fuera de orden, donde la CPU intenta reorganizar su programa de una manera más eficiente sin cambiar su significado; si bien esta dependencia anterior es algo que no puede cambiar, puede usar su tiempo libre para trabajar en otras partes del programa que son independientes del primer cálculo.
Entonces, después de todo esto, prueba su CPU y descubre que el rendimiento no es tan bueno como se imaginaba. Todas sus tuberías están vacías, después de haber completado todo lo que pudieron hace mucho tiempo, esperando la decisión final de la memoria principal durante cientos de ciclos (70-80% de las lecturas de memoria se resolverán desde la memoria caché, que es mucho más rápido, pero aún así no instantáneo, especialmente si está en L2 o L3 (o ahora L4, implementado como eDRAM)). Desde el punto de vista de su circuito, la memoria principal es el correo postal, y podría estar esperando una respuesta simple de sí / no, a la que sabe que la respuesta probablemente será la misma que la última vez que preguntó (o en algún patrón específico que reconoces), sin embargo, estás sentado allí, sin hacer nada. Esto conduce a predictores de rama y ejecución especulativa, donde simplemente continúa ejecutando las rutas más probables o incluso las dos, y cuando llega la respuesta de la memoria principal, simplemente arroja el resultado que asumió la respuesta incorrecta y se queda con el otro. En realidad, tiene más que suficiente tiempo, por lo que realizar cálculos innecesarios es más eficiente que la alternativa.
Tenga en cuenta que todo lo anterior es invisible para el programador (al menos en las CPU modernas y en lenguajes de alto nivel). Para aumentar aún más el rendimiento de un chip, también puede hacer algo más: tener múltiples núcleos completos en un solo dado. Sin embargo, esto coloca la carga de explotar el paralelismo en el programador, y es una carga pesada. La gente ha estado tratando de crear un compilador que paraleliza automáticamente el código durante mucho tiempo y con un éxito variable, pero todavía no estamos en ninguno de los idiomas principales (pero nos estamos acercando bastante a algunos no convencionales).
Luego llegamos al Pentium MMX, que provocó la revolución más reciente con los procesadores SIMD (Single Instruction Multiple Data). MMX, SSE, AVX, 3D ¡Ahora! son todos coprocesadores de “vector corto” (en contraste con los procesadores de vector de supercomputadora anteriores, que procesaron miles de elementos en paralelo). Las GPU también son ejemplos de procesadores SIMD (Computación de propósito general en unidades de procesamiento de gráficos para el fenómeno relativamente reciente de usarlos como procesadores normales, en lugar de solo para gráficos 3D). La idea es tener muchas unidades lógicas aritméticas, para que pueda realizar operaciones en múltiples elementos de datos a la vez; esto no hace que el procesador sea mucho más complejo, porque todos comparten la misma lógica de control (no puede tener saltos condicionales) , pero acelera las proyecciones, las multiplicaciones escalares vectoriales y muchas otras tareas del álgebra lineal. Algunos compiladores de lenguaje modernos de alto nivel incluso cuentan con “auto-vectorización”, lo que significa que pueden encontrar código que procesa múltiples elementos de la misma manera y luego emiten instrucciones para el coprocesador de vectores, hasta hace poco, usando esas instrucciones requeridas desplegables para ensamblar dividir un programa entre la CPU y la GPU todavía no es automático (en la GPU, la parte “MD” de “SIMD” se lleva al extremo, lo que lo hace mucho más eficiente que cualquier CPU para algunas tareas específicas).