¿Por qué un procesador tiene 32 registros?

52

Siempre me he preguntado por qué los procesadores se detuvieron en 32 registros. Es, con mucho, la pieza más rápida de la máquina, ¿por qué no simplemente hacer procesadores más grandes con más registros? ¿No significaría eso menos ir a la RAM?

Matt Capone
fuente
2
Supongo que más allá de cierto punto todas sus variables locales se ajustan a los registros. Los datos reales con los que está trabajando probablemente sean demasiado grandes de todos modos
Niklas B.
14
Rendimientos decrecientes. Claramente, los registros son "más caros" (en varios sentidos) que la RAM o simplemente tendríamos 8 GB de registros.
David Richerby
55
Una de las razones por la que es tan rápido es porque no hay muchos de ellos.
stackErr
55
Hay una diferencia entre cuántos registros tiene la CPU en total y cuántos puede usar a la vez.
Thorbjørn Ravn Andersen
Las CPU y las GPU ocultan la latencia principalmente por cachés y subprocesos múltiples, respectivamente. Entonces, las CPU tienen pocos registros, mientras que las GPU tienen decenas de miles en registros. Consulte el documento de mi encuesta sobre el archivo de registro de GPU que analiza todas estas compensaciones y factores.
user984260

Respuestas:

82

Primero, no todas las arquitecturas de procesador se detuvieron en 32 registros. Casi todas las arquitecturas RISC que tienen 32 registros expuestos en el conjunto de instrucciones en realidad tienen 32 registros enteros y 32 registros de coma flotante más (es decir, 64). (El punto flotante "add" usa registros diferentes que los enteros "add".) La arquitectura SPARC tiene ventanas de registro. En SPARC solo puede acceder a 32 registros enteros a la vez, pero los registros actúan como una pila y puede empujar y abrir nuevos registros 16 a la vez. La arquitectura Itanium de HP / Intel tenía 128 registros enteros y 128 de coma flotante expuestos en el conjunto de instrucciones. Las GPU modernas de NVidia, AMD, Intel, ARM e Imagination Technologies, exponen un gran número de registros en sus archivos de registro. (Sé que esto es cierto para las arquitecturas NVidia e Intel, no estoy muy familiarizado con los conjuntos de instrucciones AMD, ARM e Imagination, pero creo que los archivos de registro también son grandes allí).

En segundo lugar, la mayoría de los microprocesadores modernos implementan el cambio de nombre de registros para eliminar la serialización innecesaria causada por la necesidad de reutilizar recursos, por lo que los archivos de registro físicos subyacentes pueden ser más grandes (96, 128 o 192 registros en algunas máquinas). Esto (y la programación dinámica) elimina algunos de los necesita que el compilador genere tantos nombres de registro únicos, al tiempo que proporciona un archivo de registro más grande al planificador.

Hay dos razones por las que puede ser difícil aumentar aún más el número de registros expuestos en el conjunto de instrucciones. Primero, debe poder especificar los identificadores de registro en cada instrucción. 32 registros requieren un especificador de registro de 5 bits, por lo que las instrucciones de 3 direcciones (comunes en las arquitecturas RISC) gastan 15 de los 32 bits de instrucción solo para especificar los registros. Si aumentara eso a 6 o 7 bits, tendría menos espacio para especificar códigos de operación y constantes. Las GPU e Itanium tienen instrucciones mucho más grandes. Las instrucciones más grandes tienen un costo: necesita usar más memoria de instrucciones, por lo que su comportamiento de caché de instrucciones es menos ideal.

nO(n)

Lógica Errante
fuente
1
Hubiera mencionado los 256 FPR de SPARC64 VIIIfx y los 32 GPR adicionales que no son de ventana, logrados al agregar una instrucción Set XAR que proporciona 13 bits cada uno para las siguientes una o dos instrucciones. Estaba dirigido a HPC, por lo que el recuento de registros es más comprensible. También habría tenido la tentación de exponer algunas de las compensaciones y técnicas asociadas con más registros; pero mostró la sabiduría para evitar una respuesta más agotadora (e incluso no exhaustiva).
Paul A. Clayton
2
Puede valer la pena agregar un poco al beneficio decreciente de más registros para el código de "propósito general", aunque no es fácil encontrar mediciones significativas. Creo que Mitch Alsup mencionó en comp.arch que extender x86 a 32 registros en lugar de 16 habría ganado aproximadamente un 3% en rendimiento en comparación con (ISTR) 10-15% para la extensión de registro de 8 a 16 que se eligió. Incluso para un ISA de tienda de carga, ir a 64 probablemente proporciona pocos beneficios (al menos para el código GP actual). (Por cierto, las GPU a menudo comparten registros a través de subprocesos: por ejemplo, un subproceso con 250 dejando en 16 total privado para otros subprocesos.)
Paul A. Clayton
Es interesante ver que la gestión del entorno (por lo tanto, la conversión alfa), a menudo asociada con lenguajes de alto nivel, en realidad se usa en el nivel de registro.
babou
@ PaulA.Clayton Siempre pensé que IA-64 es la arquitectura que tiene el mayor número de registros ISA
phuclv
@ LưuVĩnhPhúc El SPARC64 VIIIfx era específico de HPC. Para su información, el Am29k (introducido alrededor de 1987-8 ) tenía 64 GPR globales y 128 con ventana, que es más GPR que Itanium (que tiene 8 registros de sucursal y un registro de conteo de bucles cuya función estaría en GPR en algunas otras ISA).
Paul A. Clayton
16

Solo dos razones más para limitar el número de registros:

  • Se espera poca ganancia: la CPU como los modelos actuales Intel / AMD x64 tienen 32kByte y más de caché L1-D, y el acceso a la caché L1 generalmente toma solo un ciclo de reloj (en comparación con alrededor de cien ciclos de reloj para una sola RAM completa acceso). Por lo tanto, hay poco que ganar al tener más datos en los registros en comparación con tener datos en el caché L1
  • Costos computacionales adicionales: Tener más registros crea una sobrecarga que en realidad puede hacer que una computadora sea más lenta:
    • En entornos multitarea, un cambio de tarea generalmente tiene que guardar el contenido de todos los registros del proceso que se deja en la memoria, y tiene que cargar los del proceso a ingresar. Cuantos más registros tenga, más tardará esto.
    • De manera similar, en arquitecturas sin ventanas de registro, las llamadas a funciones en cascada usan el mismo conjunto de registros. Entonces, una función A que llama a una función B usa el mismo conjunto de registros que B en sí. Por lo tanto, B tiene que guardar el contenido de todos los registros que usa (que aún contienen los valores de A) y debe volver a escribirlos antes de regresar (en algunas convenciones de llamadas, es el trabajo de A guardar sus contenidos de registro antes de llamar a B, pero el los gastos generales son similares). Cuantos más registros tenga, más tiempo demorará este ahorro y, por lo tanto, más costosa será una llamada a la función.
Robert Buchholz
fuente
¿Cómo funciona para el caché L1 para que no tengamos el mismo problema que para los registros?
babou
44
En los procesadores de alto rendimiento, la latencia L1 Dcache suele ser de 3 o 4 ciclos (incluida la generación de direcciones), por ejemplo, el Haswell de Intel tiene una latencia de 4 ciclos (no tener una latencia de registro de dependencia de datos también es más fácil de ocultar en la tubería). Dcache también tiende a admitir menos accesos por ciclo (p. Ej., 2 lecturas, 1 escritura para Haswell) que un archivo de registro (p. Ej., 4 lecturas, 6 escrituras para Alpha 21264 que replicó el archivo, 2 archivos con 4 lecturas es más rápido que 1 con 8)
Paul A. Clayton
@ PaulA.Clayton: Si el caché L1 tiene una latencia de 3-4 ciclos, eso sugeriría que podría haber algún beneficio al tener, por ejemplo, unos pocos conjuntos de 64 palabras de memoria de ciclo único con su propio espacio de direcciones de 64 palabras, y instrucciones dedicadas de "carga / almacenamiento directo", especialmente si había una manera de empujar todos los valores distintos de cero seguidos de una palabra que decía qué palabras no eran cero, y luego una forma de recuperarlos (poner a cero los registros que no aparecieron) . Muchos métodos tienen entre 16 y 60 palabras de variables locales, por lo que sería útil reducir el tiempo de acceso para aquellos de 3-4 ciclos a uno.
supercat
@supercat Se han presentado varias ideas de caché de pila (y global / TLS [por ejemplo, mochila]) en documentos académicos, así como mecanismos como el búfer de firma ( PDF ) Uso real, no tanto (parece). Esto se está volviendo hablador (por lo que probablemente debería terminar o ir a otro lado)
Paul A. Clayton
4

Una gran cantidad de código tiene muchos accesos a la memoria (el 30% es una cifra típica). Fuera de eso, típicamente alrededor de 2/3 son accesos de lectura y 1/3 son accesos de escritura. Esto no se debe a quedarse sin registros tanto como a acceder a matrices, acceder a variables de miembros de objetos, etc.

Esto TIENE que hacerse en la memoria (o caché de datos) debido a cómo se hace C / C ++ (todo lo que puede obtener un puntero debe tener una dirección para poder ser almacenado en la memoria). Si el compilador puede adivinar que no va a escribir en las variables de forma involuntaria usando trucos indirectos de puntero, los colocará en registros, y esto funciona muy bien para las variables de función, pero no para las variables de acceso global (generalmente, todo lo que sale de malloc ()) porque es esencialmente imposible adivinar cómo cambiará el estado global.

Debido a esto, no es común que el compilador pueda hacer algo con más de 16 registros de uso general de todos modos. Es por eso que todos los arquitectos populares tienen tantos (ARM tiene 16).

Los MIPS y otros RISC tienden a tener 32 porque no es muy difícil tener tantos registros; el costo es lo suficientemente bajo, por lo que es un poco "¿por qué no?". Más de 32 es en su mayoría inútil y tiene la desventaja de hacer que el archivo de registro sea más largo para acceder (cada duplicación en el número de registros potencialmente agrega una capa adicional de multiplexores que agrega un poco más de retraso ...). También hace que las instrucciones sean un poco más largas en promedio, lo que significa que cuando ejecuta el tipo de programas que dependen del ancho de banda de la memoria de instrucciones, ¡sus registros adicionales en realidad lo están ralentizando!

Si su CPU está en orden y no registra el cambio de nombre e intenta realizar muchas operaciones por ciclo (más de 3), entonces, en teoría, necesita más registros a medida que aumenta su número de operaciones por ciclo. ¡Es por eso que Itanium tiene tantos registros! Pero en la práctica, aparte del código numérico de coma flotante o SIMD (en el que Itanium era realmente bueno), la mayoría del código tendrá muchas lecturas / escrituras y saltos de memoria que hacen imposible este sueño de más de 3 operaciones por ciclo. (especialmente en software orientado al servidor como bases de datos, compiladores, ejecución de lenguaje de alto nivel como javascript, emulación, etc.). Esto es lo que hundió a Itanium.

¡Todo se reduce a la diferencia entre cálculo y ejecución!

Hubert Lamontagne
fuente
2

¿Quién te dice que el procesador siempre tiene 32 registros? x86 tiene 8, ARM de 32 bits y x86_64 tiene 16, IA-64 tiene 128 y muchos otros números más. Puedes echar un vistazo aquí . Incluso MIPS, PPC o cualquier arquitectura que tenga 32 registros de propósito general en el conjunto de instrucciones, el número es mucho mayor que 32 ya que siempre hay registros de bandera (si los hay), registros de control ... sin incluir registros renombrados y registros de hardware

Todo tiene su precio. Cuanto mayor sea el número de registros, más trabajo tendrá al cambiar de tarea, más espacio necesitará en la codificación de instrucciones. Si tiene menos registros, no tiene que almacenar y restaurar mucho cuando llama y regresa de las funciones o cambia de tareas con la compensación de la falta de registros en algún código de cómputo extenso

Además, cuanto más grande sea el archivo de registro, más costoso y complejo será. SRAM es la RAM más rápida y costosa, por lo que solo se usa en la memoria caché de la CPU. Pero sigue siendo mucho más barato y ocupa menos área que un archivo de registro con la misma capacidad.

phuclv
fuente
2

Por ejemplo, un procesador Intel típico tiene "oficialmente" 16 registros enteros y 16 vectores. Pero en realidad, hay muchos más: el procesador utiliza "cambio de nombre de registro". Si tiene una instrucción reg3 = reg1 + reg2, tendría un problema si otra instrucción que usara reg3 aún no hubiera terminado; no podría ejecutar la nueva instrucción en caso de que sobrescriba reg3 antes de que haya sido leída por la instrucción anterior.

Por lo tanto, hay aproximadamente 160 registros reales . Entonces, la instrucción simple anterior se cambia a "regX = reg1 + reg2, y recuerde que regX contiene reg3". Sin cambiar el nombre de los registros, la ejecución fuera de orden estaría absolutamente muerta en el agua.

gnasher729
fuente
1

No soy ingeniero eléctrico, pero creo que otra posibilidad por la razón de limitar el número de registros es el enrutamiento. Hay un número limitado de unidades aritméticas, y deben poder tomar la entrada de cada registro y la salida a cada registro. Esto es especialmente cierto cuando tiene programas canalizados que pueden ejecutar muchas instrucciones por ciclo.

O(n2)

Se me ocurrió la idea de esta respuesta al ver algunas de las charlas de Ivan Godard sobre la CPU Mill. Parte de la innovación de la CPU Mill es que no se puede enviar a registros arbitrarios: todas las salidas se insertan en una pila de registros o "correa", lo que reduce los problemas de enrutamiento, porque siempre se sabe a dónde irá la salida. Tenga en cuenta que todavía tienen el problema de enrutamiento para obtener los registros de entrada a las unidades aritméticas.

Consulte The Mill CPU Architecture - the Belt (2 de 9) para ver el enunciado del problema y la solución de Mill.

Ensalada Realz
fuente
"Deben ser capaces de tomar la entrada de cada registro y la salida a cada registro". - Espero que esto se implemente típicamente con un bus, no tiene que haber una conexión separada a las ALU (s) para cada registro.
user253751
1
@immibis: si desea mover datos en 300 picosegundos, un autobús no lo hará. Y si desea mover muchos datos (por ejemplo, para realizar tres instrucciones con dos operandos y un resultado cada uno en el mismo ciclo), un bus no funcionará absolutamente.
gnasher729
0

En cuanto a MIPS ISA, Hennessy y Patterson, Computer Organization and Design 4th edition p. 176, responde a esta pregunta específica directamente:

Más pequeño es más rápido. El deseo de velocidad es la razón por la que MIPS tiene 32 registros en lugar de muchos más.

Olsonista
fuente