This article needs additional citations for verification. (January 2010) |
En electrónica , informática e ingeniería informática , la microarquitectura , también llamada organización informática y a veces abreviada como μarch o uarch , es la forma en que se implementa una arquitectura de conjunto de instrucciones (ISA) determinada en un procesador en particular . [1] Una ISA determinada puede implementarse con diferentes microarquitecturas; [2] [3] las implementaciones pueden variar debido a diferentes objetivos de un diseño determinado o debido a cambios en la tecnología. [4]
La arquitectura de la computadora es la combinación de la microarquitectura y la arquitectura del conjunto de instrucciones.
La ISA es aproximadamente igual al modelo de programación de un procesador tal como lo ve un programador de lenguaje ensamblador o un escritor de compiladores. La ISA incluye las instrucciones , el modelo de ejecución , los registros del procesador , las direcciones y los formatos de datos, entre otras cosas. La microarquitectura incluye las partes constituyentes del procesador y cómo estas se interconectan e interoperan para implementar la ISA.
La microarquitectura de una máquina suele representarse mediante diagramas (más o menos detallados) que describen las interconexiones de los diversos elementos microarquitectónicos de la máquina, que pueden ser desde puertas y registros individuales hasta unidades lógicas aritméticas (ALU) completas e incluso elementos más grandes. Estos diagramas generalmente separan la ruta de datos (donde se colocan los datos) y la ruta de control (que se puede decir que dirige los datos). [5]
La persona que diseña un sistema generalmente dibuja la microarquitectura específica como una especie de diagrama de flujo de datos . Al igual que un diagrama de bloques , el diagrama de microarquitectura muestra elementos de microarquitectura como la unidad aritmética y lógica y el archivo de registros como un solo símbolo esquemático. Por lo general, el diagrama conecta esos elementos con flechas, líneas gruesas y líneas delgadas para distinguir entre buses de tres estados (que requieren un búfer de tres estados para cada dispositivo que impulsa el bus), buses unidireccionales (siempre impulsados por una sola fuente, como la forma en que el bus de direcciones en computadoras más simples siempre es impulsado por el registro de direcciones de memoria ) y líneas de control individuales. Las computadoras muy simples tienen una única organización de bus de datos : tienen un solo bus de tres estados . El diagrama de computadoras más complejas generalmente muestra múltiples buses de tres estados, que ayudan a la máquina a realizar más operaciones simultáneamente.
Cada elemento de la microarquitectura está representado a su vez por un esquema que describe las interconexiones de las puertas lógicas utilizadas para implementarlo. Cada puerta lógica está representada a su vez por un diagrama de circuito que describe las conexiones de los transistores utilizados para implementarla en alguna familia lógica particular . Las máquinas con diferentes microarquitecturas pueden tener la misma arquitectura de conjunto de instrucciones y, por lo tanto, ser capaces de ejecutar los mismos programas. Las nuevas microarquitecturas y/o soluciones de circuitos, junto con los avances en la fabricación de semiconductores, son lo que permite que las nuevas generaciones de procesadores logren un mayor rendimiento mientras utilizan la misma ISA.
En principio, una única microarquitectura podría ejecutar varias ISA diferentes con sólo cambios menores en el microcódigo .
La ruta de datos segmentada es el diseño de ruta de datos más utilizado en la microarquitectura actual. Esta técnica se utiliza en la mayoría de los microprocesadores, microcontroladores y DSP modernos . La arquitectura segmentada permite que varias instrucciones se superpongan en la ejecución, de forma muy similar a una línea de montaje. La segmentación incluye varias etapas diferentes que son fundamentales en los diseños de microarquitectura. [5] Algunas de estas etapas incluyen la obtención de instrucciones, la decodificación de instrucciones, la ejecución y la reescritura. Algunas arquitecturas incluyen otras etapas, como el acceso a la memoria. El diseño de segmentaciones es una de las tareas centrales de la microarquitectura.
Las unidades de ejecución también son esenciales para la microarquitectura. Las unidades de ejecución incluyen unidades lógicas aritméticas (ALU), unidades de punto flotante (FPU), unidades de carga/almacenamiento, predicción de bifurcación y SIMD . Estas unidades realizan las operaciones o cálculos del procesador. La elección del número de unidades de ejecución, su latencia y rendimiento es una tarea central de diseño de microarquitectura. El tamaño, la latencia, el rendimiento y la conectividad de las memorias dentro del sistema también son decisiones de microarquitectura.
Las decisiones de diseño a nivel de sistema, como por ejemplo si se deben incluir o no periféricos , como controladores de memoria , pueden considerarse parte del proceso de diseño microarquitectónico. Esto incluye decisiones sobre el nivel de rendimiento y la conectividad de estos periféricos.
A diferencia del diseño arquitectónico, donde el objetivo principal es lograr un nivel de rendimiento específico, el diseño microarquitectónico presta más atención a otras limitaciones. Dado que las decisiones de diseño de microarquitectura afectan directamente lo que se incluye en un sistema, se debe prestar atención a cuestiones como el área/costo del chip, el consumo de energía, la complejidad lógica, la facilidad de conectividad, la capacidad de fabricación, la facilidad de depuración y la capacidad de prueba.
Para ejecutar programas, todas las CPU de uno o varios chips:
El ciclo de instrucciones se repite continuamente hasta que se apaga el dispositivo.
Históricamente, las primeras computadoras eran diseños multiciclo. Las computadoras más pequeñas y menos costosas aún usan esta técnica. Las arquitecturas multiciclo suelen usar la menor cantidad total de elementos lógicos y cantidades razonables de energía. Pueden diseñarse para tener tiempos deterministas y alta confiabilidad. En particular, no tienen una línea de procesamiento que se detenga al tomar ramificaciones condicionales o interrupciones. Sin embargo, otras microarquitecturas suelen ejecutar más instrucciones por unidad de tiempo, usando la misma familia lógica. Cuando se habla de "rendimiento mejorado", una mejora a menudo se relaciona con un diseño multiciclo.
En una computadora multiciclo, la computadora realiza los cuatro pasos en secuencia, a lo largo de varios ciclos de reloj. Algunos diseños pueden realizar la secuencia en dos ciclos de reloj completando etapas sucesivas en flancos de reloj alternos, posiblemente con operaciones más largas ocurriendo fuera del ciclo principal. Por ejemplo, la etapa uno en el flanco ascendente del primer ciclo, la etapa dos en el flanco descendente del primer ciclo, etc.
En la lógica de control, la combinación del contador de ciclos, el estado del ciclo (alto o bajo) y los bits del registro de decodificación de instrucciones determinan exactamente lo que cada parte de la computadora debería estar haciendo. Para diseñar la lógica de control, se puede crear una tabla de bits que describa las señales de control para cada parte de la computadora en cada ciclo de cada instrucción. Luego, esta tabla lógica se puede probar en una simulación de software ejecutando código de prueba. Si la tabla lógica se coloca en una memoria y se usa para ejecutar una computadora real, se llama microprograma . En algunos diseños de computadoras, la tabla lógica se optimiza en forma de lógica combinacional hecha de puertas lógicas, generalmente usando un programa de computadora que optimiza la lógica. Las primeras computadoras usaban un diseño lógico ad-hoc para el control hasta que Maurice Wilkes inventó este enfoque tabular y lo llamó microprogramación. [6]
Lo que complica esta serie de pasos aparentemente simples es el hecho de que la jerarquía de memoria, que incluye el almacenamiento en caché , la memoria principal y el almacenamiento no volátil como los discos duros (donde residen las instrucciones y los datos del programa), siempre ha sido más lenta que el propio procesador. El paso (2) a menudo introduce un retraso prolongado (en términos de CPU) mientras los datos llegan a través del bus de la computadora . Se ha dedicado una cantidad considerable de investigación a diseños que eviten estos retrasos tanto como sea posible. A lo largo de los años, un objetivo central fue ejecutar más instrucciones en paralelo, aumentando así la velocidad de ejecución efectiva de un programa. Estos esfuerzos introdujeron estructuras lógicas y de circuitos complicadas. Inicialmente, estas técnicas solo se podían implementar en mainframes o supercomputadoras costosas debido a la cantidad de circuitos necesarios para estas técnicas. A medida que avanzaba la fabricación de semiconductores, cada vez se podían implementar más de estas técnicas en un solo chip semiconductor. Consulte la ley de Moore .
Los conjuntos de instrucciones han cambiado a lo largo de los años, desde originalmente muy simples a veces muy complejos (en varios aspectos). En los últimos años, las arquitecturas de carga y almacenamiento , los tipos VLIW y EPIC han estado de moda. Las arquitecturas que se ocupan del paralelismo de datos incluyen SIMD y Vectores . Algunas etiquetas utilizadas para denotar clases de arquitecturas de CPU no son particularmente descriptivas, especialmente la etiqueta CISC; muchos diseños tempranos denotados retroactivamente " CISC " son de hecho significativamente más simples que los procesadores RISC modernos (en varios aspectos).
Sin embargo, la elección de la arquitectura del conjunto de instrucciones puede afectar en gran medida la complejidad de la implementación de dispositivos de alto rendimiento. La estrategia principal, utilizada para desarrollar los primeros procesadores RISC, fue simplificar las instrucciones a un mínimo de complejidad semántica individual combinada con una alta regularidad y simplicidad de codificación. Estas instrucciones uniformes se podían obtener, decodificar y ejecutar fácilmente de forma segmentada y una estrategia simple para reducir el número de niveles lógicos con el fin de alcanzar altas frecuencias de operación; las memorias caché de instrucciones compensaban la mayor frecuencia de operación y la densidad de código inherentemente baja , mientras que se utilizaban grandes conjuntos de registros para factorizar la mayor parte posible de los accesos a la memoria (lentos).
Una de las primeras técnicas, y la más poderosa, para mejorar el rendimiento es el uso de la segmentación de instrucciones . Los primeros diseños de procesadores llevaban a cabo todos los pasos anteriores para una instrucción antes de pasar a la siguiente. Grandes porciones de los circuitos se dejaban inactivas en cualquier paso; por ejemplo, los circuitos de decodificación de instrucciones quedaban inactivos durante la ejecución, y así sucesivamente.
La segmentación mejora el rendimiento al permitir que varias instrucciones avancen por el procesador al mismo tiempo. En el mismo ejemplo básico, el procesador comenzaría a decodificar (paso 1) una nueva instrucción mientras la última esperaba los resultados. Esto permitiría que hasta cuatro instrucciones estuvieran "en proceso" a la vez, lo que haría que el procesador pareciera cuatro veces más rápido. Aunque cualquier instrucción tarda el mismo tiempo en completarse (aún hay cuatro pasos), la CPU en su conjunto "retira" las instrucciones mucho más rápido.
RISC hace que los pipelines sean más pequeños y mucho más fáciles de construir al separar claramente cada etapa del proceso de instrucción y hacer que tomen la misma cantidad de tiempo: un ciclo. El procesador en su conjunto opera como una cadena de montaje , con instrucciones que entran por un lado y resultados que salen por el otro. Debido a la menor complejidad del pipeline RISC clásico , el núcleo pipeline y una caché de instrucciones se podían colocar en el mismo tamaño de chip que, de otro modo, encajaría solo en el núcleo en un diseño CISC. Esta fue la verdadera razón por la que RISC era más rápido. Los primeros diseños, como SPARC y MIPS, solían funcionar más de 10 veces más rápido que las soluciones CISC de Intel y Motorola a la misma velocidad de reloj y precio.
Las canalizaciones no se limitan de ninguna manera a los diseños RISC. En 1986, la implementación de VAX de gama alta ( VAX 8800 ) era un diseño con gran cantidad de canalizaciones, ligeramente anterior a los primeros diseños comerciales MIPS y SPARC. La mayoría de las CPU modernas (incluso las CPU integradas) ahora están canalizadas, y las CPU microcodificadas sin canalización solo se ven en los procesadores integrados con mayor área restringida. [ ejemplos necesarios ] Las grandes máquinas CISC, desde el VAX 8800 hasta los modernos Pentium 4 y Athlon, se implementan tanto con microcódigo como con canalizaciones. Las mejoras en la canalización y el almacenamiento en caché son los dos principales avances microarquitectónicos que han permitido que el rendimiento del procesador siga el ritmo de la tecnología de circuitos en la que se basan.
No pasó mucho tiempo hasta que las mejoras en la fabricación de chips permitieron colocar aún más circuitos en la matriz, y los diseñadores comenzaron a buscar formas de utilizarlos. Una de las más comunes fue agregar una cantidad cada vez mayor de memoria caché en la matriz. La memoria caché es una memoria muy rápida y costosa. Se puede acceder a ella en unos pocos ciclos en lugar de los muchos necesarios para "hablar" con la memoria principal. La CPU incluye un controlador de caché que automatiza la lectura y escritura desde la caché. Si los datos ya están en la caché, se accede a ellos desde allí, con un ahorro de tiempo considerable, mientras que si no lo están, el procesador se "bloquea" mientras el controlador de caché los lee.
Los diseños RISC comenzaron a agregar caché a mediados y fines de la década de 1980, a menudo solo 4 KB en total. Esta cantidad aumentó con el tiempo y las CPU típicas ahora tienen al menos 2 MB, mientras que las CPU más potentes vienen con 4 o 6 o 12 MB o incluso 32 MB o más, siendo la máxima de 768 MB en la línea EPYC Milan-X recientemente lanzada, organizada en múltiples niveles de una jerarquía de memoria . En términos generales, más caché significa más rendimiento, debido a la reducción del bloqueo.
Los cachés y los pipelines eran una combinación perfecta. Antes, no tenía mucho sentido construir un pipeline que pudiera funcionar más rápido que la latencia de acceso de la memoria externa al chip. El uso de memoria caché en el chip en su lugar significaba que un pipeline podía funcionar a la velocidad de la latencia de acceso a la caché, durante un período de tiempo mucho menor. Esto permitía que las frecuencias operativas de los procesadores aumentaran a un ritmo mucho más rápido que el de la memoria externa al chip.
Una barrera para lograr un mayor rendimiento mediante el paralelismo a nivel de instrucción proviene de los bloqueos y vaciados de la tubería debido a las bifurcaciones. Normalmente, no se sabe si se tomará una bifurcación condicional hasta que se encuentra en una etapa avanzada de la tubería, ya que las bifurcaciones condicionales dependen de los resultados que provienen de un registro. Desde el momento en que el decodificador de instrucciones del procesador descubre que ha encontrado una instrucción de bifurcación condicional hasta el momento en que se puede leer el valor del registro decisivo, la tubería debe detenerse durante varios ciclos o, si no es así y se toma la bifurcación, es necesario vaciarla. A medida que aumentan las velocidades de reloj, la profundidad de la tubería aumenta con ella y algunos procesadores modernos pueden tener 20 etapas o más. En promedio, una de cada cinco instrucciones ejecutadas es una bifurcación, por lo que, sin ninguna intervención, se trata de una gran cantidad de bloqueos.
Se utilizan técnicas como la predicción de bifurcaciones y la ejecución especulativa para reducir estas penalizaciones por bifurcaciones. La predicción de bifurcaciones es cuando el hardware hace conjeturas fundamentadas sobre si se tomará una bifurcación en particular. En realidad, se llamará a un lado u otro de la bifurcación con mucha más frecuencia que al otro. Los diseños modernos tienen sistemas de predicción estadística bastante complejos, que observan los resultados de bifurcaciones pasadas para predecir el futuro con mayor precisión. La conjetura permite que el hardware obtenga instrucciones con antelación sin esperar a que se lea el registro. La ejecución especulativa es una mejora adicional en la que el código a lo largo de la ruta predicha no solo se obtiene con antelación, sino que también se ejecuta antes de que se sepa si se debe tomar la bifurcación o no. Esto puede generar un mejor rendimiento cuando la conjetura es correcta, con el riesgo de una gran penalización cuando la conjetura es incorrecta porque es necesario deshacer las instrucciones.
Incluso con toda la complejidad adicional y las puertas necesarias para respaldar los conceptos descritos anteriormente, las mejoras en la fabricación de semiconductores pronto permitieron que se utilizaran aún más puertas lógicas.
En el esquema anterior, el procesador procesa partes de una sola instrucción a la vez. Los programas informáticos podrían ejecutarse más rápido si se procesaran varias instrucciones simultáneamente. Esto es lo que consiguen los procesadores superescalares , al replicar unidades funcionales como las ALU. La replicación de unidades funcionales solo fue posible cuando el área de la matriz de un procesador de un solo componente ya no superaba los límites de lo que se podía fabricar de forma fiable. A finales de la década de 1980, los diseños superescalares empezaron a entrar en el mercado.
En los diseños modernos es habitual encontrar dos unidades de carga, una de almacenamiento (muchas instrucciones no tienen resultados que almacenar), dos o más unidades matemáticas de números enteros, dos o más unidades de punto flotante y, a menudo, una unidad SIMD de algún tipo. La lógica de emisión de instrucciones aumenta en complejidad al leer una enorme lista de instrucciones de la memoria y entregárselas a las diferentes unidades de ejecución que están inactivas en ese momento. Luego, los resultados se recopilan y se reordenan al final.
La adición de cachés reduce la frecuencia o duración de los bloqueos debidos a la espera de que se obtengan datos de la jerarquía de memoria, pero no elimina estos bloqueos por completo. En los primeros diseños, un error de caché obligaba al controlador de caché a bloquear el procesador y esperar. Por supuesto, puede haber alguna otra instrucción en el programa cuyos datos estén disponibles en la caché en ese momento. La ejecución fuera de orden permite que esa instrucción preparada se procese mientras una instrucción más antigua espera en la caché y luego reordena los resultados para que parezca que todo sucedió en el orden programado. Esta técnica también se utiliza para evitar otros bloqueos de dependencia de operandos, como una instrucción que espera un resultado de una operación de punto flotante de latencia prolongada u otras operaciones de varios ciclos.
El cambio de nombre de registros se refiere a una técnica utilizada para evitar la ejecución serializada innecesaria de instrucciones de programa debido a la reutilización de los mismos registros por parte de esas instrucciones. Supongamos que tenemos dos grupos de instrucciones que utilizarán el mismo registro . Un conjunto de instrucciones se ejecuta primero para dejar el registro al otro conjunto, pero si el otro conjunto se asigna a un registro similar diferente, ambos conjuntos de instrucciones se pueden ejecutar en paralelo (o) en serie.
Los arquitectos de computadoras se han visto obstaculizados por el creciente desajuste entre las frecuencias de funcionamiento de la CPU y los tiempos de acceso a la memoria DRAM . Ninguna de las técnicas que explotaban el paralelismo a nivel de instrucción (ILP) dentro de un programa podía compensar los largos bloqueos que se producían cuando había que recuperar datos de la memoria principal. Además, el gran número de transistores y las altas frecuencias de funcionamiento necesarias para las técnicas de ILP más avanzadas exigían niveles de disipación de energía que ya no se podían enfriar de forma económica. Por estas razones, las generaciones más nuevas de computadoras han comenzado a explotar niveles más altos de paralelismo que existen fuera de un solo programa o hilo de programa .
Esta tendencia se conoce a veces como computación de rendimiento . Esta idea se originó en el mercado de mainframes, donde el procesamiento de transacciones en línea enfatizaba no solo la velocidad de ejecución de una transacción, sino también la capacidad de manejar cantidades masivas de transacciones. Con el gran aumento de aplicaciones basadas en transacciones, como el enrutamiento de redes y el servicio de sitios web, en la última década, la industria informática ha vuelto a enfatizar los problemas de capacidad y rendimiento.
Una técnica para lograr este paralelismo es mediante sistemas multiprocesamiento , sistemas informáticos con múltiples CPU. Los servidores multiprocesadores de pequeña escala (2-8), que en el pasado estaban reservados para los mainframes y supercomputadoras de gama alta , se han vuelto comunes en el mercado de las pequeñas empresas. En el caso de las grandes corporaciones, los multiprocesadores de gran escala (16-256) son comunes. Incluso los ordenadores personales con múltiples CPU han aparecido desde los años 1990.
Con las reducciones de tamaño de los transistores que se hicieron posibles gracias a los avances en la tecnología de semiconductores, han aparecido las CPU multinúcleo , en las que se implementan varias CPU en el mismo chip de silicio. Inicialmente se utilizaron en chips destinados a mercados integrados, en los que las CPU más simples y más pequeñas permitirían que varias instancias cupieran en una sola pieza de silicio. En 2005, la tecnología de semiconductores permitió que se fabricaran chips CMP de CPU duales de escritorio de alta gama en grandes cantidades. Algunos diseños, como el UltraSPARC T1 de Sun Microsystems, han vuelto a ser diseños más simples (escalares, en orden) para poder colocar más procesadores en una sola pieza de silicio.
Otra técnica que se ha vuelto más popular recientemente es el multithreading . En el multithreading, cuando el procesador tiene que obtener datos de una memoria lenta del sistema, en lugar de esperar a que lleguen los datos, el procesador cambia a otro programa o subproceso de programa que esté listo para ejecutarse. Aunque esto no acelera un programa o subproceso en particular, aumenta el rendimiento general del sistema al reducir el tiempo que la CPU está inactiva.
En términos conceptuales, el multihilo equivale a un cambio de contexto a nivel del sistema operativo. La diferencia es que una CPU multihilo puede realizar un cambio de subproceso en un ciclo de CPU en lugar de los cientos o miles de ciclos de CPU que normalmente requiere un cambio de contexto. Esto se logra replicando el hardware de estado (como el archivo de registro y el contador de programa ) para cada subproceso activo.
Otra mejora es el subprocesamiento simultáneo de múltiples hilos . Esta técnica permite que las CPU superescalares ejecuten instrucciones de diferentes programas o subprocesos simultáneamente en el mismo ciclo.
Comentarios sobre Arquitectura y organización de computadoras: La arquitectura de computadoras es un componente clave de la ingeniería informática y el ingeniero informático en ejercicio debe tener una comprensión práctica de este tema...