Una unidad central de procesamiento ( CPU ), también llamada procesador central , procesador principal o simplemente procesador , es el procesador más importante de una computadora determinada . [1] [2] Sus circuitos electrónicos ejecutan instrucciones de un programa de computadora , como operaciones aritméticas , lógicas, de control y de entrada/salida (E/S). [3] [4] [5] Esta función contrasta con la de los componentes externos, como la memoria principal y los circuitos de E/S, [6] y los coprocesadores especializados como las unidades de procesamiento gráfico (GPU).
La forma, el diseño y la implementación de las CPU han cambiado con el tiempo, pero su funcionamiento fundamental permanece casi inalterado. [7] Los componentes principales de una CPU incluyen la unidad aritmético-lógica (ALU) que realiza operaciones aritméticas y lógicas , los registros del procesador que suministran operandos a la ALU y almacenan los resultados de las operaciones de la ALU, y una unidad de control que orquesta la obtención (de la memoria), la decodificación y la ejecución (de instrucciones) al dirigir las operaciones coordinadas de la ALU, los registros y otros componentes. Las CPU modernas dedican una gran cantidad de área de semiconductores a cachés y paralelismo a nivel de instrucción para aumentar el rendimiento y a modos de CPU para soportar sistemas operativos y virtualización .
La mayoría de las CPU modernas se implementan en microprocesadores de circuitos integrados (CI) , con una o más CPU en un solo chip CI. Los chips de microprocesador con múltiples CPU se denominan procesadores multinúcleo . [8] Las CPU físicas individuales, llamadas núcleos de procesador , también pueden tener múltiples subprocesos para admitir subprocesos múltiples a nivel de CPU. [9]
Un CI que contiene una CPU también puede contener memoria , interfaces periféricas y otros componentes de una computadora; [10] dichos dispositivos integrados se denominan microcontroladores o sistemas en un chip (SoC).
Las primeras computadoras, como la ENIAC, tuvieron que ser recableadas físicamente para realizar diferentes tareas, lo que provocó que estas máquinas se llamaran "computadoras de programa fijo". [11] El término "unidad central de procesamiento" se ha utilizado desde 1955. [12] [13] Dado que el término "CPU" se define generalmente como un dispositivo para la ejecución de software (programa de computadora), los primeros dispositivos que podrían llamarse correctamente CPU llegaron con la llegada de la computadora de programa almacenado .
La idea de una computadora con programa almacenado ya había estado presente en el diseño de ENIAC de J. Presper Eckert y John William Mauchly , pero inicialmente se omitió para que ENIAC pudiera terminarse antes. [14] El 30 de junio de 1945, antes de que se hiciera ENIAC, el matemático John von Neumann distribuyó un documento titulado Primer borrador de un informe sobre el EDVAC . Era el esquema de una computadora con programa almacenado que finalmente se completaría en agosto de 1949. [15] EDVAC fue diseñado para realizar una cierta cantidad de instrucciones (u operaciones) de varios tipos. Significativamente, los programas escritos para EDVAC debían almacenarse en la memoria de computadora de alta velocidad en lugar de especificarse por el cableado físico de la computadora. [16] Esto superó una grave limitación de ENIAC, que era el tiempo y el esfuerzo considerables requeridos para reconfigurar la computadora para realizar una nueva tarea. [17] Con el diseño de von Neumann, el programa que ejecutaba EDVAC podía modificarse simplemente modificando el contenido de la memoria. EDVAC no fue el primer ordenador con programa almacenado; el Manchester Baby , que era un ordenador experimental a pequeña escala con programa almacenado, ejecutó su primer programa el 21 de junio de 1948 [18] y el Manchester Mark 1 ejecutó su primer programa durante la noche del 16 al 17 de junio de 1949. [19]
Las primeras CPU eran diseños personalizados que se utilizaban como parte de una computadora más grande y, a veces, distintiva. [20] Sin embargo, este método de diseñar CPU personalizadas para una aplicación particular ha dado paso en gran medida al desarrollo de procesadores multipropósito producidos en grandes cantidades. Esta estandarización comenzó en la era de las computadoras centrales y minicomputadoras con transistores discretos , y se ha acelerado rápidamente con la popularización del circuito integrado (CI). El CI ha permitido diseñar y fabricar CPU cada vez más complejas con tolerancias del orden de los nanómetros . [21] Tanto la miniaturización como la estandarización de las CPU han aumentado la presencia de dispositivos digitales en la vida moderna mucho más allá de la aplicación limitada de las máquinas de computación dedicadas. Los microprocesadores modernos aparecen en dispositivos electrónicos que van desde automóviles [22] hasta teléfonos celulares, [23] y, a veces, incluso en juguetes. [24] [25]
Aunque a von Neumann se le atribuye con mayor frecuencia el diseño de la computadora de programa almacenado debido a su diseño de EDVAC, y el diseño se conoció como la arquitectura von Neumann , otros antes que él, como Konrad Zuse , habían sugerido e implementado ideas similares. [26] La llamada arquitectura Harvard de Harvard Mark I , que se completó antes de EDVAC, [27] [28] también utilizó un diseño de programa almacenado utilizando cinta de papel perforada en lugar de memoria electrónica. [29] La diferencia clave entre las arquitecturas von Neumann y Harvard es que esta última separa el almacenamiento y el tratamiento de las instrucciones y los datos de la CPU, mientras que la primera utiliza el mismo espacio de memoria para ambos. [30] La mayoría de las CPU modernas son principalmente de diseño von Neumann, pero también se ven CPU con la arquitectura Harvard, especialmente en aplicaciones integradas; por ejemplo, los microcontroladores Atmel AVR son procesadores de arquitectura Harvard. [31]
Los relés y los tubos de vacío (tubos termoiónicos) se utilizaban habitualmente como elementos de conmutación; [32] [33] un ordenador útil requiere miles o decenas de miles de dispositivos de conmutación. La velocidad total de un sistema depende de la velocidad de los conmutadores. Los ordenadores de tubos de vacío como el EDVAC tendían a tener un promedio de ocho horas entre fallos, mientras que los ordenadores de relés (como el más lento pero anterior Harvard Mark I) fallaban muy raramente. [13] Al final, las CPU basadas en tubos se convirtieron en dominantes porque las importantes ventajas de velocidad que ofrecían generalmente superaban los problemas de fiabilidad. La mayoría de estas primeras CPU síncronas funcionaban a velocidades de reloj bajas en comparación con los diseños microelectrónicos modernos. Las frecuencias de señal de reloj que iban desde 100 kHz a 4 MHz eran muy comunes en esa época, limitadas en gran medida por la velocidad de los dispositivos de conmutación con los que estaban construidos. [34]
La complejidad del diseño de las CPU aumentó a medida que varias tecnologías facilitaron la construcción de dispositivos electrónicos más pequeños y confiables. La primera de esas mejoras se produjo con la llegada del transistor . Las CPU transistorizadas durante las décadas de 1950 y 1960 ya no tenían que construirse con elementos de conmutación voluminosos, poco confiables y frágiles, como tubos de vacío y relés . [35] Con esta mejora, se construyeron CPU más complejas y confiables en una o varias placas de circuito impreso que contenían componentes discretos (individuales).
En 1964, IBM presentó su arquitectura informática IBM System/360 , que se utilizó en una serie de ordenadores capaces de ejecutar los mismos programas con diferentes velocidades y rendimientos. [36] Esto fue significativo en una época en la que la mayoría de los ordenadores electrónicos eran incompatibles entre sí, incluso los fabricados por el mismo fabricante. Para facilitar esta mejora, IBM utilizó el concepto de microprograma (a menudo llamado "microcódigo"), que todavía se utiliza ampliamente en las CPU modernas. [37] La arquitectura System/360 fue tan popular que dominó el mercado de los ordenadores mainframe durante décadas y dejó un legado que continúan ordenadores modernos similares como el IBM zSeries . [38] [39] En 1965, Digital Equipment Corporation (DEC) presentó otro ordenador influyente destinado a los mercados científicos y de investigación: el PDP-8 . [40]
Los ordenadores basados en transistores tenían varias ventajas distintivas sobre sus predecesores. Además de facilitar una mayor fiabilidad y un menor consumo de energía, los transistores también permitían que las CPU funcionaran a velocidades mucho más altas debido al corto tiempo de conmutación de un transistor en comparación con un tubo o un relé. [41] La mayor fiabilidad y la velocidad drásticamente aumentada de los elementos de conmutación, que en ese momento eran casi exclusivamente transistores; durante este período se obtuvieron fácilmente velocidades de reloj de CPU de decenas de megahercios. [42] Además, mientras que los transistores discretos y las CPU con circuitos integrados se utilizaban intensamente, comenzaron a aparecer nuevos diseños de alto rendimiento como los procesadores vectoriales de instrucción única y datos múltiples (SIMD) . [43] Estos primeros diseños experimentales dieron lugar más tarde a la era de las supercomputadoras especializadas como las fabricadas por Cray Inc. y Fujitsu Ltd. [ 43]
Durante este período, se desarrolló un método para fabricar muchos transistores interconectados en un espacio compacto. El circuito integrado (CI) permitió fabricar una gran cantidad de transistores en un solo chip o "chip" basado en semiconductores . Al principio, solo se miniaturizaron en CI circuitos digitales muy básicos no especializados, como las puertas NOR . [44] Las CPU basadas en estos CI de "bloques de construcción" generalmente se conocen como dispositivos de "integración a pequeña escala" (SSI). Los CI de SSI, como los utilizados en la computadora de guía Apollo , generalmente contenían hasta unas pocas docenas de transistores. Construir una CPU completa a partir de CI de SSI requería miles de chips individuales, pero aún consumía mucho menos espacio y energía que los diseños de transistores discretos anteriores. [45]
El System/370 de IBM , sucesor del System/360, utilizaba circuitos integrados SSI en lugar de módulos de transistores discretos de Solid Logic Technology . [46] [47] El PDP-8 /I de DEC y el PDP-10 KI10 también cambiaron los transistores individuales utilizados por el PDP-8 y el PDP-10 por circuitos integrados SSI, [48] y su extremadamente popular línea PDP-11 se construyó originalmente con circuitos integrados SSI, pero finalmente se implementó con componentes LSI una vez que estos se volvieron prácticos.
Lee Boysel publicó artículos influyentes, incluido un "manifiesto" de 1967, que describía cómo construir el equivalente de una computadora mainframe de 32 bits a partir de una cantidad relativamente pequeña de circuitos de integración a gran escala (LSI). [49] [50] La única forma de construir chips LSI, que son chips con cien o más puertas, era construirlos utilizando un proceso de fabricación de semiconductores de óxido de metal (MOS) (ya sea lógica PMOS , lógica NMOS o lógica CMOS ). Sin embargo, algunas empresas continuaron construyendo procesadores a partir de chips de lógica transistor-transistor bipolar (TTL) porque los transistores de unión bipolar eran más rápidos que los chips MOS hasta la década de 1970 (algunas empresas como Datapoint continuaron construyendo procesadores a partir de chips TTL hasta principios de la década de 1980). [50] En la década de 1960, los CI MOS eran más lentos e inicialmente se consideraron útiles solo en aplicaciones que requerían baja potencia. [51] [52] Tras el desarrollo de la tecnología MOS de compuerta de silicio por Federico Faggin en Fairchild Semiconductor en 1968, los circuitos integrados MOS reemplazaron en gran medida al TTL bipolar como tecnología de chip estándar a principios de la década de 1970. [53]
A medida que la tecnología microelectrónica avanzaba, se colocaban cada vez más transistores en los circuitos integrados, lo que disminuyó la cantidad de circuitos integrados individuales necesarios para una CPU completa. Los circuitos integrados MSI y LSI aumentaron la cantidad de transistores a cientos y luego a miles. En 1968, la cantidad de circuitos integrados necesarios para construir una CPU completa se había reducido a 24 circuitos integrados de ocho tipos diferentes, y cada circuito integrado contenía aproximadamente 1000 MOSFET. [54] En marcado contraste con sus predecesores SSI y MSI, la primera implementación LSI del PDP-11 contenía una CPU compuesta por solo cuatro circuitos integrados LSI. [55]
Desde que se introdujeron por primera vez los microprocesadores, han superado casi por completo todos los demás métodos de implementación de unidades centrales de procesamiento. El primer microprocesador disponible comercialmente, fabricado en 1971, fue el Intel 4004 , y el primer microprocesador ampliamente utilizado, fabricado en 1974, fue el Intel 8080. Los fabricantes de mainframes y minicomputadoras de la época lanzaron programas de desarrollo de circuitos integrados propietarios para actualizar sus arquitecturas informáticas más antiguas y, finalmente, produjeron microprocesadores compatibles con conjuntos de instrucciones que eran compatibles con versiones anteriores de su hardware y software más antiguos. Combinado con el advenimiento y el éxito final de la ubicua computadora personal , el término CPU ahora se aplica casi exclusivamente [a] a los microprocesadores. Se pueden combinar varias CPU (denominadas núcleos ) en un solo chip de procesamiento. [56]
Las generaciones anteriores de CPU se implementaron como componentes discretos y numerosos circuitos integrados pequeños (CI) en una o más placas de circuitos. [57] Los microprocesadores, por otro lado, son CPU fabricadas en una cantidad muy pequeña de CI; generalmente solo uno. [58] El tamaño general más pequeño de la CPU, como resultado de estar implementado en una sola matriz, significa un tiempo de conmutación más rápido debido a factores físicos como la disminución de la capacitancia parásita de la compuerta . [59] [60] Esto ha permitido que los microprocesadores síncronos tengan velocidades de reloj que van desde decenas de megahercios hasta varios gigahercios. Además, la capacidad de construir transistores extremadamente pequeños en un CI ha aumentado la complejidad y la cantidad de transistores en una sola CPU muchas veces. Esta tendencia ampliamente observada se describe mediante la ley de Moore , que había demostrado ser un predictor bastante preciso del crecimiento de la complejidad de la CPU (y otros CI) hasta 2016. [61] [62]
Si bien la complejidad, el tamaño, la construcción y la forma general de las CPU han cambiado enormemente desde 1950, [63] el diseño básico y la función no han cambiado mucho en absoluto. Casi todas las CPU comunes en la actualidad pueden describirse con mucha precisión como máquinas de programa almacenado de von Neumann. [64] [b] Como la ley de Moore ya no se cumple, han surgido preocupaciones sobre los límites de la tecnología de transistores de circuitos integrados. La miniaturización extrema de las puertas electrónicas está haciendo que los efectos de fenómenos como la electromigración y la fuga subumbral se vuelvan mucho más significativos. [66] [67] Estas preocupaciones más nuevas se encuentran entre los muchos factores que hacen que los investigadores investiguen nuevos métodos de computación como la computadora cuántica , así como para expandir el uso del paralelismo y otros métodos que extienden la utilidad del modelo clásico de von Neumann.
La operación fundamental de la mayoría de las CPU, independientemente de la forma física que adopten, es ejecutar una secuencia de instrucciones almacenadas que se denomina programa. Las instrucciones que se van a ejecutar se guardan en algún tipo de memoria de la computadora . Casi todas las CPU siguen los pasos de búsqueda, decodificación y ejecución en su funcionamiento, que se conocen colectivamente como ciclo de instrucción .
Después de la ejecución de una instrucción, todo el proceso se repite, y el siguiente ciclo de instrucción normalmente recupera la siguiente instrucción en la secuencia debido al valor incrementado en el contador de programa . Si se ejecutó una instrucción de salto, el contador de programa se modificará para contener la dirección de la instrucción a la que se saltó y la ejecución del programa continúa normalmente. En CPU más complejas, se pueden recuperar, decodificar y ejecutar múltiples instrucciones simultáneamente. Esta sección describe lo que generalmente se conoce como la " tubería RISC clásica ", que es bastante común entre las CPU simples que se utilizan en muchos dispositivos electrónicos (a menudo llamados microcontroladores). Ignora en gran medida el importante papel de la memoria caché de la CPU y, por lo tanto, la etapa de acceso de la tubería.
Algunas instrucciones manipulan el contador del programa en lugar de producir datos de resultados directamente; dichas instrucciones generalmente se denominan "saltos" y facilitan el comportamiento del programa como bucles , ejecución condicional del programa (a través del uso de un salto condicional) y existencia de funciones . [c] En algunos procesadores, algunas otras instrucciones cambian el estado de los bits en un registro de "banderas" . Estas banderas se pueden usar para influir en el comportamiento de un programa, ya que a menudo indican el resultado de varias operaciones. Por ejemplo, en dichos procesadores una instrucción de "comparación" evalúa dos valores y establece o borra bits en el registro de banderas para indicar cuál es mayor o si son iguales; una de estas banderas podría luego ser utilizada por una instrucción de salto posterior para determinar el flujo del programa.
La recuperación implica recuperar una instrucción (que está representada por un número o una secuencia de números) de la memoria del programa. La ubicación de la instrucción (dirección) en la memoria del programa está determinada por el contador de programa (PC; llamado "puntero de instrucción" en los microprocesadores Intel x86 ), que almacena un número que identifica la dirección de la siguiente instrucción que se recuperará. Después de que se recupera una instrucción, el PC se incrementa por la longitud de la instrucción para que contenga la dirección de la siguiente instrucción en la secuencia. [d] A menudo, la instrucción que se va a recuperar debe recuperarse de una memoria relativamente lenta, lo que hace que la CPU se detenga mientras espera que se devuelva la instrucción. Este problema se soluciona en gran medida en los procesadores modernos mediante cachés y arquitecturas de canalización (ver a continuación).
La instrucción que la CPU obtiene de la memoria determina lo que hará la CPU. En el paso de decodificación, realizado por un circuito decodificador binario conocido como decodificador de instrucciones , la instrucción se convierte en señales que controlan otras partes de la CPU.
La forma en que se interpreta la instrucción está definida por la arquitectura del conjunto de instrucciones (ISA) de la CPU. [e] A menudo, un grupo de bits (es decir, un "campo") dentro de la instrucción, llamado código de operación, indica qué operación se debe realizar, mientras que los campos restantes suelen proporcionar información complementaria necesaria para la operación, como los operandos. Esos operandos pueden especificarse como un valor constante (llamado valor inmediato) o como la ubicación de un valor que puede ser un registro del procesador o una dirección de memoria, según lo determine algún modo de direccionamiento .
En algunos diseños de CPU, el decodificador de instrucciones se implementa como un circuito decodificador binario cableado e inmutable. En otros, se utiliza un microprograma para traducir las instrucciones en conjuntos de señales de configuración de CPU que se aplican secuencialmente a lo largo de múltiples pulsos de reloj. En algunos casos, la memoria que almacena el microprograma es reescribible, lo que permite cambiar la forma en que la CPU decodifica las instrucciones.
Después de los pasos de búsqueda y decodificación, se lleva a cabo el paso de ejecución. Según la arquitectura de la CPU, puede consistir en una sola acción o en una secuencia de acciones. Durante cada acción, las señales de control habilitan o deshabilitan eléctricamente varias partes de la CPU para que puedan realizar la totalidad o parte de la operación deseada. Luego, la acción se completa, generalmente en respuesta a un pulso de reloj. Muy a menudo, los resultados se escriben en un registro interno de la CPU para que las instrucciones posteriores puedan acceder a ellos rápidamente. En otros casos, los resultados se pueden escribir en una memoria principal más lenta, pero menos costosa y de mayor capacidad .
Por ejemplo, si se debe ejecutar una instrucción que realiza una suma, se activan los registros que contienen operandos (números que se van a sumar), al igual que las partes de la unidad lógica aritmética (ALU) que realizan la suma. Cuando se produce el pulso de reloj, los operandos fluyen desde los registros de origen hacia la ALU, y la suma aparece en su salida. En los pulsos de reloj posteriores, se habilitan (y deshabilitan) otros componentes para mover la salida (la suma de la operación) al almacenamiento (por ejemplo, un registro o memoria). Si la suma resultante es demasiado grande (es decir, es mayor que el tamaño de palabra de salida de la ALU), se activará un indicador de desbordamiento aritmético, lo que influirá en la siguiente operación.
En los circuitos de una CPU hay un conjunto de operaciones básicas que puede realizar, llamadas conjunto de instrucciones . Estas operaciones pueden implicar, por ejemplo, sumar o restar dos números, comparar dos números o saltar a una parte diferente de un programa. Cada instrucción está representada por una combinación única de bits , conocida como código de operación en lenguaje de máquina . Mientras procesa una instrucción, la CPU decodifica el código de operación (a través de un decodificador binario ) en señales de control, que orquestan el comportamiento de la CPU. Una instrucción completa en lenguaje de máquina consta de un código de operación y, en muchos casos, bits adicionales que especifican argumentos para la operación (por ejemplo, los números que se sumarán en el caso de una operación de suma). Subiendo en la escala de complejidad, un programa en lenguaje de máquina es una colección de instrucciones en lenguaje de máquina que ejecuta la CPU.
La operación matemática real para cada instrucción la realiza un circuito lógico combinacional dentro del procesador de la CPU, conocido como unidad aritmético-lógica o ALU. En general, una CPU ejecuta una instrucción extrayéndola de la memoria, utilizando su ALU para realizar una operación y luego almacenando el resultado en la memoria. Además de las instrucciones para operaciones lógicas y matemáticas con números enteros, existen otras instrucciones de máquina, como las que se utilizan para cargar datos de la memoria y almacenarlos nuevamente, operaciones de ramificación y operaciones matemáticas con números de punto flotante realizadas por la unidad de punto flotante (FPU) de la CPU. [68]
La unidad de control (UC) es un componente de la CPU que dirige el funcionamiento del procesador. Indica a la memoria, la unidad aritmética y lógica y los dispositivos de entrada y salida de la computadora cómo responder a las instrucciones que se han enviado al procesador.
Dirige el funcionamiento de las otras unidades proporcionando señales de control y sincronización. La mayoría de los recursos informáticos son gestionados por la UC. Dirige el flujo de datos entre la CPU y los demás dispositivos. John von Neumann incluyó la unidad de control como parte de la arquitectura de von Neumann . En los diseños informáticos modernos, la unidad de control suele ser una parte interna de la CPU con su función y funcionamiento generales sin cambios desde su introducción. [69]
La unidad aritmético lógica (ALU) es un circuito digital dentro del procesador que realiza operaciones aritméticas de números enteros y operaciones lógicas bit a bit . Las entradas a la ALU son las palabras de datos sobre las que se va a operar (llamadas operandos ), información de estado de operaciones anteriores y un código de la unidad de control que indica qué operación se debe realizar. Según la instrucción que se esté ejecutando, los operandos pueden provenir de registros internos de la CPU , memoria externa o constantes generadas por la propia ALU.
Cuando todas las señales de entrada se han establecido y propagado a través de los circuitos de la ALU, el resultado de la operación realizada aparece en las salidas de la ALU. El resultado consta de una palabra de datos, que puede almacenarse en un registro o memoria, y de información de estado que normalmente se almacena en un registro interno especial de la CPU reservado para este fin.
Las CPU modernas generalmente contienen más de una ALU para mejorar el rendimiento.
La unidad de generación de direcciones (AGU), a veces también llamada unidad de cálculo de direcciones (ACU), [70] es una unidad de ejecución dentro de la CPU que calcula las direcciones que utiliza la CPU para acceder a la memoria principal . Al tener los cálculos de direcciones manejados por circuitos separados que operan en paralelo con el resto de la CPU, se puede reducir la cantidad de ciclos de CPU necesarios para ejecutar varias instrucciones de máquina , lo que genera mejoras en el rendimiento.
Al realizar diversas operaciones, las CPU necesitan calcular las direcciones de memoria necesarias para obtener datos de la memoria; por ejemplo, las posiciones en memoria de los elementos de la matriz deben calcularse antes de que la CPU pueda obtener los datos de las ubicaciones de memoria reales. Esos cálculos de generación de direcciones involucran diferentes operaciones aritméticas de números enteros , como suma, resta, operaciones de módulo o desplazamientos de bits . A menudo, el cálculo de una dirección de memoria involucra más de una instrucción de máquina de propósito general, que no necesariamente se decodifican y ejecutan rápidamente. Al incorporar una AGU en un diseño de CPU, junto con la introducción de instrucciones especializadas que usan la AGU, varios cálculos de generación de direcciones se pueden descargar del resto de la CPU y, a menudo, se pueden ejecutar rápidamente en un solo ciclo de CPU.
Las capacidades de una AGU dependen de una CPU en particular y de su arquitectura . Por lo tanto, algunas AGU implementan y exponen más operaciones de cálculo de direcciones, mientras que otras también incluyen instrucciones especializadas más avanzadas que pueden operar en múltiples operandos a la vez. Algunas arquitecturas de CPU incluyen múltiples AGU, por lo que se puede ejecutar más de una operación de cálculo de direcciones simultáneamente, lo que genera más mejoras de rendimiento debido a la naturaleza superescalar de los diseños de CPU avanzados. Por ejemplo, Intel incorpora múltiples AGU en sus microarquitecturas Sandy Bridge y Haswell , que aumentan el ancho de banda del subsistema de memoria de la CPU al permitir que se ejecuten múltiples instrucciones de acceso a la memoria en paralelo.
Muchos microprocesadores (en teléfonos inteligentes y computadoras de escritorio, portátiles y servidores) tienen una unidad de administración de memoria, que traduce direcciones lógicas en direcciones de RAM físicas, brindando protección de memoria y capacidades de paginación , útiles para la memoria virtual . Los procesadores más simples, especialmente los microcontroladores , generalmente no incluyen una MMU.
Una caché de CPU [71] es una caché de hardware utilizada por la unidad central de procesamiento (CPU) de una computadora para reducir el costo promedio (tiempo o energía) para acceder a los datos de la memoria principal . Una caché es una memoria más pequeña y rápida, más cercana a un núcleo de procesador , que almacena copias de los datos de las ubicaciones de memoria principal utilizadas con frecuencia . La mayoría de las CPU tienen diferentes cachés independientes, incluidos los cachés de instrucciones y datos , donde el caché de datos generalmente se organiza como una jerarquía de más niveles de caché (L1, L2, L3, L4, etc.).
Todas las CPU modernas (rápidas) (con pocas excepciones especializadas [f] ) tienen múltiples niveles de caché de CPU. Las primeras CPU que usaban una caché tenían solo un nivel de caché; a diferencia de las cachés de nivel 1 posteriores, no estaba dividida en L1d (para datos) y L1i (para instrucciones). Casi todas las CPU actuales con cachés tienen una caché L1 dividida. También tienen cachés L2 y, para procesadores más grandes, también cachés L3. La caché L2 generalmente no está dividida y actúa como un repositorio común para la caché L1 ya dividida. Cada núcleo de un procesador multinúcleo tiene una caché L2 dedicada y generalmente no se comparte entre los núcleos. La caché L3 y las cachés de nivel superior se comparten entre los núcleos y no se dividen. Una caché L4 actualmente es poco común y generalmente se encuentra en la memoria dinámica de acceso aleatorio (DRAM), en lugar de en la memoria estática de acceso aleatorio (SRAM), en una matriz o chip separado. Históricamente, esto también ha sucedido con L1, aunque los chips más grandes han permitido la integración de este y, en general, de todos los niveles de caché, con la posible excepción del último nivel. Cada nivel adicional de caché tiende a ser más grande y se optimiza de manera diferente.
Existen otros tipos de cachés (que no se cuentan dentro del "tamaño de caché" de los cachés más importantes mencionados anteriormente), como el búfer de búsqueda de traducción (TLB) que es parte de la unidad de administración de memoria (MMU) que tienen la mayoría de las CPU.
Los cachés generalmente se dimensionan en potencias de dos: 2, 8, 16, etc. KiB o MiB (para tamaños más grandes que no sean L1), aunque el IBM z13 tiene un caché de instrucciones L1 de 96 KiB. [72]
La mayoría de las CPU son circuitos síncronos , lo que significa que emplean una señal de reloj para marcar el ritmo de sus operaciones secuenciales. La señal de reloj es producida por un circuito oscilador externo que genera una cantidad constante de pulsos cada segundo en forma de onda cuadrada periódica . La frecuencia de los pulsos de reloj determina la velocidad a la que una CPU ejecuta instrucciones y, en consecuencia, cuanto más rápido sea el reloj, más instrucciones ejecutará la CPU cada segundo.
Para garantizar el funcionamiento correcto de la CPU, el período de reloj es más largo que el tiempo máximo necesario para que todas las señales se propaguen (se muevan) a través de la CPU. Al establecer el período de reloj en un valor muy por encima del retardo de propagación en el peor de los casos , es posible diseñar toda la CPU y la forma en que mueve los datos alrededor de los "bordes" de la señal de reloj ascendente y descendente. Esto tiene la ventaja de simplificar significativamente la CPU, tanto desde una perspectiva de diseño como desde una perspectiva de conteo de componentes. Sin embargo, también tiene la desventaja de que toda la CPU debe esperar a sus elementos más lentos, aunque algunas partes de ella sean mucho más rápidas. Esta limitación se ha compensado en gran medida con varios métodos para aumentar el paralelismo de la CPU (ver a continuación).
Sin embargo, las mejoras arquitectónicas por sí solas no resuelven todos los inconvenientes de las CPU globalmente sincrónicas. Por ejemplo, una señal de reloj está sujeta a los retrasos de cualquier otra señal eléctrica. Las frecuencias de reloj más altas en CPU cada vez más complejas hacen que sea más difícil mantener la señal de reloj en fase (sincronizada) en toda la unidad. Esto ha llevado a que muchas CPU modernas requieran que se proporcionen múltiples señales de reloj idénticas para evitar retrasar una sola señal lo suficiente como para provocar un mal funcionamiento de la CPU. Otro problema importante, a medida que las frecuencias de reloj aumentan drásticamente, es la cantidad de calor que disipa la CPU . El reloj en constante cambio hace que muchos componentes cambien independientemente de si se están utilizando en ese momento. En general, un componente que está cambiando utiliza más energía que un elemento en estado estático. Por lo tanto, a medida que aumenta la frecuencia de reloj, también lo hace el consumo de energía, lo que hace que la CPU requiera una mayor disipación de calor en forma de soluciones de refrigeración de CPU .
Un método para lidiar con la conmutación de componentes innecesarios se llama control de reloj , que implica apagar la señal de reloj a los componentes innecesarios (deshabilitándolos efectivamente). Sin embargo, esto a menudo se considera difícil de implementar y, por lo tanto, no se usa comúnmente fuera de los diseños de muy bajo consumo. Un diseño de CPU reciente notable que usa control de reloj extensivo es el Xenon basado en IBM PowerPC utilizado en la Xbox 360 ; esto reduce los requisitos de energía de la Xbox 360. [73]
Otro método para abordar algunos de los problemas con una señal de reloj global es la eliminación total de la señal de reloj. Si bien la eliminación de la señal de reloj global hace que el proceso de diseño sea considerablemente más complejo en muchos sentidos, los diseños asincrónicos (o sin reloj) conllevan marcadas ventajas en el consumo de energía y la disipación de calor en comparación con diseños sincrónicos similares. Si bien es poco común, se han construido CPU asincrónicas completas sin utilizar una señal de reloj global. Dos ejemplos notables de esto son el AMULET compatible con ARM y el MiniMIPS compatible con MIPS R3000. [74]
En lugar de eliminar totalmente la señal de reloj, algunos diseños de CPU permiten que ciertas partes del dispositivo sean asincrónicas, como el uso de ALU asincrónicas junto con la segmentación superescalar para lograr algunas ganancias en el rendimiento aritmético. Si bien no está del todo claro si los diseños totalmente asincrónicos pueden funcionar a un nivel comparable o mejor que sus contrapartes sincrónicas, es evidente que al menos se destacan en operaciones matemáticas más simples. Esto, combinado con sus excelentes propiedades de consumo de energía y disipación de calor, los hace muy adecuados para computadoras integradas . [75]
Muchas CPU modernas tienen un módulo de administración de energía integrado que regula el suministro de voltaje según demanda a los circuitos de la CPU, lo que le permite mantener el equilibrio entre el rendimiento y el consumo de energía.
Cada CPU representa valores numéricos de una manera específica. Por ejemplo, algunas de las primeras computadoras digitales representaban los números como valores del sistema numérico decimal (base 10) y otras empleaban representaciones más inusuales, como el ternario (base tres). Casi todas las CPU modernas representan los números en forma binaria , y cada dígito se representa mediante una cantidad física de dos valores, como un voltaje "alto" o "bajo" . [g]
Relacionado con la representación numérica está el tamaño y la precisión de los números enteros que una CPU puede representar. En el caso de una CPU binaria, esto se mide por la cantidad de bits (dígitos significativos de un entero codificado en binario) que la CPU puede procesar en una operación, lo que comúnmente se denomina tamaño de palabra , ancho de bit , ancho de ruta de datos , precisión de entero o tamaño de entero . El tamaño de entero de una CPU determina el rango de valores enteros en los que puede operar directamente. [h] Por ejemplo, una CPU de 8 bits puede manipular directamente números enteros representados por ocho bits, que tienen un rango de 256 (2 8 ) valores enteros discretos.
El rango de números enteros también puede afectar la cantidad de ubicaciones de memoria a las que la CPU puede acceder directamente (una dirección es un valor entero que representa una ubicación de memoria específica). Por ejemplo, si una CPU binaria utiliza 32 bits para representar una dirección de memoria, entonces puede acceder directamente a 232 ubicaciones de memoria. Para evitar esta limitación y por varias otras razones, algunas CPU utilizan mecanismos (como la conmutación de bancos ) que permiten acceder a memoria adicional.
Las CPU con tamaños de palabra más grandes requieren más circuitos y, en consecuencia, son físicamente más grandes, cuestan más y consumen más energía (y, por lo tanto, generan más calor). Como resultado, en las aplicaciones modernas se utilizan comúnmente microcontroladores más pequeños de 4 u 8 bits , aunque hay CPU con tamaños de palabra mucho más grandes (como 16, 32, 64 e incluso 128 bits). Sin embargo, cuando se requiere un mayor rendimiento, los beneficios de un tamaño de palabra más grande (rangos de datos y espacios de direcciones más grandes) pueden superar las desventajas. Una CPU puede tener rutas de datos internas más cortas que el tamaño de la palabra para reducir el tamaño y el costo. Por ejemplo, aunque la arquitectura del conjunto de instrucciones del IBM System/360 era un conjunto de instrucciones de 32 bits, el System/360 Modelo 30 y el Modelo 40 tenían rutas de datos de 8 bits en la unidad lógica aritmética, de modo que una suma de 32 bits requería cuatro ciclos, uno por cada 8 bits de los operandos, y, aunque el conjunto de instrucciones de la serie Motorola 68000 era un conjunto de instrucciones de 32 bits, el Motorola 68000 y el Motorola 68010 tenían rutas de datos de 16 bits en la unidad lógica aritmética, de modo que una suma de 32 bits requería dos ciclos.
Para obtener algunas de las ventajas que ofrecen las longitudes de bits más bajas y más altas, muchos conjuntos de instrucciones tienen diferentes anchos de bits para datos enteros y de punto flotante, lo que permite que las CPU que implementan ese conjunto de instrucciones tengan diferentes anchos de bits para diferentes partes del dispositivo. Por ejemplo, el conjunto de instrucciones IBM System/360 era principalmente de 32 bits, pero admitía valores de punto flotante de 64 bits para facilitar una mayor precisión y rango en números de punto flotante. [37] El System/360 Modelo 65 tenía un sumador de 8 bits para aritmética binaria decimal y de punto fijo y un sumador de 60 bits para aritmética de punto flotante. [76] Muchos diseños de CPU posteriores usan un ancho de bits mixto similar, especialmente cuando el procesador está destinado a un uso de propósito general donde se requiere un equilibrio razonable de capacidad de números enteros y de punto flotante.
La descripción del funcionamiento básico de una CPU ofrecida en la sección anterior describe la forma más simple que puede adoptar una CPU. Este tipo de CPU, generalmente denominada subescalar , opera y ejecuta una instrucción sobre uno o dos datos a la vez, es decir, menos de una instrucción por ciclo de reloj ( IPC < 1 ).
Este proceso da lugar a una ineficiencia inherente en las CPU subescalares. Dado que sólo se ejecuta una instrucción a la vez, toda la CPU debe esperar a que esa instrucción se complete antes de proceder a la siguiente instrucción. Como resultado, la CPU subescalar se "cuelga" en instrucciones que tardan más de un ciclo de reloj en completar su ejecución. Incluso añadir una segunda unidad de ejecución (ver más abajo) no mejora mucho el rendimiento; en lugar de que se cuelgue una vía, ahora se cuelgan dos vías y aumenta la cantidad de transistores sin usar. Este diseño, en el que los recursos de ejecución de la CPU pueden operar sólo en una instrucción a la vez, sólo puede alcanzar un rendimiento escalar (una instrucción por ciclo de reloj, IPC = 1 ). Sin embargo, el rendimiento es casi siempre subescalar (menos de una instrucción por ciclo de reloj, IPC < 1 ).
Los intentos de lograr un rendimiento escalar y mejor han dado como resultado una variedad de metodologías de diseño que hacen que la CPU se comporte de manera menos lineal y más en paralelo. Cuando se hace referencia al paralelismo en las CPU, generalmente se utilizan dos términos para clasificar estas técnicas de diseño:
Cada metodología difiere tanto en las formas en que se implementan, como en la efectividad relativa que brindan para aumentar el rendimiento de la CPU para una aplicación. [i]
Uno de los métodos más simples para aumentar el paralelismo es comenzar los primeros pasos de obtención y decodificación de instrucciones antes de que la instrucción anterior termine de ejecutarse. Esta es una técnica conocida como canalización de instrucciones y se utiliza en casi todas las CPU modernas de propósito general. La canalización permite ejecutar múltiples instrucciones a la vez dividiendo la ruta de ejecución en etapas discretas. Esta separación se puede comparar con una línea de ensamblaje, en la que una instrucción se va completando en cada etapa hasta que sale de la cadena de ejecución y se retira.
Sin embargo, la segmentación introduce la posibilidad de que se dé una situación en la que se necesite el resultado de la operación anterior para completar la siguiente, una condición que suele denominarse conflicto de dependencia de datos. Por lo tanto, los procesadores segmentados deben comprobar este tipo de condiciones y retrasar una parte de la segmentación si es necesario. Un procesador segmentado puede llegar a ser casi escalar, inhibido únicamente por bloqueos de la segmentación (una instrucción que pasa más de un ciclo de reloj en una etapa).
Las mejoras en la canalización de instrucciones llevaron a mayores reducciones en el tiempo de inactividad de los componentes de la CPU. Los diseños que se dice que son superescalares incluyen una larga canalización de instrucciones y múltiples unidades de ejecución idénticas , como unidades de carga y almacenamiento , unidades aritmético-lógicas , unidades de punto flotante y unidades de generación de direcciones . [77] En una canalización superescalar, las instrucciones se leen y pasan a un despachador, que decide si las instrucciones se pueden ejecutar o no en paralelo (simultáneamente). Si es así, se envían a las unidades de ejecución, lo que resulta en su ejecución simultánea. En general, la cantidad de instrucciones que una CPU superescalar completará en un ciclo depende de la cantidad de instrucciones que puede enviar simultáneamente a las unidades de ejecución.
La mayor parte de la dificultad en el diseño de una arquitectura de CPU superescalar radica en la creación de un despachador efectivo. El despachador debe ser capaz de determinar rápidamente si las instrucciones se pueden ejecutar en paralelo, así como despacharlas de tal manera que mantenga ocupadas tantas unidades de ejecución como sea posible. Esto requiere que la secuencia de instrucciones se llene con la mayor frecuencia posible y requiere cantidades significativas de caché de CPU . También hace que las técnicas para evitar riesgos como la predicción de bifurcaciones , la ejecución especulativa , el cambio de nombre de registros , la ejecución fuera de orden y la memoria transaccional sean cruciales para mantener altos niveles de rendimiento. Al intentar predecir qué bifurcación (o ruta) tomará una instrucción condicional, la CPU puede minimizar la cantidad de veces que toda la secuencia debe esperar hasta que se complete una instrucción condicional. La ejecución especulativa a menudo proporciona aumentos de rendimiento modestos al ejecutar partes de código que pueden no ser necesarias después de que se complete una operación condicional. La ejecución fuera de orden reorganiza un poco el orden en el que se ejecutan las instrucciones para reducir los retrasos debido a las dependencias de datos. También en el caso de un flujo de instrucciones único o de múltiples flujos de datos , un caso en el que se deben procesar muchos datos del mismo tipo, los procesadores modernos pueden deshabilitar partes de la cadena de procesamiento de modo que cuando una sola instrucción se ejecuta muchas veces, la CPU omite las fases de búsqueda y decodificación y, por lo tanto, aumenta enormemente el rendimiento en ciertas ocasiones, especialmente en motores de programas altamente monótonos como el software de creación de videos y el procesamiento de fotografías.
Cuando una fracción de la CPU es superescalar, la parte que no lo es sufre una penalización de rendimiento debido a bloqueos de programación. El Intel P5 Pentium tenía dos ALU superescalares que podían aceptar una instrucción por ciclo de reloj cada una, pero su FPU no. Por lo tanto, el P5 era superescalar entero pero no superescalar de punto flotante. El sucesor de Intel de la arquitectura P5, P6 , agregó capacidades superescalares a sus características de punto flotante.
El diseño superescalar y de canalización simple aumenta el ILP de una CPU al permitirle ejecutar instrucciones a tasas que superan una instrucción por ciclo de reloj. La mayoría de los diseños de CPU modernos son al menos algo superescalares, y casi todas las CPU de propósito general diseñadas en la última década son superescalares. En los últimos años, parte del énfasis en el diseño de computadoras con alto ILP se ha trasladado del hardware de la CPU a su interfaz de software, o arquitectura del conjunto de instrucciones (ISA). La estrategia de la palabra de instrucción muy larga (VLIW) hace que parte del ILP quede implícito directamente en el software, lo que reduce el trabajo de la CPU para aumentar el ILP y, por lo tanto, reduce la complejidad del diseño.
Otra estrategia para lograr el rendimiento es ejecutar múltiples hilos o procesos en paralelo. Esta área de investigación se conoce como computación paralela . [78] En la taxonomía de Flynn , esta estrategia se conoce como flujo de instrucciones múltiples, flujo de datos múltiples (MIMD, por sus siglas en inglés). [79]
Una tecnología utilizada para este propósito es el multiprocesamiento (MP). [80] El tipo inicial de esta tecnología se conoce como multiprocesamiento simétrico (SMP), donde un pequeño número de CPU comparten una vista coherente de su sistema de memoria. En este esquema, cada CPU tiene hardware adicional para mantener una vista constantemente actualizada de la memoria. Al evitar vistas obsoletas de la memoria, las CPU pueden cooperar en el mismo programa y los programas pueden migrar de una CPU a otra. Para aumentar el número de CPU cooperantes más allá de un puñado, se introdujeron esquemas como el acceso a memoria no uniforme (NUMA) y los protocolos de coherencia basados en directorios en la década de 1990. Los sistemas SMP están limitados 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ó utilizando múltiples CPU y placas discretas para implementar la interconexión entre los procesadores. Cuando los procesadores y su interconexión se implementan todos en un solo chip, la tecnología se conoce como multiprocesamiento a nivel de chip (CMP) y el chip como procesador multinúcleo .
Más tarde se reconoció que existía un paralelismo de grano más fino con un solo programa. Un solo programa podría tener varios subprocesos (o funciones) que podrían ejecutarse por separado o en paralelo. Algunos de los primeros ejemplos de esta tecnología implementaron el procesamiento de entrada/salida , como el acceso directo a la memoria como un subproceso separado del subproceso de cálculo. Un enfoque más general para esta tecnología se introdujo en la década de 1970, cuando se diseñaron sistemas para ejecutar múltiples subprocesos de cálculo en paralelo. Esta tecnología se conoce como multiprocesamiento (MT). El enfoque se considera más rentable que el multiprocesamiento, ya que solo se replica una pequeña cantidad de componentes dentro de una CPU para admitir MT en lugar de toda la CPU en el caso de MP. En MT, las unidades de ejecución y el sistema de memoria, incluidas las cachés, se comparten entre varios subprocesos. La desventaja de MT es que el soporte de hardware para multiproceso es más visible para el software que el de MP y, por lo tanto, el software supervisor, como los sistemas operativos, tienen que sufrir cambios más grandes para admitir MT. Un tipo de MT que se implementó se conoce como multihilo temporal , donde un hilo se ejecuta hasta que se detiene esperando que los datos regresen de la memoria externa. En este esquema, la CPU luego cambiaría rápidamente de contexto a otro hilo que esté listo para ejecutarse, el cambio a menudo se realiza en un ciclo de reloj de la CPU, como UltraSPARC T1 . Otro tipo de MT es el multihilo simultáneo , donde las instrucciones de múltiples hilos se ejecutan en paralelo dentro de un ciclo de reloj de la CPU.
Durante varias décadas, desde la década de 1970 hasta principios de la década de 2000, el enfoque en el diseño de CPU de propósito general de alto rendimiento se centró principalmente en lograr un ILP alto a través de tecnologías como canalización, cachés, ejecución superescalar, ejecución fuera de orden, etc. Esta tendencia culminó en CPU grandes y de alto consumo de energía como Intel Pentium 4. A principios de la década de 2000, los diseñadores de CPU se vieron frustrados en la tarea de lograr un mayor rendimiento a partir de técnicas ILP debido a la creciente disparidad entre las frecuencias de funcionamiento de la CPU y las frecuencias de funcionamiento de la memoria principal, así como a la creciente disipación de energía de la CPU debido a técnicas ILP más esotéricas.
Los diseñadores de CPU luego tomaron prestadas ideas de los mercados de computación comercial, como el procesamiento de transacciones , donde el rendimiento agregado de múltiples programas, también conocido como computación de rendimiento , era más importante que el rendimiento de un solo hilo o proceso.
Esta inversión de énfasis se evidencia en la proliferación de diseños de procesadores de doble núcleo y más núcleos y, en particular, en los diseños más nuevos de Intel que se asemejan a su arquitectura P6 menos superescalar. Los diseños más recientes de varias familias de procesadores presentan CMP, incluidos los x86-64 Opteron y Athlon 64 X2 , SPARC UltraSPARC T1 , IBM POWER4 y POWER5 , así como varias CPU de consolas de videojuegos como el diseño PowerPC de triple núcleo de Xbox 360 y el microprocesador Cell de 7 núcleos de PlayStation 3 .
Un paradigma menos común pero cada vez más importante de los procesadores (y de hecho, de la informática en general) se ocupa del paralelismo de datos. Todos los procesadores discutidos anteriormente se conocen como algún tipo de dispositivo escalar. [j] Como su nombre lo indica, los procesadores vectoriales tratan con múltiples piezas de datos en el contexto de una instrucción. Esto contrasta con los procesadores escalares, que tratan con una pieza de datos para cada instrucción. Usando la taxonomía de Flynn , estos dos esquemas de tratamiento de datos generalmente se conocen como flujo de instrucción única , flujo de datos múltiples ( SIMD ) y flujo de instrucción única , flujo de datos única ( SISD ), respectivamente. La gran utilidad en la creación de procesadores que tratan con vectores de datos radica en optimizar tareas que tienden a requerir que se realice la misma operación (por ejemplo, una suma o un producto escalar ) en un gran conjunto de datos. Algunos ejemplos clásicos de este tipo de tareas incluyen aplicaciones multimedia (imágenes, video y sonido), así como muchos tipos de tareas científicas y de ingeniería. Mientras que un procesador escalar debe completar todo el proceso de obtención, decodificación y ejecución de cada instrucción y valor en un conjunto de datos, un procesador vectorial puede realizar una sola operación en un conjunto de datos comparativamente grande con una sola instrucción. Esto solo es posible cuando la aplicación tiende a requerir muchos pasos que aplican una operación a un conjunto grande de datos.
La mayoría de los primeros procesadores vectoriales, como el Cray-1 , se asociaban casi exclusivamente con la investigación científica y las aplicaciones de criptografía . Sin embargo, a medida que el multimedia se ha desplazado en gran medida a los medios digitales, la necesidad de alguna forma de SIMD en los procesadores de propósito general se ha vuelto significativa. Poco después de que la inclusión de unidades de punto flotante comenzara a volverse algo común en los procesadores de propósito general, también comenzaron a aparecer especificaciones e implementaciones de unidades de ejecución SIMD para procesadores de propósito general. [ ¿cuándo? ] Algunas de estas primeras especificaciones SIMD, como Multimedia Acceleration eXtensions (MAX) de HP y MMX de Intel , eran solo de números enteros. Esto resultó ser un impedimento significativo para algunos desarrolladores de software, ya que muchas de las aplicaciones que se benefician de SIMD tratan principalmente con números de punto flotante . Progresivamente, los desarrolladores refinaron y rehicieron estos primeros diseños en algunas de las especificaciones SIMD modernas comunes, que generalmente se asocian con una arquitectura de conjunto de instrucciones (ISA). Algunos ejemplos modernos notables incluyen Streaming SIMD Extensions (SSE) de Intel y AltiVec relacionado con PowerPC (también conocido como VMX). [k]
Muchas arquitecturas modernas (incluidas las integradas) a menudo incluyen contadores de rendimiento de hardware (HPC), que permiten la recopilación, evaluación comparativa , depuración o análisis de bajo nivel (nivel de instrucción) de métricas de software en ejecución. [81] [82] El HPC también se puede utilizar para descubrir y analizar actividad inusual o sospechosa del software, como exploits de programación orientada al retorno (ROP) o programación orientada al retorno (SROP), etc. [83] Esto generalmente lo hacen los equipos de seguridad de software para evaluar y encontrar programas binarios maliciosos. [84]
Muchos proveedores importantes (como IBM , Intel , AMD y Arm ) proporcionan interfaces de software (generalmente escritas en C/C++) que se pueden usar para recopilar datos de los registros de la CPU con el fin de obtener métricas. [85] Los proveedores de sistemas operativos también proporcionan software como perf
(Linux) para registrar, evaluar o rastrear eventos de la CPU que ejecutan núcleos y aplicaciones.
Los contadores de hardware proporcionan un método de bajo consumo para recopilar métricas de rendimiento integrales relacionadas con los elementos centrales de una CPU (unidades funcionales, cachés, memoria principal, etc.), una ventaja significativa sobre los perfiladores de software. [86] Además, generalmente eliminan la necesidad de modificar el código fuente subyacente de un programa. [87] [88] Debido a que los diseños de hardware difieren entre arquitecturas, los tipos específicos y las interpretaciones de los contadores de hardware también cambiarán.
La mayoría de las CPU modernas tienen modos privilegiados para soportar sistemas operativos y virtualización.
La computación en la nube puede utilizar la virtualización para proporcionar unidades centrales de procesamiento virtuales [89] ( vCPU ) para usuarios separados. [90]
Un host es el equivalente virtual de una máquina física, en la que opera un sistema virtual. [91] Cuando hay varias máquinas físicas operando en tándem y administradas como un todo, los recursos de computación y memoria agrupados forman un clúster . En algunos sistemas, es posible agregar y quitar dinámicamente de un clúster. Los recursos disponibles a nivel de host y clúster se pueden dividir en grupos de recursos con granularidad fina .
El rendimiento o la velocidad de un procesador depende, entre muchos otros factores, de la frecuencia de reloj (generalmente expresada en múltiplos de hercios ) y de las instrucciones por reloj (IPC), que en conjunto son los factores de las instrucciones por segundo (IPS) que puede realizar la CPU. [92] Muchos valores IPS informados han representado tasas de ejecución "máximas" en secuencias de instrucciones artificiales con pocas ramificaciones, mientras que las cargas de trabajo realistas consisten en una mezcla de instrucciones y aplicaciones, algunas de las cuales tardan más en ejecutarse que otras. El rendimiento de la jerarquía de memoria también afecta en gran medida al rendimiento del procesador, un problema que apenas se considera en los cálculos IPS. Debido a estos problemas, se han desarrollado varias pruebas estandarizadas, a menudo llamadas "benchmarks" para este propósito, como SPECint , para intentar medir el rendimiento efectivo real en aplicaciones de uso común.
El rendimiento de procesamiento de las computadoras aumenta mediante el uso de procesadores multinúcleo , que esencialmente consiste en conectar dos o más procesadores individuales (llamados núcleos en este sentido) en un circuito integrado. [93] Idealmente, un procesador de doble núcleo sería casi el doble de potente que un procesador de un solo núcleo. En la práctica, la ganancia de rendimiento es mucho menor, solo alrededor del 50%, debido a algoritmos de software e implementación imperfectos. [94] Aumentar el número de núcleos en un procesador (es decir, doble núcleo, cuádruple núcleo, etc.) aumenta la carga de trabajo que se puede manejar. Esto significa que el procesador ahora puede manejar numerosos eventos asincrónicos, interrupciones, etc. que pueden afectar la CPU cuando se sobrecarga. Estos núcleos pueden considerarse como diferentes pisos en una planta de procesamiento, y cada piso maneja una tarea diferente. A veces, estos núcleos manejarán las mismas tareas que los núcleos adyacentes a ellos si un solo núcleo no es suficiente para manejar la información. Las CPU de múltiples núcleos mejoran la capacidad de una computadora para ejecutar varias tareas simultáneamente al proporcionar potencia de procesamiento adicional. Sin embargo, el aumento de velocidad no es directamente proporcional al número de núcleos añadidos, ya que los núcleos necesitan interactuar a través de canales específicos y esta comunicación entre núcleos consume una parte de la velocidad de procesamiento disponible. [95]
Debido a las capacidades específicas de las CPU modernas, como el subprocesamiento múltiple simultáneo y el procesamiento sin núcleo , que implican compartir los recursos reales de la CPU mientras se busca una mayor utilización, monitorear los niveles de rendimiento y el uso del hardware gradualmente se convirtió en una tarea más compleja. [96] Como respuesta, algunas CPU implementan lógica de hardware adicional que monitorea el uso real de varias partes de una CPU y proporciona varios contadores accesibles al software; un ejemplo es la tecnología Performance Counter Monitor de Intel . [9]
[...] en computación en la nube, donde varios componentes de software se ejecutan en un entorno virtual en el mismo servidor, un componente por máquina virtual (VM). A cada VM se le asigna una unidad central de procesamiento virtual [...] que es una fracción de la CPU del servidor.
Unidad central de procesamiento virtual (vCPU)[:] Subdivide las CPU físicas. Las instancias pueden utilizar esas divisiones.