La unidad central de procesamiento
o unidad de procesamiento central (conocida por las siglas CPU,
del inglés: central
processing unit), es el hardware dentro de
una computadora u otros
dispositivos programables, que interpreta las instrucciones de un programa informático mediante la realización de las
operaciones básicas aritméticas, lógicas y de entrada/salida del sistema. El
término en sí mismo y su acrónimo han estado en uso en la industria de la
Informática por lo menos desde el principio de los años 1960.1 La forma,
el diseño de CPU y la implementación de las CPU ha cambiado drásticamente desde
los primeros ejemplos, pero su operación fundamental sigue siendo la misma.
Una computadora puede tener más de una
CPU; esto se llama multiprocesamiento. Todas las CPU modernas son microprocesadores, lo que
significa que contienen un solo circuito integrado (chip). Algunos circuitos integrados pueden
contener varias CPU en un solo chip; estos son denominados procesadores multinúcleo. Un circuito
integrado que contiene una CPU también puede contener los dispositivos
periféricos, y otros componentes de un sistema informático; a esto se llama un sistema en un chip (SoC).
Dos componentes típicos de una CPU son
la unidad aritmético lógica (ALU), que realiza
operaciones aritméticas y lógicas, y la unidad de control (CU), que
extrae instrucciones de la memoria, las decodifica y las ejecuta, llamando a la ALU cuando
sea necesario.
No todos los sistemas computacionales
se basan en una unidad central de procesamiento. Una matriz de procesador o procesador vectorial tiene múltiples elementos cómputo
paralelo, sin una unidad considerada el "centro". En el modelo de computación distribuido, se resuelven
problemas mediante un conjunto interconectado y distribuido de procesadores.
Historia
Ordenadores, como el ENIAC tenían que
ser físicamente recableados para realizar diferentes tareas, que causaron que
estas máquinas se llamarán "ordenadores de programas fijo". Dado que
el término "CPU" generalmente se define como un dispositivo para la
ejecución de software (programa
informático), los primeros dispositivos que con razón podríamos llamar CPU
vinieron con el advenimiento del ordenador con programa almacenado.
La idea de un ordenador con programa
almacenado ya estaba presente en el diseño de John Presper Eckert y en el ENIAC de John William Mauchly, pero se omitió inicialmente de modo
que pudiera ser terminado antes. El 30 de junio de 1945, antes de que se
construyera la ENIAC, el matemático John von Neumann distribuyó
el trabajo titulado First Draft of a Report on the EDVAC (Primer
Borrador de un Reporte sobre el EDVAC). Fue el esbozo de un ordenador de
programa almacenado que en agosto de 1949 fue finalmente terminado.2 EDVAC fue
diseñado para realizar un cierto número de instrucciones (u operaciones) de
varios tipos. Significativamente, los programas escritos para el EDVAC se
crearon para ser almacenados en la memoria de alta velocidad del ordenador y no especificado por el
cableado físico del ordenador. Esto superó una severa limitación del ENIAC, que
era el importante tiempo y esfuerzo requerido para volver a configurar el
equipo para realizar una nueva tarea. Con el diseño de von Neumann, el programa
o software, que corría EDVAC podría ser cambiado simplemente cambiando el
contenido de la memoria. Sin embargo, EDVAC no fue el primer ordenador de
programa almacenado; la Máquina Experimental de Pequeña
Escala de Mánchester, un pequeño prototipo de ordenador de programa
almacenado, corrió su primer programa el 21 de junio de 19483 y la Manchester Mark I corrió su
primer programa en la noche del 16 hasta el 17 junio de 1949.
Las primeras CPU fueron diseñadas a
medida como parte de un ordenador más grande, generalmente un ordenador único
en su especie. Sin embargo, este método de diseñar las CPU a medida, para una
aplicación particular, ha desaparecido en gran parte y se ha sustituido por el
desarrollo de clases de procesadores baratos y estandarizados adaptados para
uno o varios propósitos. Esta tendencia de estandarización comenzó generalmente
en la era de los transistores discretos,
computadoras centrales y microcomputadoras y fue acelerada rápidamente con la popularización del circuito integrado (IC), este ha permitido que sean diseñados y fabricados
CPU más complejas en espacios pequeños en la orden de nanómetros). Tanto la
miniaturización como la estandarización de las CPU han aumentado la presencia
de estos dispositivos digitales en la vida moderna mucho más allá de las
aplicaciones limitadas de máquinas de computación dedicadas. Los
microprocesadores modernos aparecen en todo, desde automóviles hasta teléfonos móviles o celulares y juguetes de niños.
Si bien von Neumann muchas veces
acreditado por el diseño de la computadora con programa almacenado debido a su
diseño del EDVAC, otros antes que él, como Konrad Zuse, habían sugerido y aplicado ideas similares. La
denominada arquitectura Harvard del Harvard Mark I, que se completó antes de EDVAC, también utilizó un
diseño de programa almacenado usando cinta de papel perforada en vez de
memoria electrónica. La diferencia clave entre las arquitecturas de von Neumann
y la de Harvard es que la última separa el almacenamiento y tratamiento de
instrucciones de la CPU y los datos, mientras que el primero utiliza el mismo
espacio de memoria para ambos. La mayoría de los CPU modernos son de diseño von
Neumann, pero los CPU con arquitectura Harvard se ven así, sobre todo en
aplicaciones embebidas; por ejemplo, los microcontroladores Atmel AVR son
procesadores de arquitectura Harvard.
Los relés
eléctricos y los tubos de vacío (válvulas termoiónicas) eran usados comúnmente como
elementos de conmutación; un ordenador útil requiere miles o decenas de miles
de dispositivos de conmutación. La velocidad global de un sistema depende de la
velocidad de los conmutadores. Los ordenadores de tubo, como el EDVAC,
tendieron en tener un promedio de ocho horas entre fallos, mientras que los
ordenadores de relés, (anteriores y más lentos), como el Harvard Mark I, fallaban
muy raramente.1 Al final,
los CPU basados en tubo llegaron a ser dominantes porque las significativas
ventajas de velocidad producidas generalmente pesaban más que los problemas de
confiabilidad. La mayor parte de estas tempranas CPU síncronas corrían en frecuencias de reloj bajas comparadas con los modernos
diseños microelectrónicos. Eran muy comunes en este tiempo las frecuencias de
la señal del reloj con un rango desde 100 kHz hasta 4 MHz, limitado
en gran parte por la velocidad de los dispositivos de conmutación con los que
fueron construidos.
CPU de transistores y de circuitos
integrados discretos
La complejidad del diseño de las CPU
aumentó junto con facilidad de la construcción de dispositivos electrónicos más
pequeños y confiables. La primera de esas mejoras vino con el advenimiento del transistor. Las CPU
transistorizadas durante los años 1950 y los años 1960 no tuvieron que ser
construidos con elementos de conmutación abultados, no fiables y frágiles, como
los tubos de vacío y los relés eléctricos. Con esta mejora, fueron construidas
CPU más complejas y más confiables sobre una o varias tarjetas de circuito
impreso que contenían componentes discretos (individuales).
Durante este período, ganó popularidad
un método de fabricar muchos transistores en un espacio compacto. El circuito integrado (IC) permitió que una gran cantidad de transistores
fueran fabricados en una simple oblea basada en semiconductor o "chip". Al principio, solamente circuitos
digitales muy básicos, no especializados, como las puertas NOR fueron
miniaturizados en IC. Las CPU basadas en estos IC de "bloques de
construcción" generalmente son referidos como dispositivos de pequeña
escala de integración "small-scale integration" (SSI). Los
circuitos integrados SSI, como los usados en el computador guía del Apollo (Apollo Guidance Computer), usualmente
contenían transistores que se contaban en números de múltiplos de diez.
Construir un CPU completo usando IC SSI requería miles de chips individuales,
pero todavía consumía mucho menos espacio y energía que diseños anteriores de
transistores discretos. A medida que la tecnología microelectrónica avanzó, en
los IC fue colocado un número creciente de transistores, disminuyendo así la
cantidad de IC individuales necesarios para una CPU completa. Los circuitos
integrados MSI y el LSI (de mediana y gran escala de integración)
aumentaron el número de transistores a cientos y luego a miles.
En 1964, IBM introdujo
su arquitectura de ordenador System/360, que fue
usada en una serie de ordenadores que podían ejecutar los mismos programas con
velocidades y desempeños diferentes. Esto fue significativo en un tiempo en que
la mayoría de los ordenadores electrónicos eran incompatibles entre sí, incluso
las hechas por el mismo fabricante. Para facilitar esta mejora, IBM utilizó el
concepto de microprograma, a menudo
llamado «microcódigo»,
ampliamente usado aún en las CPU modernas.4 La
arquitectura System/360 era tan popular que dominó el mercado del mainframe durante
las siguientes décadas y dejó una herencia que todavía aún perdura en los
ordenadores modernos, como el IBM zSeries. En el mismo año de 1964, Digital Equipment Corporation (DEC)
introdujo otro ordenador que sería muy influyente, dirigido a los mercados
científicos y de investigación, el PDP-8. DEC
introduciría más adelante la muy popular línea del PDP-11, que
originalmente fue construido con IC SSI pero eventualmente fue implementado con
componentes LSI cuando se convirtieron en prácticos. En fuerte contraste con
sus precursores hechos con tecnología SSI y MSI, la primera implementación LSI
del PDP-11 contenía una CPU integrada únicamente por cuatro circuitos
integrados LSI.5
Los ordenadores basados en
transistores tenían varias ventajas frente a sus predecesores. Aparte de
facilitar una creciente fiabilidad y un menor consumo de energía, los
transistores también permitían que CPU operara a velocidades mucho más altas
debido al corto tiempo de conmutación de un transistor en comparación a un tubo
o relé. Gracias tanto a esta creciente fiabilidad como al dramático incremento
de velocidad de los elementos de conmutación que por este tiempo eran casi
exclusivamente transistores, se fueron alcanzando frecuencias de reloj de la
CPU de decenas de megahertz. Además, mientras que las CPU de transistores
discretos y circuitos integrados se usaban comúnmente, comenzaron a aparecer
los nuevos diseños de alto rendimiento como procesadores vectoriales SIMD (single
instruction multiple data – instrucción única, datos múltiples). Estos
primeros diseños experimentales dieron lugar más adelante a la era de los superordenadores
especializados, como los hechos por Cray Inc.
Microprocesadores
En la década de 1970 los inventos
fundamentales de Federico Faggin (ICs
Silicon Gate MOS con puertas autoalineadas junto con su nueva
metodología de diseño de lógica aleatoria) cambió el diseño e implementación de
las CPU para siempre. Desde la introducción del primer microprocesador
comercialmente disponible, el Intel 4004, en 1970 y
del primer microprocesador ampliamente usado, el Intel
8080, en 1974, esta clase de CPU ha desplazado casi
totalmente el resto de los métodos de implementación de la Unidad Central de
procesamiento. Los fabricantes de mainframes y miniordenadores de ese tiempo
lanzaron programas de desarrollo de IC propietarios para actualizar sus arquitecturas de computadoras más viejas
y eventualmente producir microprocesadores con conjuntos de instrucciones que eran
retrocompatibles con sus hardwares y softwares más viejos. Combinado con el
advenimiento y el eventual vasto éxito de la ahora ubicua computadora
personal, el término "CPU" es aplicado ahora casi
exclusivamentenota 1 a los
microprocesadores.
Las generaciones previas de CPU fueron
implementadas como componentes discretos y numerosos circuitos integrados de
pequeña escala de integración en una o más tarjetas de circuitos. Por otro
lado, los microprocesadores son CPU fabricados con un número muy pequeño de IC;
usualmente solo uno. El tamaño más pequeño del CPU, como resultado de estar
implementado en una simple pastilla, significa tiempos de conmutación más
rápidos debido a factores físicos como el decrecimiento de la capacitancia parásita
de las puertas. Esto ha
permitido que los microprocesadores síncronos tengan tiempos de reloj con un
rango de decenas de megahercios a varios gigahercios. Adicionalmente, como ha
aumentado la capacidad de construir transistores excesivamente pequeños en un
IC, la complejidad y el número de transistores en un simple CPU también se ha
incrementado dramáticamente. Esta tendencia ampliamente observada es descrita
por la ley de Moore, que ha
demostrado hasta la fecha, ser una predicción bastante exacta del crecimiento
de la complejidad de los CPUs y otros IC.6
Mientras que, en los pasados sesenta
años han cambiado drásticamente, la complejidad, el tamaño, la construcción y
la forma general de la CPU, es notable que el diseño y el funcionamiento básico
no ha cambiado demasiado. Casi todos los CPU comunes de hoy se pueden describir
con precisión como máquinas de programa
almacenado de von Neumann.nota 2 A medida
que la ya mencionada ley del Moore continúa manteniéndose verdadera,6 se han
presentado preocupaciones sobre los límites de la tecnología de transistor del
circuito integrado. La miniaturización extrema de puertas electrónicas está
causando los efectos de fenómenos que se vuelven mucho más significativos, como
la electromigración y el subumbral de pérdida. Estas
nuevas preocupaciones están entre los muchos factores que hacen a
investigadores estudiar nuevos métodos de computación como la computación
cuántica, así como ampliar el uso de paralelismo y otros
métodos que extienden la utilidad del modelo clásico de von Neumann.
Operación
La operación fundamental de la mayoría
de las CPU es ejecutar una secuencia de instrucciones almacenadas llamadas
«programa». El programa es representado por una serie de números que se
mantienen en una cierta clase de memoria de ordenador. Hay cuatro pasos que
casi todos las CPU de arquitectura de von Neumann usan en su
operación: fetch, decode, execute, y writeback,
(leer, decodificar, ejecutar y escribir).
Fetch
El primer paso, leer, implica
el recuperar una instrucción, (que es
representada por un número o una secuencia de números), de la memoria de
programa. La localización en la memoria del programa es determinada por un contador
de programa (PC), que almacena un número que identifica la dirección
de la siguiente instrucción que se debe buscar. Después se lee una instrucción,
el PC es incrementado por la longitud de la instrucción en términos de unidades
de memoria de modo que contendrá la dirección de la siguiente instrucción en la
secuencia.nota 3
Frecuentemente, la instrucción a ser leída debe ser recuperada de memoria
relativamente lenta, haciendo detener al CPU mientras espera que la instrucción
sea devuelta. Esta cuestión se trata en gran medida en los procesadores
modernos por los cachés y las arquitecturas pipeline (ver abajo).
Decode
En el paso de decodificación,
la instrucción es dividida en partes que tienen significado para otras unidades
de la CPU. La manera en que el valor de la instrucción numérica es interpretado
está definida por la arquitectura del conjunto de instrucciones (el ISA) de la
CPU.nota 4 A menudo,
un grupo de números en la instrucción, llamados opcode, indica
qué operación realizar. Las partes restantes del número usualmente proporcionan
información requerida para esa instrucción, como por ejemplo, operandos para
una operación de adición. Tales operandos
se pueden dar como un valor constante (llamado valor inmediato), o como un
lugar para localizar un valor, que según lo determinado por algún modo de dirección, puede ser un registro o una dirección
de memoria. En diseños más viejos las unidades del CPU responsables
de decodificar la instrucción eran dispositivos de hardware fijos. Sin embargo,
en CPUs e ISAs más abstractos y complicados, es frecuentemente usado un microprograma para
ayudar a traducir instrucciones en varias señales de configuración para el CPU.
Este microprograma es a veces reescribible de tal manera que puede ser
modificado para cambiar la manera en que el CPU decodifica instrucciones
incluso después de que haya sido fabricado.
Execute
Diagrama de bloques de un CPU simple
Writeback
El paso final, la escritura,
simplemente «escribe» los resultados del paso de ejecución a una cierta forma
de memoria. Muy a menudo, los resultados son escritos a algún registro interno
del CPU para acceso rápido por subsecuentes instrucciones. En otros casos los
resultados pueden ser escritos a una memoria principal más lenta pero más
barata y más grande. Algunos tipos de instrucciones manipulan el contador de
programa en lugar de directamente producir datos de resultado. Estas son
llamadas generalmente "saltos" (jumps) y facilitan comportamientos
como bucles, la
ejecución condicional de programas (con el uso de saltos condicionales), y funciones en
programas.nota 5 Muchas
instrucciones también cambiarán el estado de dígitos en un registro de
"banderas". Estas banderas pueden ser usadas para influenciar cómo se
comporta un programa, puesto que a menudo indican el resultado de varias
operaciones. Por ejemplo, un tipo de instrucción de "comparación"
considera dos valores y fija un número, en el registro de banderas, de acuerdo
a cuál es el mayor. Entonces, esta bandera puede ser usada por una posterior
instrucción de salto para determinar el flujo de programa.
Después de la ejecución de la
instrucción y la escritura de los datos resultantes, el proceso entero se
repite con el siguiente ciclo de instrucción, normalmente leyendo la siguiente
instrucción en secuencia debido al valor incrementado en el contador de
programa. Si la instrucción completada era un salto, el contador de programa
será modificado para contener la dirección de la instrucción a la cual se
saltó, y la ejecución del programa continúa normalmente. En CPUs más complejos
que el descrito aquí, múltiples instrucciones pueden ser leídas, decodificadas,
y ejecutadas simultáneamente. Esta sección describe lo que es referido
generalmente como el "entubado RISC clásico" (Classic RISC pipeline),
que de hecho es bastante común entre los CPU simples usados en muchos
dispositivos electrónicos, a menudo llamados microcontroladores.nota 6
Diseño e implementación
Rango de enteros
La manera en que un CPU representa los
números es una opción de diseño que afecta las más básicas formas en que el
dispositivo funciona. Algunas de las primeras calculadoras digitales usaron,
para representar números internamente, un modelo eléctrico del sistema de numeración decimal común (base diez). Algunas otras
computadoras han usado sistemas de numeración más exóticos como el ternario (base
tres). Casi todos los CPU modernos representan los números en forma binaria, en donde cada dígito es representado
por una cierta cantidad física de dos valores, como un voltaje "alto" o
"bajo".nota 7
El rango del número entero también
puede afectar el número de posiciones en memoria que el CPU puede direccionar
(localizar). Por ejemplo, si un CPU binario utiliza 32 bits para representar
una dirección de memoria, y cada dirección de memoria representa a un octeto (8 bits), la
cantidad máxima de memoria que el CPU puede direccionar es 232
octetos, o 4 GB. Esta es una vista
muy simple del espacio de dirección del CPU, y
muchos diseños modernos usan métodos de dirección mucho más complejos como paginación para
localizar más memoria que su rango entero permitiría con un espacio de
dirección plano.
Niveles más altos del rango de números
enteros requieren más estructuras para manejar los dígitos adicionales, y por
lo tanto, más complejidad, tamaño, uso de energía, y generalmente costo. Por
ello, no es del todo infrecuente, ver microcontroladores de 4 y 8
bits usados en aplicaciones modernas, aun cuando están disponibles CPU con un
rango mucho más alto (de 16, 32, 64, e incluso 128 bits). Los
microcontroladores más simples son generalmente más baratos, usan menos
energía, y por lo tanto disipan menos calor. Todo esto pueden ser
consideraciones de diseño importantes para los dispositivos electrónicos. Sin
embargo, en aplicaciones del extremo alto, los beneficios producidos por el
rango adicional, (más a menudo el espacio de dirección adicional), son más
significativos y con frecuencia afectan las opciones del diseño. Para ganar
algunas de las ventajas proporcionadas por las longitudes de bits tanto más
bajas, como más altas, muchas CPUs están diseñadas con anchos de bit diferentes
para diferentes unidades del dispositivo. Por ejemplo, el IBM System/370 usó un CPU
que fue sobre todo de 32 bits, pero usó precisión de 128 bits dentro de sus
unidades de coma flotante para
facilitar mayor exactitud y rango de números de coma flotante.4 Muchos
diseños posteriores de CPU usan una mezcla de ancho de bits similar,
especialmente cuando el procesador está diseñado para usos de propósito general
donde se requiere un razonable equilibrio entre la capacidad de números enteros
y de coma flotante.
Frecuencia de reloj
La mayoría de los CPU, y de hecho, la
mayoría de los dispositivos de lógica
secuencial, son de naturaleza síncrona.nota 9 Es decir,
están diseñados y operan en función de una señal de sincronización. Esta señal,
conocida como señal de reloj, usualmente toma la forma de una onda cuadrada periódica.
Calculando el tiempo máximo en que las señales eléctricas pueden moverse en las
varias bifurcaciones de los muchos circuitos de un CPU, los diseñadores pueden
seleccionar un período apropiado para la
señal del reloj.
Este período debe ser más largo que la
cantidad de tiempo que toma a una señal moverse, o propagarse en el peor de los
casos. Al fijar el período del reloj a un valor bastante mayor sobre el retardo
de la propagación del peor caso, es posible diseñar todo el CPU y la manera que
mueve los datos alrededor de los "bordes" de la subida y bajada de la
señal del reloj. Esto tiene la ventaja de simplificar el CPU
significativamente, tanto en una perspectiva de diseño, como en una perspectiva
de cantidad de componentes. Sin embargo, esto también tiene la desventaja que
todo el CPU debe esperar por sus elementos más lentos, aún cuando algunas
unidades de la misma son mucho más rápidas. Esta limitación ha sido compensada
en gran parte por varios métodos de aumentar el paralelismo del CPU (ver
abajo).
Sin embargo, las mejoras
arquitectónicas por sí solas, no solucionan todas las desventajas de CPUs
globalmente síncronas. Por ejemplo, una señal de reloj está sujeta a los retardos
de cualquier otra señal eléctrica. Velocidades de reloj más altas en CPUs cada
vez más complejas hacen más difícil de mantener la señal del reloj en fase
(sincronizada) a través de toda la unidad. Esto ha conducido que muchos CPU
modernos requieran que se les proporcione múltiples señales de reloj idénticas,
para evitar retardar una sola señal lo suficiente como para hacer al CPU
funcionar incorrectamente. Otro importante problema cuando la velocidad del
reloj aumenta dramáticamente, es la cantidad de calor que es disipado por el
CPU. La señal del reloj cambia constantemente, provocando la conmutación de
muchos componentes (cambio de estado) sin importar si están siendo usados en
ese momento. En general, un componente que está cambiando de estado, usa más
energía que un elemento en un estado estático. Por lo tanto, a medida que la
velocidad del reloj aumenta, así lo hace también la disipación de calor,
causando que el CPU requiera soluciones de enfriamiento más efectivas.
Un método de tratar la conmutación de
componentes innecesarios se llama el clock gating, que implica
apagar la señal del reloj a los componentes innecesarios, efectivamente
desactivándolos. Sin embargo, esto es frecuentemente considerado como difícil
de implementar y por lo tanto no ve uso común fuera de diseños de muy baja
potencia. Un notable diseño de CPU tardío que utiliza una amplia compuerta del
reloj para reducir los requisitos de potencia de la consola de videojuegos es
la de la Xbox 360 basada en la PowerPC de IBM.7 Otro
método de tratar algunos de los problemas de una señal global de reloj es la
completa remoción de la misma. Mientras que quitar la señal global del reloj
hace, de muchas maneras, considerablemente más complejo el proceso del diseño,
en comparación con diseños síncronos similares, los diseños asincrónicos (o sin
reloj) tienen marcadas ventajas en el consumo de energía y la disipación de
calor. Aunque se trate de algo infrecuente, las CPUs completas se han
construido sin utilizar una señal global de reloj. Dos notables ejemplos de
esto son el AMULET, que implementa la arquitectura del ARM, y el MiniMIPS, compatible con el MIPS R3000. En lugar de
remover totalmente la señal del reloj, algunos diseños de CPU permiten que
ciertas unidades del dispositivo sean asincrónicas, como por ejemplo, usando ALU en conjunción con
pipelining superescalar para alcanzar algunas ganancias en el desempeño
aritmético. Mientras que no esté completamente claro si los diseños totalmente
asincrónicos pueden desempeñarse a un nivel comparable o mejor que sus
contrapartes síncronas, es evidente que por lo menos sobresalen en las
operaciones matemáticas más simples. Esto, combinado con sus excelentes
características de consumo de energía y disipación de calor, los hace muy
adecuados para sistemas embebidos.8
Paralelismo
Modelo de un CPU subescalar. Note que toma quince ciclos
para terminar tres instrucciones. La descripción de la operación básica
de un CPU ofrecida en la sección anterior describe la forma más simple que
puede tomar un CPU. Este tipo de CPU, usualmente referido como subescalar,
opera sobre y ejecuta una sola instrucción con una o dos piezas de datos a la
vez.
Este proceso da lugar a una ineficacia
inherente en CPU subescalares. Puesto que solamente una instrucción es
ejecutada a la vez, todo el CPU debe esperar que esa instrucción se complete
antes de proceder a la siguiente instrucción. Como resultado, la CPU subescalar
queda "paralizado" en instrucciones que toman más de un ciclo de
reloj para completar su ejecución. Incluso la adición de una segunda unidad de
ejecución (ver abajo) no mejora mucho el desempeño. En lugar de un camino
quedando congelado, ahora dos caminos se paralizan y aumenta el número de
transistores no usados. Este diseño, en donde los recursos de ejecución de la
CPU pueden operar con solamente una instrucción a la vez, solo puede,
posiblemente, alcanzar el desempeño escalar (una instrucción por ciclo
de reloj). Sin embargo, el desempeño casi siempre es subescalar (menos de una
instrucción por ciclo).
Las tentativas de alcanzar un
desempeño escalar y mejor, han resultado en una variedad de metodologías de
diseño que hacen comportarse al CPU menos linealmente y más en paralelo. Cuando
se refiere al paralelismo en los CPU, generalmente son usados dos términos para
clasificar estas técnicas de diseño.
- El paralelismo a nivel
de instrucción, en
inglés instruction level parallelism (ILP), busca aumentar
la tasa en la cual las instrucciones son ejecutadas dentro de un CPU, es
decir, aumentar la utilización de los recursos de ejecución en la
pastilla.
- El paralelismo a nivel de hilo de ejecución, en inglés thread level parallelism
(TLP), que se propone incrementar el número de hilos (efectivamente programas individuales) que un CPU
pueda ejecutar simultáneamente.
Cada metodología se diferencia tanto
en las maneras en las que están implementadas, como en la efectividad relativa
que producen en el aumento del desempeño de la CPU para una aplicación.nota 10
ILP: Segmentación y arquitectura superescalar
Tubería básica de cinco etapas. En el mejor de los casos,
esta tubería puede sostener un ratio de completado de una instrucción por
ciclo. Uno de los métodos más simples para
lograr incrementar el paralelismo es comenzar los primeros pasos de leer y
decodificar la instrucción antes de que la instrucción anterior haya terminado
de ejecutarse. Esta es la forma más simple de una técnica conocida como
segmentación (instruction pipelining en inglés), y es utilizada en casi
todas los CPU de propósito general modernos. Al dividir la ruta de ejecución en
etapas discretas, la tubería permite que más de una instrucción sea ejecutada
en cualquier tiempo. Esta separación puede ser comparada a una línea de
ensamblaje, en la cual una instrucción es hecha más completa en cada etapa
hasta que sale de la tubería de ejecución y es retirada.
Sin embargo, la tubería introduce la
posibilidad de una situación donde es necesario terminar el resultado de la
operación anterior para completar la operación siguiente; una condición llamada
a menudo como conflicto de dependencia de datos. Para hacer frente a esto, debe
ser tomado un cuidado adicional para comprobar estas clases de condiciones, y
si esto ocurre, se debe retrasar una porción de la tubería de instrucción.
Naturalmente, lograr esto requiere circuitería adicional, los procesadores
entubados son más complejos que los subescalares, pero no mucho. Un procesador
entubado puede llegar a ser casi completamente escalar, solamente inhibido por
las abruptas paradas de la tubería (una instrucción durando más de un ciclo de
reloj en una etapa). Segmentación superescalar simple. Al leer y despachar dos
instrucciones a la vez, un máximo de dos instrucciones por ciclo pueden ser
completadas.
Una mejora adicional sobre la idea del
entubado de instrucción (instruction pipelining) condujo al desarrollo de un
método que disminuye incluso más el tiempo ocioso de los componentes del CPU.
Diseños que se dice que son superescalares incluyen una larga tubería de
instrucción y múltiples unidades de ejecución idénticas.9 En una
tubería superescalar, múltiples instrucciones son leídas y pasadas a un
despachador, que decide si las instrucciones se pueden o no ejecutar en
paralelo (simultáneamente). De ser así, son despachadas a las unidades de
ejecución disponibles, dando por resultado la capacidad para que varias
instrucciones sean ejecutadas simultáneamente. En general, cuanto más
instrucciones un CPU superescalar es capaz de despachar simultáneamente a las
unidades de ejecución en espera, más instrucciones serán completadas en un ciclo
dado.
La mayor parte de la dificultad en el
diseño de una arquitectura superescalar de CPU descansa en crear un despachador
eficaz. El despachador necesita poder determinar rápida y correctamente si las
instrucciones pueden ejecutarse en paralelo, tan bien como despacharlas de una
manera que mantenga ocupadas tantas unidades de ejecución como sea posible.
Esto requiere que la tubería de instrucción sea llenada tan a menudo como sea
posible y se incrementa la necesidad, en las arquitecturas superescalares, de
cantidades significativas de caché
de CPU. Esto también crea técnicas para evitar peligros como la predicción de bifurcación, ejecución especulativa, y la ejecución fuera de orden, cruciales para
mantener altos niveles de desempeño. Tratando de predecir qué rama (o
trayectoria) tomará una instrucción condicional, la CPU puede minimizar el
número de veces que todo el canal debe esperar hasta que se complete una
instrucción condicional. Frecuentemente, la ejecución especulativa proporciona
aumentos modestos del desempeño al ejecutar porciones de código que no puede
ser necesario después de completarse una operación condicional. Fuera de la
orden de ejecución cambia de algún modo el orden en que se ejecutan las
instrucciones para reducir retardos debido a las dependencias de datos. También
en el caso de instrucciones individuales de datos múltiples — los procesadores
modernos, en caso de que se hayan procesado una gran cantidad de datos del
mismo tipo, pueden desactivar partes de la tubería de manera que cuando se
ejecuta una sola sentencia muchas veces, la CPU salta la captación y decodifica
fases y por lo tanto aumenta considerablemente el rendimiento en ciertas
ocasiones, sobre todo en los motores de programas altamente monótonos como el
software de creación de video y procesamiento de fotografías.
En el caso donde una porción de la CPU
es superescalar y una parte no lo es, la parte que no es superescalar sufre en
el desempeño debido a las paradas de horario. El Intel
Pentium original (P5) tenía dos ALUs superescalares que podían
aceptar, cada una, una instrucción por ciclo de reloj, pero su FPU no podía
aceptar una instrucción por ciclo de reloj. Así el P5 era superescalar en la
parte de números enteros pero no era superescalar de números de coma (o punto
[decimal]) flotante. El sucesor a la arquitectura del Pentium de Intel, el P6, agregó capacidades superescalares a
sus funciones de coma flotante, y por lo tanto produjo un significativo aumento
en el desempeño de este tipo de instrucciones.
Tanto el diseño superescalar como el
entubado simple aumentan el ILP de una CPU al permitir a un solo procesador
completar la ejecución de instrucciones en ratios que sobrepasan una
instrucción por ciclo (IPC).nota 11 La mayoría
de los modernos diseños de CPU son por lo menos algo superescalares, y en la
última década, casi todos los diseños de CPU de propósito general son
superescalares. En los últimos años algo del énfasis en el diseño de
computadores de alto ILP se ha movido del hardware del CPU hacia su interfaz de
software, o ISA. La estrategia very long instruction word o VLIW,
causa a algún ILP a ser implícito directamente por el software, reduciendo la
cantidad de trabajo que el CPU debe realizar para darle un empuje significativo
al ILP y por lo tanto reducir la complejidad del diseño.
Paralelismo a nivel de hilos
Otra estrategia para lograr el
rendimiento es ejecutar varios programas o hilos en paralelo. Esta área de
investigación se conoce como computación paralela. En la taxonomía de Flynn,
esta estrategia se conoce como múltiples instrucciones de varios datos o MIMD.
Una tecnología utilizada para este
propósito fue el multiprocesamiento (MP). El
puntapié inicial de esta tecnología se conoce como multiprocesamiento simétrico (SMP),
donde un pequeño número de CPU comparten una visión coherente de su sistema de
memoria. En este esquema, cada CPU tiene un hardware adicional para mantener
una visión constantemente actualizada de la memoria. Para evitar visitas
rancias de la memoria, las CPU pueden cooperar en el mismo programa y los
programas pueden migrar desde una CPU a otra. Para aumentar el número de CPUs
que cooperan más allá de unas pocas, se introdujeron en 1990, los esquemas
tales como el non-uniform memory Access (acceso no uniforme a memoria) (NUMA) y los protocolos de coherencia
basados en directorios. Los sistemas SMP se limitan a un
pequeño número de CPU mientras que los sistemas NUMA se han construido con
miles de procesadores. Inicialmente, el multiprocesamiento se construyó usando
múltiples CPUs discretas y tableros para implementar la interconexión entre los
procesadores. Cuando los procesadores y su interconexión hayan sido
implementadas en un único chip de silicio, la tecnología se conoce como un procesador multinúcleo.
Posteriormente, se reconoció que
existía un paralelismo muy estrecho con un único programa. Un único programa
podría tener varios hilos (o funciones) que podrían ser ejecutadas por separado
o en paralelo. Algunos de los primeros ejemplos de esta tecnología implementaba
procesamiento de entrada/salida tales como
el acceso directo a memoria como un hilo
separado del hilo computado. En la década de 1970, se introdujo un enfoque más
general a esta tecnología, cuando se diseñaron sistemas para ejecutar múltiples
hilos de computación en paralelo. Esta tecnología se conoce como multihilo (MT).
Este enfoque se considera más rentable
que la del multiprocesamiento, ya que solo se replica un pequeño número de
componentes dentro de una CPU para soportar MT en oposición a la totalidad de
la CPU en el caso de MP. En MT, las unidades de ejecución y el sistema de
memoria incluyendo los cachés son compartidos entre varios hilos. La desventaja
de MT es que el soporte de hardware para multihilo es más visible para el
software que la de MP y por lo tanto el software supervisor como el de los
sistemas operativos tienen que someterse a los cambios más grandes para apoyar
MT. Un tipo de MT que se implementó es conocido como bloque multihilo, donde se
ejecuta un hilo hasta que se paralice esperando que regresen los datos desde la
memoria externa. En este esquema, la CPU tendría luego que cambiar rápidamente
a otro hilo que está listo para funcionar, el interruptor muchas veces realiza
un ciclo de reloj de la CPU, como la tecnología UltraSPARC. Otro tipo
de MT se denomina multihilo simultáneo, en donde
las instrucciones de múltiples hilos se ejecutan en paralelo dentro de un ciclo
de reloj de la CPU.
Paralelismo de datos
Un menos común pero cada vez más
importante paradigma de CPU (y de hecho, de computación en general) trata con
vectores. Los procesadores de los que se ha hablado anteriormente son todos
referidos como cierto tipo de dispositivo escalar.nota 12 Como
implica su nombre, los procesadores vectoriales se ocupan de múltiples piezas
de datos en el contexto de una instrucción, esto contrasta con los procesadores
escalares, que tratan una pieza de dato por cada instrucción. Estos dos
esquemas de ocuparse de los datos son generalmente referidos respectivamente
como SISD (single
instruction, single data) y SIMD (single
instruction, multiple data). La gran utilidad en crear CPU que se ocupen de
vectores de datos radica en la optimización de tareas que tienden a requerir la
misma operación, por ejemplo, una suma, o un producto
escalar, a ser realizado en un gran conjunto de datos. Algunos
ejemplos clásicos de este tipo de tareas son las aplicaciones multimedia (imágenes,
vídeo, y sonido), así como muchos tipos de tareas científicas y de ingeniería.
Mientras que una CPU escalar debe completar todo el proceso de leer,
decodificar, y ejecutar cada instrucción y valor en un conjunto de datos, una
CPU vectorial puede realizar una simple operación en un comparativamente grande
conjunto de datos con una sola instrucción. Por supuesto, esto es solamente
posible cuando la aplicación tiende a requerir muchos pasos que apliquen una
operación a un conjunto grande de datos.
La mayoría de las primeras CPU
vectoriales, como el Cray-1, se asociaron casi
exclusivamente a aplicaciones de investigación científica y criptografía. Sin
embargo, a medida que la multimedia se desplazó en gran parte a medios
digitales, ha llegado a ser significativa la necesidad de una cierta forma de
SIMD en CPUs de propósito general. Poco después de que comenzara a ser común
incluir unidades de coma flotante en procesadores de
uso general, también comenzaron a aparecer especificaciones e implementaciones
de unidades de ejecución SIMD para las CPU de uso general. Algunas de estas
primeras especificaciones SIMD, como el MMX de Intel, fueron
solamente para números enteros. Esto demostró ser un impedimento significativo
para algunos desarrolladores de software, ya que muchas de las aplicaciones que
se beneficiaban del SIMD trataban sobre todo con números de coma flotante.
Progresivamente, estos primeros diseños fueron refinados y rehechos en alguna
de las comunes, modernas especificaciones SIMD, que generalmente están
asociadas a un ISA. Algunos ejemplos modernos notables son el SSE de Intel y el
AltiVec relacionado con el PowerPC (también conocido como VMX).nota 13
Desempeño
El "desempeño" (performance)
o la velocidad de un procesador depende de, entre muchos otros factores, la
velocidad del reloj (generalmente dada en múltiplos de hertz) y las
instrucciones por ciclo de reloj (IPC), que juntos son los factores para las instrucciones por segundo (IPS) que el CPU
puede rendir.10 Muchos
reportes de valores IPS han representado tasas de ejecución "pico" en
secuencias de instrucciones artificiales con pocas ramas, mientras que las
cargas de trabajo realistas consisten en una combinación de instrucciones y de
aplicaciones, algunas de las cuales requieren más tiempo para ejecutar que
otras. El rendimiento de la jerarquía
de memoria también afecta en gran medida al rendimiento del
procesador, un tema muy poco tenido en cuenta en los cálculos de MIPS. Debido a
estos problemas, para este fin, se han desarrollado varios exámenes
estandarizados, tales como SPECint muchas veces llamados "puntos de referencia" - para
tratar de medir el rendimiento real efectivo en aplicaciones de uso cotidiano.
El desempeño de procesamiento de las
computadoras se incrementa utilizando procesadores multinúcleo, que en esencia es
conectar dos o más procesadores individuales (llamados núcleos en este sentido)
en un solo circuito
integrado.11
Idealmente, un procesador de doble núcleo sería casi dos veces tan potente como
un procesador de núcleo único. En la práctica, la ganancia de desempeño es
mucho menor, solo alrededor del 50%, debido a
la implementación de algoritmos imperfectos de software.12 El aumento
del número de núcleos en un procesador (es decir, dual-core, quad-core, etc)
aumenta la carga de trabajo que se puede manejar. Esto significa que el
procesador ahora puede manejar numerosos eventos asíncronos, interrupciones,
etc que pueden tomar un "peaje" en la CPU (Central Processing Unit) cuando
se abruma. Estos núcleos pueden considerarse como diferentes plantas en una
planta de procesamiento, con el manejo de cada piso una tarea diferente. En
ocasiones, estos núcleos se manejan las mismas tareas que los núcleos
adyacentes a ellos si un solo núcleo no es suficiente para manejar la
información.
Debido a las capacidades específicas
de las CPU modernas, como Hyper-Threading y Uncore, que implican el intercambio de
recursos reales de la CPU mientras que el objetivo de una mayor utilización,
supervisar los niveles de rendimiento y la utilización del hardware se fue
convirtiendo gradualmente en una tarea más compleja. Como respuesta, algunas
CPUs implementan lógica de hardware adicional que controla la utilización real
de las diversas partes de una CPU y proporciona varios contadores accesibles a
software; un ejemplo es la tecnología Performance Counter Monitor
("Monitor de contador de rendimiento") de Intel.13
No hay comentarios:
Publicar un comentario