¿Cómo puede una CPU entregar más de una instrucción por ciclo?

La página de instrucciones por segundo de Wikipedia dice que un i7 3630QM ofrece ~110 000 MIPS a una frecuencia de 3,2 GHz; sería (110/3.2 instrucciones) / 4 núcleos = ~8.6 instrucciones por ciclo por núcleo? ¿Cómo puede un solo núcleo entregar más de una instrucción por ciclo?

Según tengo entendido, una tubería solo debería poder entregar un resultado por reloj.

Estos son mis pensamientos:

  • La frecuencia interna es en realidad superior a 3,2 GHz
  • Algunas partes de la CPU son asíncronas de una manera que un humano humilde como yo no puede entender.
  • Hay múltiples canalizaciones simultáneas por núcleo
  • Una canalización puede entregar más de un resultado por reloj, una instrucción puede omitir etapas de la canalización y hay varios captadores previos para mantenerse al día.
  • me falta algo
Ofrece 110 000 Dhrystone MIPS, por lo que DMIPS, no MIPS, es algo que veo directamente. ¿Quizás esto podría marcar la diferencia? Ver en.wikipedia.org/wiki/Dhrystone

Respuestas (5)

Primero, como señalan el comentario de Keelan y la respuesta de Turbo J , la medida fue 113,093 Dhrystone MIPS, no MIPS nativos .

La microarquitectura Ivy Bridge del i7 3630QM solo puede comprometer 4 µops fusionados por ciclo, aunque puede comenzar la ejecución de 6 µops por ciclo. (La cantidad de µops fusionados en un rastro de código es aproximadamente igual a la cantidad de instrucciones; algunas instrucciones complejas se decodifican en múltiples µops que no están fusionadas y algunos pares de instrucciones se pueden fusionar en una sola µop, por ejemplo, una comparación inmediata seguido de un salto condicional.)

Dos de sus especulaciones sobre cómo se pueden ejecutar varias instrucciones en un solo ciclo son bastante válidas y se han utilizado en procesadores reales. Su primera especulación, que se usa un reloj interno más rápido, se usó en las ALU de "bola de fuego" del Pentium 4 original. Estas ALU estaban sincronizadas al doble de la frecuencia del resto del núcleo, que ya era relativamente alta.

(Esto se logró mediante el uso de una ALU escalonada en la que la mitad inferior de una suma se realizó en un ciclo, lo que permitió que una operación dependiente utilizara la mitad inferior del resultado en el ciclo siguiente. Para operaciones como suma, xor o desplazamiento a la izquierda que solo necesitan la mitad inferior de los operandos para producir la mitad inferior completa del resultado, tal escalonamiento, también conocido como canalización de ancho, permite la latencia del resultado de un solo ciclo, así como el rendimiento de un solo ciclo).

HyperSPARC utilizó una técnica algo relacionada, ALU en cascada. El HyperSPARC introdujo los resultados de dos ALU en una tercera ALU. Esto permitió ejecutar dos operaciones independientes y una tercera dependiente en un solo ciclo.

Su especulación de que "hay múltiples canalizaciones simultáneas por núcleo" es la otra técnica que se ha utilizado. Este tipo de diseño se denomina superescalar y es, con mucho, el medio más común para aumentar el número de operaciones ejecutadas en un solo ciclo.

También hay algunas otras ventajas y desventajas de la ejecución de instrucciones que vale la pena mencionar. Algunas operaciones se pueden realizar de manera más eficiente fuera de las unidades de ejecución ordinarias. La técnica de eliminación de movimientos explota el uso del cambio de nombre de registros en procesadores fuera de orden para realizar operaciones de movimiento durante el cambio de nombre de registros; el movimiento simplemente copia el número de registro físico de una posición en la tabla de cambio de nombre (llamada tabla de alias de registro) a otra. Esto no solo aumenta efectivamente el ancho de ejecución, sino que también elimina una dependencia. Esta técnica se usó al principio con el x87 basado en pila, pero ahora se usa ampliamente en los procesadores x86 de alto rendimiento de Intel. (El uso de instrucciones destructivas de dos operandos en x86 hace que la eliminación de movimientos sea más útil de lo que sería en un RISC típico).

Una técnica similar a la eliminación de movimientos es el manejo de instrucciones de puesta a cero de registros durante el cambio de nombre. Al proporcionar un nombre de registro que proporcione el valor cero, una instrucción de limpieza de registros (como xor o restar con ambos operandos siendo el mismo registro) puede simplemente insertar ese nombre en la tabla de cambio de nombre (RAT).

Otra técnica utilizada por algunos procesadores x86 reduce el costo de las operaciones push y pop. Por lo general, una instrucción que usa el puntero de pila tendría que esperar un ciclo completo para que un impulso o una ventana emergente actualicen el valor del puntero de pila. Al reconocer que empujar y sacar solo agregan o restan un pequeño valor al puntero de la pila, se pueden calcular los resultados de múltiples sumas/subtacciones en paralelo. El retraso principal para la suma es la propagación del acarreo, pero con valores pequeños, los bits más significativos del valor base (en este caso, el puntero de la pila) solo tendrán como máximo un acarreo. Esto permite aplicar una optimización similar a la de un sumador de selección de acarreo a sumas múltiples de valores pequeños. Además, dado que el puntero de la pila generalmente solo se actualiza mediante constantes,

También es posible fusionar instrucciones en una sola operación más compleja. Si bien el proceso inverso de dividir las instrucciones en múltiples operaciones más simples es una técnica antigua, la combinación de instrucciones (lo que Intel denomina fusión macro-op) puede permitir que la implementación admita operaciones más complejas que las expuestas en el conjunto de instrucciones.

En el lado teórico, se han propuesto otras técnicas. Las constantes pequeñas distintas de cero podrían admitirse en la RAT y algunas operaciones simples que usan o producen de manera confiable valores tan pequeños podrían manejarse temprano. ("Physical Register Inlining", Mikko H. Lipasti et al., 2004, sugirió usar la RAT como un medio para reducir el recuento de registros, pero la idea podría extenderse para admitir la carga de operaciones simples e inmediatas pequeñas en números pequeños).

Para cachés de rastreo (que almacenan secuencias de instrucciones bajo suposiciones particulares de flujo de control), puede haber oportunidades para fusionar operaciones separadas por ramas y eliminar operaciones que producen resultados no utilizados en el rastreo. El almacenamiento en caché de las optimizaciones en un caché de seguimiento también puede fomentar la realización de optimizaciones, como la combinación de instrucciones, que podría no valer la pena si tuvieran que realizarse cada vez que se recupera el flujo de instrucciones.

La predicción de valores se puede utilizar para aumentar la cantidad de operaciones que se pueden ejecutar en paralelo mediante la eliminación de dependencias. Un predictor de valor basado en pasos es similar a la optimización pop/push de un motor de pila especializado mencionado anteriormente. Puede calcular múltiples adiciones principalmente en paralelo, eliminando la serialización. La idea general de la predicción de valores es que con un valor predicho, las operaciones dependientes pueden continuar sin demora. (La dirección de la rama y la predicción del objetivo son efectivamente solo una forma muy limitada de predicción de valor, que permite obtener las siguientes instrucciones que dependen del "valor" de la rama, tomada o no, y la siguiente dirección de instrucción, otro valor).

¡increíble! Gracias por la valiosa información. ¿Podría sugerirme un libro donde pueda leer todas estas técnicas arquitectónicas?
@workless Una vez que vaya más allá de los conceptos básicos de canalización y ejecución superescalar fuera de orden (que estaría cubierto por la mayoría de los libros de texto de arquitectura informática), las mejores fuentes de información son probablemente descripciones de microarquitecturas de procesador específicas (como el artículo sobre Haswell vinculado en la respuesta de gnasher729 ) y artículos académicos (ISCA y MICRO [conferencias] generalmente tienen buenos artículos; HPCA, PACT, ASPLOS, y quizás algunos otros también tienen buena reputación). Andy Glew (quizás el más famoso por su trabajo en el Pentium Pro)...
... estaba trabajando en un wiki de CompArch, que presentaría conceptos más avanzados, pero el progreso fue lento y aparentemente fue pirateado hace un tiempo y ahora solo da un mensaje de error ( semipublic.comp-arch.net/wiki ). Tiene la intención de restablecer el wiki (el texto original se ha conservado) usando un software wiki diferente (tuvo algunos problemas con el software que estaba usando y está tomando esto como una oportunidad para hacer mejoras), pero "será un tiempo".
Un buen ejemplo del éxito de la arquitectura superescalar fue HyperThreading de Intel: con todas esas optimizaciones, los ingenieros de Intel descubrieron que aproximadamente el 30 % de la ALU no se usaba la mayor parte del tiempo, porque la memoria no puede fluir lo suficientemente rápido o el tubería no se puede llenar de manera suficientemente eficiente. HyperThreading le permite obtener mucho trabajo gratis en el escenario ideal. Es mucho menos que tener un nuevo núcleo separado, pero también es mucho más barato (y también se puede combinar con varios núcleos).
@PaulA.Clayton: dos capturas de esa página están en Wayback. 20 de diciembre de 2013 y 14 de febrero de 2014 . No sé si esas capturas son anteriores a los problemas con la página. Desafortunadamente, cuando traté de visitar esas páginas en Wayback, recibí el mensaje "Qué lástima. La máquina que sirve este archivo está inactiva. Estamos trabajando en eso ". mensaje, así que no estoy seguro de lo que se puede ver en esas páginas .
@KevinFegan He publicado copias de algunos artículos y enlaces a algunas de las copias de Wayback en mi sitio de Google Sites . Esta no es de ninguna manera una reproducción completa de la wiki anterior, pero podría ser de interés para algunos.

Algo de magia oscura ocurre en el interior de los procesadores modernos, pero sus pensamientos definitivamente están en la línea correcta.

La clave para comprender la eficiencia de los procesadores modernos es darse cuenta de que son superescalares . De Wikipedia (énfasis mío):

Una arquitectura de CPU superescalar implementa una forma de paralelismo llamado paralelismo a nivel de instrucción dentro de un solo procesador. Por lo tanto, permite un rendimiento de la CPU más rápido de lo que sería posible a una velocidad de reloj dada.

Estos procesadores modernos tienen múltiples unidades de ejecución por núcleo, como habrás adivinado. Es interesante considerar Hyper-Threading , algunas partes de la canalización están duplicadas pero otras no.

También es interesante leer sobre la ejecución fuera de orden , pero no responde directamente a su pregunta. Sin embargo, reduce el número de ciclos de CPU "desperdiciados".

La eficiencia también se ve afectada por muchas otras cosas que pueden causar un bloqueo dentro del procesador, que incluyen (pero definitivamente no se limitan a):

  • No estar disponibles los resultados de instrucciones anteriores.
  • Caché falla.
  • La bifurcación del código, que invalidaría las instrucciones ya obtenidas (lea sobre la predicción de bifurcación aquí y aquí ).

Los compiladores modernos intentan ayudar con muchos de los elementos anteriores, luego el procesador se hace cargo. Para ver un buen ejemplo, consulte esta pregunta en otra parte de Stackexchange, que destaca una diferencia importante entre dos instrucciones que pueden hacer lo mismo (en algunas circunstancias). Sin embargo, uno puede ser "más rápido" que el otro en algunos procesadores debido a la unidad de ejecución en uso.

Para obtener una explicación legible por humanos de la canalización de CPU moderna, consulte Un viaje a través de la canalización de CPU . Para obtener una explicación un poco más técnica, consulte el artículo Microarchitecture de Agner Fog .

gracias por la explicación y los enlaces muy interesantes. Como nota, Cell se ve muy interesante, espero estudiar más sobre arquitecturas de CPU ^_^. "" El x86 usa una "supertubería" como se describe anteriormente. La familia Cell utiliza un enfoque "sinérgico" que involucra nueve mini-cpus. Es cierto que cada mini-cpu sigue una canalización en su mayoría en orden, las mini-cpus tienen múltiples canalizaciones superescalares paralelas en lugar de una sola canalización".""

¿Qué crees que sucedió? Todos los ingenieros de Intel, AMD e IBM leyeron que una canalización solo puede ofrecer un resultado por ciclo y dijeron "bueno, eso es todo, no pueden hacer que estos procesadores sean más rápidos". ¿O leyeron esto y dijeron: "¿No se puede entregar más de un resultado por ciclo? ¡Ya veremos!".

Para una buena introducción a la arquitectura Haswell, por ejemplo, puede seguir este enlace http://www.realworldtech.com/haswell-cpu/ o simplemente puede ir al sitio web de Intel y encontrará un poco de documentación allí.

Cada núcleo del procesador Haswell tiene una gran cantidad de unidades de ejecución, que pueden realizar operaciones independientes entre sí, por lo que se pueden realizar varias operaciones en paralelo. A continuación, el procesador Haswell tiene varias unidades de ejecución que manejan operaciones vectoriales de hasta 256 bits de tamaño. Una operación vectorial podría, por ejemplo, realizar cuatro operaciones de punto flotante de precisión doble u ocho operaciones de punto flotante de precisión simple en una operación vectorial. Y, por último, el procesador Haswell admite "multiplicación fusionada", lo que significa que calcular a por b más c es una sola operación.

El máximo teórico, dado que Haswell tiene dos unidades capaces de combinar sumas y multiplicaciones, es dos operaciones de suma y multiplicación fusionadas por ciclo, cada operación hace ocho multiplicaciones de precisión simple más sumas, o 32 operaciones de punto flotante de precisión simple.

El procesador 3630 no está en la última lista de precios de Intel, pero hay modelos como el 3740QM con cuatro núcleos. Entonces, en lugar de 32, puede obtener 128 operaciones de punto flotante por ciclo de reloj. Este es el máximo teórico. Lograr la mitad de eso en la vida real es un desafío, pero no imposible para las tareas adecuadas. Hay otros procesadores disponibles con hasta 15 núcleos (a precios que ni los más fanáticos de los videojuegos pagarán).

Así que tienes una combinación de varios multiplicadores:

  1. Múltiples núcleos por procesador.
  2. (Hyperthreading, no mencionado antes, le permite acercarse a los límites teóricos)
  3. La operación de suma y multiplicación fusionada realiza dos operaciones aritméticas que cuentan solo como una.
  4. Vectores de 256 bits que realizan 8 operaciones contando solo como uno.
  5. Dos unidades de ejecución de vectores capaces de manejar sumas fusionadas y multiplicadas.

8,6 operaciones por ciclo no es demasiado difícil de lograr. Incluso 8,6 operaciones por ciclo por núcleo no es demasiado difícil.

Me pregunto si sería práctico o ventajoso diseñar una CPU con algunos núcleos que ejecutaran x86 y algunos que ejecutaran un conjunto de instrucciones optimizado para un comportamiento superescalar. Sé que Intel y AMD hacen cosas bastante sorprendentes para sortear las limitaciones en el conjunto de instrucciones x86, pero en algunos casos creo que sería útil saber algunas cosas que el conjunto de instrucciones actual no puede expresar. Por ejemplo, distintas versiones de ADDinstrucciones basadas en si el desbordamiento no debe verse afectado o debe configurarse cuando se produce un desbordamiento (y dejarse configurado si no ocurre).
Me entristece que, en la actualidad, muchos idiomas no controlen el desbordamiento de manera predeterminada. Sé que Java está bastante atascado por los requisitos semánticos, pero en lenguajes como C# que incluyen operadores aritméticos tanto con captura como sin captura, la única buena razón que veo para no atrapar el desbordamiento es porque uno necesita un comportamiento envolvente. En la actualidad, la verificación de desbordamiento puede imponer una penalización de velocidad significativa, pero si se diseñara un lenguaje de máquina en torno a la idea de que la captura de desbordamiento no necesita ser precisa siempre que el código pueda garantizar que no se hayan producido desbordamientos antes de la operación...
...alcanza ciertos puntos críticos, debería ser posible reducir la sobrecarga de captura de desbordamiento a casi cero. Si el código realiza un cálculo y luego almacena un valor en una ubicación que se abandonará si el primer cálculo se desborda, no debería haber necesidad de retrasar el almacenamiento hasta que el procesador sepa si el primer cálculo tuvo éxito, pero el procesador actualmente no tiene forma. de saber eso. Si el código pudiera simplemente hacer todas las operaciones que se pueden realizar de manera segura, ya sea que se produzca un desbordamiento o no, y luego verificar si se produjeron desbordamientos incorrectos en cualquiera de ellos ...
... eso parecería que debería ayudar a reducir las dependencias de ejecución.

El punto de referencia de Drystone es de 1984, y la máquina VAX de 1 MIPS nominal correspondiente no es muy eficiente en términos modernos. Incluso un Cortex M3 ofrece 1,25 DMPIS / MHz.

De hecho, los procesadores de arquitectura Intel Core pueden ejecutar varias instrucciones en paralelo en un solo núcleo, porque hay varias unidades informáticas presentes.

Aprendí mucho de los excelentes y extensos artículos de Jon "Hannibal" Stokes de Ars Technica sobre el tema de la arquitectura de microprocesadores. Los artículos están un poco anticuados (parecen ser de alrededor de 2004), pero siguen siendo muy relevantes.

Algunos de los enlaces a la siguiente parte de un artículo están rotos, sin embargo, parece que puede arreglarlos usted mismo comparando cuidadosamente la URL de la primera parte y la URL rota de la página siguiente (por ejemplo, agregando m-algún lugar en la URL).

(sí, esta es una respuesta glorificada de solo enlace, lo siento; los artículos son demasiado buenos para no mencionarlos)