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?
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.
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.
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.
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:
¹ 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.
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):
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:
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.
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.
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.
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;
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).
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 gzip
hablando 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 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).
tobalto
usuario_1818839
mitu raj
Jörg W. Mittag
Syed