¿Por qué los procesadores modernos usan pocos núcleos avanzados en lugar de muchos simples o una combinación híbrida de los dos?

Entiendo que la memoria es un gran cuello de botella en los sistemas informáticos modernos, pero ¿no puede un sistema con muchos núcleos simples ser más eficiente que uno con un número de núcleos avanzados de un solo dígito para algunas tareas?

Por lo que entiendo, una GPU es una versión extrema de esto, pero ¿no hay un término medio para ciertas tareas que necesitan una densidad/complejidad que se encuentre en algún lugar entre los dos extremos?

¡Sí, más núcleos y más paralelismo es más eficiente! Pero el límite del paralelismo de instrucciones útiles para el código general ha limitado el número útil de núcleos de CPU en las últimas décadas a un número tan bajo que no fue gran cosa hacer que todos estos núcleos fueran de "alto rendimiento". Con cada vez más conciencia sobre el paralelismo, se ven a) núcleos más amplios yb) muchos más núcleos recientemente... de hecho, hasta tal punto que la arquitectura más moderna de Intel utiliza el enfoque grande -pequeño (híbrido) y estoy seguro de que AMD adoptará algo similar durante esta década.
Término de búsqueda útil: Ley de Amdahl. Relevancia hoy: cuanto más parte de su carga de tareas sea inherentemente en serie, menor será el beneficio de tener núcleos paralelos. Cada carga es diferente.
¿Por qué desperdiciar el costo del silicio si puedo implementar el mismo rendimiento con un núcleo que consume un área mucho menor?
"¿ No puede un sistema con muchos núcleos simples ser más eficiente que uno con un número de núcleos avanzados de un solo dígito para algunas tareas ?" – Ahí está el quid de la cuestión: puede ser más eficiente para algunas tareas . Pero no es más eficiente para la mayoría de las tareas, incluidas las que normalmente se ejecutan en las máquinas principales.
Puede tener muchos núcleos simples y puede hacer toda la división paralela de tareas (si es posible y cuando sea posible), pero luego llega el momento de volver a juntar todos los resultados [así como distribuir las nuevas entradas a los núcleos]. La memoria (prácticamente) subdividida necesita mantener la sincronización. y el rendimiento sufre. La comunicación y la sincronización entre los núcleos principal/auxiliar se convierte en el cuello de botella. Una GPU se beneficia de más núcleos o más simples, ya que la mayoría de sus tareas tienen el mismo aspecto (para las cuales las GPU tienen unidades de procesamiento especializadas). Para una CPU general, ese no es un caso de uso frecuente.

Respuestas (7)

  1. La programación para el paralelismo es difícil, por lo que la mayoría de las cosas se realizan en gran parte de forma secuencial, lo que requiere procesadores más complejos. El límite de reloj evita que los procesadores se vuelvan mucho más complejos, por lo que en su lugar tenemos varios procesadores complejos que principalmente permiten ejecutar tareas independientes simultáneamente o permiten que una sola tarea se divida en varios subprocesos simultáneos cuando es realmente obvio y simple de hacer. entonces.

  2. Debido a que la programación para el paralelismo es difícil, se puede predecir con bastante precisión cuándo se invertirá el esfuerzo adicional para el paralelismo masivo en el lado de la programación (es decir, dónde se necesita realmente). Esto hace que sea más fácil apuntar exactamente a quién realmente se molestará en hacer trabajo en paralelo con muchos núcleos simples, por lo que termina con CPU de propósito general con menos núcleos complejos y GPU de propósito especial con una gran cantidad de núcleos más simples.

  3. El desarrollo es costoso, por lo que necesita un mercado lo suficientemente grande para respaldar el desarrollo de un procesador multinúcleo mixto o de complejidad media.

¡Sí! Tantas veces si. Complementé esta excelente respuesta con mi punto de vista sobre lo que son estos procesadores de muchos núcleos de complejidad "intermedia", hoy.

Por lo que entiendo, una GPU es una versión extrema de esto, pero ¿no hay un término medio para ciertas tareas que necesitan una densidad/complejidad que se encuentre en algún lugar entre los dos extremos?

Las GPU modernas son ese término medio. Mientras que las GPU anteriores eran realmente simples "una instrucción, datos diferentes, todos esperan hasta que se haga la más lenta, la siguiente instrucción" con solo conjuntos de instrucciones muy limitados, las unidades de cómputo de las GPU modernas son mucho más generales e independientes.

Hubo múltiples (si no muchos) intentos de hacer esto antes, y aparte del uso de nicho, todos fallaron debido a que no cayeron en el punto óptimo de las CPU independientes de alto rendimiento ni en las unidades de sombreado simplistas masivamente paralelas baratas y de bajo consumo. Básicamente, debe ser eficiente tanto con el tiempo de su CPU como con el ancho de banda de su memoria, y eso significa que necesita pocos núcleos, pero de alto rendimiento, que compartan la memoria principal pero que tengan extensos cachés locales, o que necesite muchos núcleos más simples, pero orquestados centralmente. Ha demostrado que realmente no se pueden tener ambos fácilmente, que es (mi interpretación de) por qué el mundo tardó tanto en llegar a las GPU modernas y por qué solo dos empresas dominan el mercado de GPGPU de manera muy clara, con un líder claro.

Ejemplos de estos fracasos comerciales incluyen:

  • teraescala de Intel
  • Intel Larrabee¹
  • Tilera azulejo64
  • IBM kilocore

¹ Larrabee usó núcleos x86 muy poco eficientes en un procesador de muchos núcleos y, por lo tanto, era un término medio e inútil, tomado por GPU por un lado y CPU clásicas de estación de trabajo/servidor por el otro, aunque se podría argumentar que su sucesor, el Xeon Phi, tiene un mejor destino, pero estos realmente son más como muchos poderosos x86-64 que incluyen AVX-512 en un solo chip, por lo que no es el término medio que esperas. La serie se descontinuó el año pasado, principalmente debido a la falta de demanda: las GPU por un lado, las clásicas x86-64 por el otro simplemente son más útiles y tienen mejor cálculo por vatio.

Los girocópteros del mundo del silicio.
También hay que tener en cuenta: la mayoría de las veces se encuentran GPU que conviven con CPU con esos núcleos de alto rendimiento. Simplemente no construye una computadora completa con GPU, porque si bien pueden hacer algunas cosas muy rápido, aún necesitan CPU para dirigir la dirección general de la aplicación.
@TimWescott también es muy cierto, pero el papel de las CPU en la computación de alto rendimiento basada en paletas de GPU: las GPU del centro de datos combinadas con las tarjetas de red adecuadas pueden hacer cosas como tomar transferencias de datos directamente de la red, hacer el cálculo de la GPU y devolver el resultado out – sin ningún preámbulo de la CPU (aparte de inicializar todo). Esto se alinea muy bien con los paradigmas de programación como se ve en TensorFlow y PyTorch, donde su desarrollo computacional se realiza en un lenguaje de secuencias de comandos que al final compila un gráfico de flujo de datos para la GPU, de modo que la CPU no participa en el cálculo real.
Los nuevos chips de Intel podrían ser una nueva mejora. Combinación de núcleos complejos y núcleos simples para descargar diferentes tipos de trabajo en lugar de simplemente un número de los mismos núcleos.
@Nelson, sí, se están subiendo al pequeño GRAN carro en el que los procesadores de aplicaciones de gama alta del brazo han estado montando durante una década. pero considero que estos enfoques son básicamente idénticos a "unos pocos procesadores pesados", y lejos de "un mar de pequeños procesadores idénticos"; es realmente un matiz.

Me gustaría llevar el desafío del marco más allá de las otras respuestas aquí. Hasta finales del siglo XX, la computación paralela era el dominio de servidores especializados y supercomputadoras; Las computadoras de consumo de uso general se basaban en un solo núcleo de procesador que funcionaba a velocidades de reloj cada vez más rápidas. Desde entonces, los procesadores de múltiples núcleos se han convertido en la norma y la cantidad de núcleos incluidos ha aumentado lentamente.

Las arquitecturas modernas pueden incluir (incluso en un solo chip):

  • Núcleos de CPU de bajo consumo
  • Núcleos de CPU de alta potencia que se pueden apagar cuando no se usan
  • Unidades de computación paralelas dispuestas en una GPU

No obstante, una gran cantidad de software solo puede hacer uso de un solo núcleo, por lo que es probable que los núcleos de CPU de uso general no desaparezcan pronto. Eso es porque solo puede hacer uso de múltiples núcleos en ciertos casos seleccionados:

  • Tiene muchos datos que desea procesar de manera similar. Esto es para lo que están optimizadas las GPU, porque las tareas gráficas a menudo tienen muchos elementos que necesitan el mismo procesamiento relativamente simple. Ha demostrado ser útil en el aprendizaje automático.
  • Tiene múltiples tareas que son en gran medida independientes entre sí. Ejecutar varios programas en un sistema operativo de escritorio parece que entraría en esta categoría, pero la mayoría de los programas pasan mucho tiempo esperando una entrada externa de todos modos, por lo que simplemente pueden compartir el tiempo en el mismo procesador. Dentro de un solo programa, a menudo hay mucha complejidad para identificar qué instrucciones se pueden ejecutar en paralelo (o fuera de secuencia) y sincronizar tareas de manera segura.

Algunas tareas se prestan al paralelismo, otras no. En términos generales, las tareas que tienden a ser repetitivas con mucho tiempo invertido en bucles se pueden dividir en subtareas más pequeñas, organizadas por el host. Las tareas que tienden a ser 'filosas' con muchas ramas no son tan fáciles de dividir.

Los gráficos y la IA son ejemplos que se pueden dividir en tareas paralelas. TCP/IP, no tanto.

El punto es que hay un lugar para ambos.

Dado que TCP/IP es intrínsecamente capaz de descomponerse en conexiones individuales, diría que TCP/IP de hecho es bastante bueno para paralelizarse. En un servidor web, puede paralelizar no solo el trabajo del encabezado TCP, etc., sino también la compresión/descompresión y el cifrado/descifrado. A menos que esté hablando de una cantidad muy pequeña de conexiones de alto rendimiento, en cuyo caso estoy de acuerdo (pero ese no es el caso de uso típico del servidor).
Mi experiencia con esto es mezclar TCP/IP con procesamiento de medios en una arquitectura VLIW. No funcionó tan bien. gen2 utilizó un enfoque híbrido VLIW + ARM.
Un VLIW requiere un paralelismo de nivel de instrucción a muy pequeña escala para funcionar bien. @abligh está hablando sobre el paralelismo a nivel de subprocesos disponible desde múltiples conexiones TCP que hacen que múltiples núcleos sean útiles, como la pregunta. Pero TCP/IP en sí mismo es tan liviano que no necesita un núcleo completo por conexión, por lo que, a menos que tenga mucho trabajo por hacer (como cifrado/descifrado y (des)compresión), no es algo que necesite o desee. un SPARC Niagara o Xeon Phi para. Aún así, las conexiones múltiples distribuyen el rendimiento entre los núcleos fácilmente.

Umm, las GPU no son "una versión extrema de un sistema con muchos núcleos simples". Por ejemplo, en una GPU Nvidia, cada SM (multiprocesador de transmisión) es un procesador altamente multiproceso. La ruta de datos es IIRC 16 carriles, cada uno capaz de cálculos de punto flotante de 32 bits. La programación de subprocesos múltiples de una GPU es mucho más sofisticada que la programación de una CPU MT, y podría decirse que es comparable a la de un programador OOO ILP.

La gran diferencia es que una CPU OOO necesita tomar muchas decisiones de programación diferentes en cada ciclo que afectan los próximos 1-3 ciclos. Decisiones de programación muy diferentes para cada instrucción. Mientras que la decisión de programación de la GPU se aplica a ese conjunto de 16 ALU de ancho en el espacio, también normalmente de 2 a 4 ciclos de profundidad en el tiempo. Además, en lugar de programar una instrucción dependiente 1 o 2 ciclos más tarde, en una GPU, la siguiente instrucción dependiente del mismo hilo solo puede llegar muchos ciclos más tarde, ¡en algunas GPU no antes de los 40 ciclos! Entre los programas de GPU, las operaciones agrupan otros subprocesos. Sin embargo, cada vez más, incluso las cargas de trabajo masivamente paralelas de una GPU no tienen suficiente paralelismo,

Es decir, la mayor diferencia entre CPU y GPU SM es que el SM amortiza el costo de la lógica de control sobre muchos elementos lockstep por subproceso/warp, y muchos subprocesos/warps de flujo de control independientes dentro del mismo procesador.

Además, por supuesto, una GPU tiene múltiples elementos de procesamiento. Muchos más en un solo chip que las CPU.

En general, las GPU tienen una proporción mucho más baja si controlan la lógica para calcular/lógica ALU que las CPU. La lógica de control de la GPU es bastante sofisticada, pero su costo se distribuye, amortiza, entre más ALU, porque en una GPU muchas de las ALU están haciendo casi exactamente lo mismo al mismo tiempo.

Pero no estoy respondiendo a tu pregunta, ¿verdad? Usted preguntó "¿por qué no muchos procesadores simples, en lugar de los grandes y complicados procesadores únicos..."?

El nombre de "muchos procesadores independientes" es MIMD. Múltiples Instrucción Múltiples Datos”. Ahora, una GPU es MIMD, pero cada uno de sus procesadores independientes es SIMD lockstep y MT multiproceso.

Creo que está preguntando sobre "muchos procesadores simples independientes". Un MIMD cuyos procesadores independientes son, digamos, inky de 32 o 64 bits de ancho, no multiproceso, no suoerscakar y no OOO. Me gusta llamar a esto un MIMD (1), mientras que una GPU es un MIMD (SIMD (16x2) * MT (...))

Entonces: aquí es donde una GPU supera a una MIMD-1: la MIMD-1 tiene al menos 16 veces más lógica de control, proporcionalmente, que la simple GPU MIMd (SIMD (32)), incluso suponiendo que los núcleos GPZu no son MT o ILP . Es decir, la GPU desperdicia solo 1/16 del área y la lógica de control de encendido que el MIMD-1.

—-

Pero nuevamente, no está preguntando por qué una GPU supera a un MIMD-1 masivamente paralelo. Está preguntando por qué una máquina paralela masiva con elementos de procesamiento MIMD-1 simples no supera a una máquina cuyos elementos de procesamiento son mucho más complicados. Quizás 16 o 1024x más complicado, por lo que solo puede tener 1/16 - 1/1024 si los procesadores. Digamos, "solo" 8 CPU por chip, frente a quizás 128 o incluso 8K MIMD-1 en el mismo chip.

Bueno, el MPP-MIMD-1 superaría a la máquina con núcleos mucho más complicados, exactamente para las mismas cargas de trabajo que la GPU supera a la máquina MIMD-1. Así que el MIMD-1 queda exprimido.

Y para otras cargas de trabajo… bueno, si no hay suficiente paralelismo para usar todos los procesadores simples MIMD-1, las grandes CPU lo superan. E incluso si hay suficiente paralelismo, pero si el tipo irregular que las GPU no pueden hacer bien, bueno, entonces los núcleos MIMD-1 probablemente estén pasando mucho tiempo esperando memoria.

Además, para el caso, si tiene 16 veces más procesadores MIMD-1 que CPU grandes, tiene 16 veces más cables que van a la memoria. Lo que carcome esa supuesta ventaja de 16x.

Por ejemplo, un MIMD-1 MPP vencería a una máquina menos paralela de gran CPU, en una carga de trabajo que tuviera suficiente paralelismo, si la memoria fuera libre, con latencia de 1 ciclo y si los cables de memoria no costaran nada. O, de manera equivalente, si cada uno de los MIMD-1 accedió a la memoria privada solamente. Si las puertas lógicas fueran mucho más grandes que los cables... pero cuando el área de cableado y la potencia dominan la lógica real, los MIMD-1 pierden cada vez más terreno ante menos CPU paralelas más grandes.

—-

Todavía puede haber un lugar para los MPP MIMD-1, pero está apretado entre las GPU y las CPU grandes que no son GPU.

—-

Demasiado para las malas noticias. Ahora las buenas noticias:

Los programadores prefieren pensar en CPU MIMD completamente independientes a pensar en compensaciones complejas entre MIMD, SIMD y MT.

De hecho, el modelo histórico de programación de GPU consistía en tratar cada uno de los subprocesos de carril de bloqueo dentro de una deformación de flujo de control como un MIMD-1 independiente.

Por el contrario, otro modelo de programación con el que los humanos parecen sentirse cómodos es un solo hilo de control, pero con operaciones paralelas de datos, como operar en matrices arbitrarias. Básicamente, un procesador vectorial. Pero, de nuevo, a los humanos les gustan los vectores y matrices arbitrarios, y no les gusta tener que preocuparse por sintonizar diferentes números de elementos vectoriales, etc.

En muchos sentidos, una GPU es solo una forma de tomar el código MIMD-1 y ejecutarlo en una microarquitectura menos costosa que comparte la lógica de control entre lo que de otro modo serían elementos de procesamiento independientes.

Es decir, la buena noticia es que su modelo de "muchos procesadores simples" gana en algunos dominios, pero como un concepto de modelo de software o programación, uno que implementamos de manera más eficiente ya sea por una GPU o menos microarquitecturas paralelas pero más ILP/MLP.

Aquí hay mucha información buena, pero la respuesta tiene muy poca estructura para ser comprensible en mi opinión. Le sugiero que dedique algún tiempo a corregirlo/reorganizarlo. Creo que también se salta un poco el papel de los compiladores. De hecho, los desarrolladores capacitados en lenguajes clásicos como C a veces pueden no pensar en paralelo. Pero en estos casos hay compiladores que se encargan de eso. educar a millones de desarrolladores es un problema más difícil que optimizar compiladores. Las CPU obtienen cada vez más paralelismo (intracore e intercore) porque los compiladores mejoran.
Oh, un punto interesante sobre los tamaños de las puertas lógicas y los cables. ¿Es esa parte de la razón por la que diseños como UltraSPARC T1 Niagara eran viables y útiles para algunas cargas de trabajo en 2005? O simplemente que sus 8 núcleos eran un buen número en cuanto a interconexiones, y es un número de núcleos bastante modesto según los estándares actuales. ¿Pero en 2005 tenían que ser simples para encajar tantos en un chip? (Y convertirlos en procesadores de barril para ocultar la latencia era una forma de obtener un rendimiento decente en muchos subprocesos de procesadores más simples, ya que la idea era apoyarse en subprocesos).
@PeterCordes: No me di cuenta de que Niagara era bueno para nada. :-). Está bien, estoy siendo un poco sarcástico, en parte solo para modificar a la gente del Niágara que conozco. Mi punto sobre la escala de puerta versus cable es AFAIK más aplicable a la diferencia entre las décadas de 1960 y 1980 y en la actualidad. Tendría que comprobarlo, pero no creo que la proporción haya cambiado tanto desde 2005. Aunque las tendencias continúan, todo lo relacionado con la tecnología de procesos se ha ralentizado en los últimos años.
Está bien. Sabía que la resistencia de los cables y el retraso de la propagación eran un desafío cada vez mayor a medida que los procesos se encogían, por ejemplo, realworldtech.com/shrinking-cpu/4 de 2004, ya que la resistencia aumenta con el área/longitud, por lo que aumenta si todo se encoge de manera uniforme, aunque los cables sean más cortos . (Tampoco tengo evidencia directa de que Niagara sea bueno para nada, pero supongo que al menos estuvo bien en las cargas de trabajo para las que fue diseñado específicamente, si no mucho más. :P Las CPU que son ejemplos interesantes a menudo son ejemplos de "nunca vayas full <xyz>", como Alpha con su falta de carga/almacenamiento de bytes :P)
@tobalt: tienes razón, mi respuesta es más una diatriba. Me cansa mucho que la gente diga que las GPU son ejemplos de muchos procesadores simples. Supongo que, y algunos otros, una declaración tan simple, o un resumen más útil. Me ocuparé de eso en mi abundante tiempo libre.
Solo estaba haciendo una sugerencia para mejorar ... Si debido a la falta de tiempo no es una opción, entonces prefiero leer un texto más profundo y menos estructurado en lugar de una respuesta simple y trivial, así que déjelo. 😊 Después de todo, si los lectores están interesados, pueden leerlo varias veces o completar las partes que faltan con su propia investigación.

Los algoritmos, las pruebas, los procesos de pensamiento tienden a ser una lista de cosas para hacer en secuencia. El cerebro humano puede ser un procesador masivamente paralelo, pero las cosas que hace en paralelo no son tanto procesos de pensamiento conscientes sino habilidades adquiridas. Como consecuencia, las descripciones de lo que debería estar haciendo una computadora tienden a estar estructuradas de una manera comparativamente lineal, y los conjuntos de instrucciones de la computadora están estructurados en pasos secuenciales en lugar de un conjunto de tareas que deben realizarse con cierta interdependencia. Las arquitecturas superescalares en realidad paralelizan algunas cosas mientras descubren la interdependencia, y la arquitectura MIPS original ("Microprocesador sin etapas de canalización entrelazadas") hizo que el compilador ya descubriera esas interdependencias y programara las operaciones en consecuencia.

Pero eso es en una escala muy pequeña y de muy bajo nivel. Resulta que la secuencialidad impregna mucho la computación, el pensamiento sobre la computación y la programación y los intentos de paralelismo masivo expresados ​​de forma razonablemente natural en la arquitectura ("arquitectura de flujo de datos") y/o la programación ("Occam") realmente no despegaron y algunos masivamente paralelizables los sistemas como las redes neuronales artificiales obtienen su programación más bien a través de la mano y el "aprendizaje" en lugar de instrucciones explícitas.

El MIPS R2000 original era escalar, pero sí, estaba canalizado y tenía ranuras de retraso de carga que el compilador tenía que llenar con algo (quizás solo un NOP) y ranuras de demora de ramificación. Un ejemplo de descargar el trabajo de encontrar un verdadero paralelismo a nivel de instrucción (en lugar de simplemente superponer latencias de carga y bifurcación con otras cosas) serían las arquitecturas VLIW donde una "palabra de instrucción" en realidad contiene múltiples instrucciones que la CPU ejecuta sin verificar si hay conflictos con ellas. entre sí. Itanium es un ejemplo notable. Creo que los compiladores nunca pudieron hacerlo tan bien como se esperaba.
realworldtech.com/ev8-mckinley/5 tiene un análisis de la microarquitectura Itanium de segunda generación, McKinley, con su canalización de paquete dual (6 "instrucciones" de ancho).

TL:DR: Sí, pero no para la mayoría de las tareas. Es por eso que la iteración actual de esta idea son las CPU híbridas con algo de rendimiento, algunos núcleos eficientes, ahora que tenemos presupuestos de transistores para arrojar tantos núcleos a una CPU de computadora portátil o de escritorio de consumo.

pero, ¿no puede un sistema con muchos núcleos simples ser más eficiente que uno con un número de núcleos avanzados de un solo dígito para algunas tareas?

"Para algunas tareas" es el problema. Son mucho peores para muchas otras tareas, las que no se han paralelizado o no se pueden paralelizar fácilmente. Para hacer un bucle en una matriz de tamaño mediano, por ejemplo, a menudo no vale la pena hablar con otros núcleos de CPU sobre cómo hacer parte del trabajo, porque la latencia involucrada es comparable al tiempo que llevaría hacer el trabajo en un solo hilo.

Y un procesador de "muchas CPU simples" es peor que las GPU para tareas que son altamente paralelas y no tienen mucha bifurcación dependiente de datos. Es decir, donde se puede tolerar una alta latencia para lograr el alto rendimiento por potencia y por área de matriz que pueden proporcionar las GPU. Entonces, como han señalado otras respuestas, el término medio entre las GPU optimizadas para el rendimiento y las CPU optimizadas para la latencia no es muy grande en términos de demanda comercial. (Cosas como CPU SIMD lo hacen lo suficientemente bien para la mayoría de las cosas, aunque con la eficiencia energética cada vez más importante, hay espacio para CPU híbridas con algunos núcleos de eficiencia).

El rendimiento por subproceso es muy importante para las cosas que no son vergonzosamente paralelas. (Y también porque el ancho de banda de la memoria/la huella de la memoria caché se escalan con la cantidad de subprocesos para muchas cargas de trabajo, por lo que hay un límite inferior sobre cuán simple/pequeño desearía hacer cada núcleo sin una arquitectura totalmente diferente, como una GPU).

Un sistema con menos núcleos grandes puede usar SMT (Subprocesos múltiples simultáneos , por ejemplo, hiperprocesamiento) para hacer que esos núcleos grandes parezcan el doble de núcleos más pequeños. (O 4x u 8x, por ejemplo, en las CPU IBM POWER). Esto no es tan eficiente desde el punto de vista energético como tener núcleos más pequeños, pero está en el mismo estadio. Y, por supuesto, el simple cambio de contexto del sistema operativo permite ejecutar tantos subprocesos de software como desee en un núcleo, mientras que lo contrario no es posible: no existe una forma simple de usar muchos núcleos simples para ejecutar un subproceso rápidamente.

Hay rendimientos decrecientes Lo contrario de esta pregunta, ¿ por qué no hacer un gran núcleo de CPU? tiene

Relacionado: Microprocesadores modernos ¡Una guía de 90 minutos! tiene una sección sobre SMT y multinúcleo, y es una excelente lectura de antecedentes sobre las limitaciones de diseño de la CPU, como la energía.


Hacer grandes sistemas coherentes con la memoria caché es difícil, por lo que es difícil escalar a una gran cantidad de núcleos de CPU. Los chips Xeon y Epyc más grandes tienen 56 o 64 núcleos físicos en un dado.

Compare esto con las tarjetas de cómputo Xeon Phi , que es más o menos lo que se preguntaba: AVX-512 conectado a núcleos Silvermont de bajo consumo, llegando hasta 72 núcleos por tarjeta con algo de memoria de gran ancho de banda. (Y SMT de 4 vías para ocultar ALU y latencia de memoria, por lo que en realidad admitió 4 veces esa cantidad de subprocesos).

Descontinuaron esa línea en 2018 debido a la falta de demanda. Este artículodice que "nunca ha visto ningún éxito comercial en el mercado". No podría obtener grandes aceleraciones ejecutando binarios existentes en él; el código generalmente necesitaba ser compilado para aprovechar AVX-512. (Creo que se suponía que la cadena de herramientas de Intel podía paralelizar automáticamente algunos bucles, por lo que los cambios de fuente podrían haber sido menos necesarios o más pequeños que para usar GPU). Y omitió AVX-512BW, por lo que no era bueno para la codificación de video de alta calidad (x264/x265 a diferencia del hardware de función fija); Creo que principalmente es bueno para el trabajo de FP, lo que significa que estaba compitiendo con las GPU. (Algunos de los motivos pueden deberse a trabajar en una nueva arquitectura desde cero para la informática "exascale", después de ver cómo evolucionó el panorama informático desde el inicio del proyecto Larrabee a mediados de la década de 2000;


CPU híbridas/heterogéneas: algunas rápidas, otras eficientes

La última iteración de su idea es tener una combinación de núcleos, por lo que aún puede tener algunos núcleos rápidos para cosas en serie/sensibles a la latencia.

Algunos códigos son solo algo paralelos, o tienen algunos subprocesos diferentes que realizan tareas separadas que son individualmente seriales. (No distribuyendo realmente una tarea a través de muchos subprocesos).

ARM ha estado haciendo eso por un tiempo (llamándolo grande. PEQUEÑO), y el nuevo diseño de Alder Lake de Intel con una combinación de núcleos de rendimiento (Golden Cove) y núcleos de eficiencia (Gracemont) es exactamente esto: agregue algunos núcleos que no llegan tan lejos en los rendimientos decrecientes por gastar más energía para aumentar el rendimiento por subproceso.

Entonces, cuando se realiza un trabajo "ligero" donde un E-core es suficiente para mantenerse al día con algo que no es útil para hacer más rápido (como reproducir un video o escribir / hacer clic en una página web), solo ese pequeño núcleo necesita estar encendido.

O al hacer algunos cálculos numéricos / codificación de video / lo que sea con mucho paralelismo a nivel de subprocesos, 4 E-cores para el área de un P-core le brindan un mayor rendimiento total. Pero aún tiene algunos núcleos P para tareas que no están (o simplemente no estaban) paralelizadas. (Escribí con más detalle sobre Alder Lake en superuser.com ).

Incluso los núcleos E en Alder Lake realizan una ejecución fuera de servicio superescalar bastante amplia, y pueden tener un rendimiento bastante bueno en el código donde el paralelismo de nivel de instrucción es fácil de encontrar para la CPU. (En ARM big.LITTLE, los pequeños núcleos a menudo están en orden, pero siguen siendo superescalares de 3 anchos con cosas como cachés hit-under-miss para encontrar algo de paralelismo a nivel de memoria, por ejemplo, Cortex-A53)

Para la mayoría de los sistemas para cargas de trabajo generales, no es comercialmente viable no tener núcleos optimizados para latencia que tengan un alto rendimiento de subproceso único. Muchas tareas no se paralelizan fácilmente, o simplemente no lo han hecho porque eso es mucho más esfuerzo de programación. (Aunque los teléfonos inteligentes de gama baja a veces solo usan núcleos de gama baja; la gente preferiría tener un teléfono barato y lento que no tener ningún teléfono, y la eficiencia energética es incluso más importante que para las computadoras portátiles).


CPU anteriores de muchos núcleos pequeños:

Ya mencioné Xeon Phi, pero años antes, otro ejemplo interesante fue Sun UltraSPARC T1 , también conocido como Niagara, lanzado en 2005.

Era una CPU de 8 núcleos (o 4 o 6 núcleos para otros modelos), en un momento en que las CPU x86 apenas comenzaban a introducir 1 de doble núcleo como Athlon X2 . Ni siquiera estaban tratando de apuntar a un alto rendimiento por subproceso, que era esencial para la mayoría de los usos interactivos en ese entonces. En cambio, apuntaban a cargas de trabajo de servidor/base de datos con muchas conexiones, por lo que ya había mucho paralelismo a nivel de subprocesos para el software, incluso en ese entonces.

Cada núcleo tenía una tubería bastante simple y era un procesador de "barril", que rotaba entre hasta 4 núcleos lógicos no estancados, también conocidos como subprocesos de hardware. (Básicamente como SMT de 4 vías, pero en orden para que las instrucciones de subprocesos separados nunca se mezclen en una unidad de ejecución). Creo que mantener los núcleos pequeños y simples hizo que los gastos generales de bloqueo fueran más bajos.

32 núcleos lógicos era una gran cantidad en 2005. (Y las generaciones posteriores tenían capacidad para múltiples sockets, lo que permitía 2x o 4x en un sistema completo). El artículo wiki menciona que sin opciones especiales del compilador (supongo que para paralelizar automáticamente), dejó mucho rendimiento sobre la mesa para cargas de trabajo que aún no estaban paralelizadas, como MySQL (en 2005, e IDK si estaban gziphablando sobre una sola gran consulta o qué). Esa es la desventaja de tener muchos núcleos débiles, especialmente si realmente te apoyas en él como lo hizo Sun al hacerlo sin mucho caché y dependiendo del procesador de barril para ocultar la latencia.

Nota al pie 1 : Parte de eso fue que la mayor parte del mercado x86 era para máquinas que ejecutarían Windows, y hasta Windows XP, las versiones principales no eran IIRC compatibles con SMP. Pero los servidores habían sido multisocket durante mucho tiempo, logrando SMP al tener múltiples paquetes físicos de CPU en sockets separados. Pero principalmente era que los presupuestos de transistores todavía estaban en un punto en el que más caché y un ejecutivo OoO más amplio/profundo todavía proporcionaban ganancias significativas.


La paralelización de muchas tareas es difícil

La comunicación entre núcleos siempre va a ser bastante costosa (al menos de alta latencia), porque las distancias son intrínsecamente largas y debido a la ejecución desordenada para ocultar la memoria y la latencia de la caché L3. Un núcleo puede ver especulativamente sus propias acciones, pero las tiendas no pueden hacerse visibles para otros núcleos especulativamente; de ​​lo contrario, tendría que revertirlas al detectar una predicción errónea de una rama. (Lo cual es completamente impráctico en términos de mantener un punto consistente al que retroceder, y anularía el propósito de tener un núcleo separado).

Por lo tanto, la comunicación entre núcleos toma al menos la latencia de la interconexión y el protocolo de coherencia de caché, más la latencia del búfer de almacenamiento y la ventana de ejecución fuera de servicio. (Y las barreras de ordenación de la memoria normalmente involucradas limitan un poco la ejecución fuera de orden).

"...CPU SIMD lo hace lo suficientemente bien para la mayoría de las cosas..." - vale la pena mencionar que la supercomputadora más rápida actual usa el procesador A64FX, sin aceleradores. Eso es Arm SVE, con una enorme cantidad de ancho de banda de memoria.