Buena pregunta, o al menos con una respuesta interesante. Parte de esta respuesta imagina un mundo en el que las CPUs podría escalar eficientemente en anchura en lugar de con múltiples núcleos separados. Los modelos de licencia/precio serían diferentes.
El resto explica por qué no pueden. Resumen:
-
El coste de los núcleos múltiples escala casi linealmente (en área de la matriz / potencia). Las interconexiones eficientes entre los núcleos son más difíciles cuando se tienen más núcleos, ya que se necesita más ancho de banda agregado para utilizarlos todos de forma útil. Y todos forman parte del mismo dominio de coherencia de caché.
-
El coste de ampliar el pipeline superescalar de 1 núcleo se escala ~cuadráticamente Esto es posible con suficiente fuerza bruta, hasta cierto punto. El rendimiento de un solo hilo es muy importante para el uso interactivo (la latencia de extremo a extremo importa, no sólo el rendimiento), por lo que las actuales CPUs de gran núcleo de gama alta pagan ese precio. por ejemplo, Skylake (4 de ancho), Ryzen (5 o 6 de ancho), y El A12 de Apple (7 de ancho para los núcleos grandes, 3 de ancho para los núcleos pequeños de bajo consumo)
-
En serio disminuyendo CIP rendimientos de sólo ampliar la tubería más allá de 3 o 4 de ancho, incluso con la ejecución fuera de orden para encontrar el ILP . Los fallos de bifurcación y los fallos de caché son difíciles, y aún así se detiene todo el pipeline.
-
No has mencionado la frecuencia, sólo el IPC, pero escalar la frecuencia también es difícil. Una mayor frecuencia requiere un mayor voltaje, por lo que la potencia escala con la frecuencia al cubo : ^1
de la frecuencia directamente, y ^2
de la tensión. (La energía almacenada en el condensador escala con V^2, y la mayor parte de la potencia dinámica, más allá de la corriente de fuga, procede del bombeo de carga en las cargas capacitivas de las compuertas de los FET + los cables).
Rendimiento = frecuencia por IPC. (Dentro de la misma arquitectura. Una SIMD más amplia permite realizar el mismo trabajo con menos instrucciones, y algunas ISA son más densas que otras, por ejemplo, MIPS suele necesitar más instrucciones para realizar el mismo trabajo que x86 o AArch64).
Los costes están en el área de la matriz (coste de fabricación) y/o en la potencia (que limita indirectamente la frecuencia porque la refrigeración es difícil). Además, una menor potencia y rendimiento por vatio es un objetivo en sí mismo, sobre todo para los móviles (batería) y los servidores (densidad de potencia / costes de refrigeración / costes de electricidad).
Antes de que los núcleos múltiples por zócalo fueran una cosa, había sistemas de varios zócalos para casos de uso de alta gama en los que se quería más rendimiento del que se podía conseguir con una sola CPU que se pudiera fabricar, así que esos eran los únicos sistemas SMP. (Servidores, estaciones de trabajo de gama alta).
Si un solo núcleo pudiera escalar tan eficientemente como se desea, tendríamos sistemas con 1 núcleo físico por socket, y SMT (por ejemplo, HyperThreading) para que actúen como múltiples núcleos lógicos. Los típicos ordenadores de sobremesa/portátiles sólo tendrían 1 núcleo físico, y no tendríamos problemas para paralelizar cosas que no escalan linealmente con más núcleos, por ejemplo make -j4
para aprovechar los servidores multisocket, y/o para ocultar la latencia de E/S en un escritorio. (O tal vez todavía trataríamos de paralelizar mucho si el ancho del pipeline escalara fácilmente pero el IPC no, por lo que tendríamos que usar más hilos SMT). El núcleo del sistema operativo tendría que ejecutarse en todos los núcleos lógicos, a menos que la forma en que la CPU presenta la SMT al sistema operativo fuera muy diferente, por lo que los algoritmos de programación paralela y el bloqueo seguirían siendo necesarios.
Donald Knuth dijo en una entrevista en 2008
También podría hablar un poco de mi descontento personal con la tendencia actual hacia la arquitectura multinúcleo. Para mí, se parece más o menos a la los diseñadores de hardware se han quedado sin ideas, y que están tratando de pasar la culpa de la futura desaparición de la Ley de Moore a los escritores de software dándonos máquinas que funcionan más rápido sólo en algunos puntos de referencia clave.
Sí, si pudiéramos tener milagrosas CPUs de un solo núcleo con 8 veces el rendimiento en programas reales probablemente seguiríamos usándolas. Con los sistemas de doble zócalo sólo cuando valiera la pena pagar mucho más por un mayor rendimiento (no por el rendimiento de un solo hilo).
Las CPUs múltiples reducen los costes de cambio de contexto cuando se ejecutan varios programas (dejando que realmente se ejecuten en paralelo en lugar de cambiar rápidamente entre ellos); la multitarea preventiva que interrumpe la maquinaria masiva fuera de orden que requeriría una CPU de este tipo probablemente perjudicaría aún más de lo que lo hace ahora.
Físicamente sería de un solo núcleo (para una jerarquía de caché simple sin interconexiones entre núcleos) pero el soporte SMT (por ejemplo, HyperThreading de Intel) para que el software pueda utilizarlo como 8 núcleos lógicos que compiten dinámicamente por los recursos de rendimiento. O cuando sólo 1 hilo está en marcha / no está parado, obtendría todo el beneficio.
Así que usarías múltiples hilos cuando eso fuera realmente más fácil/natural (por ejemplo, procesos separados ejecutándose a la vez), o para problemas fácilmente paralelizables con cadenas de dependencias que impidieran maximizar el IPC de esta bestia.
Pero, por desgracia, es una ilusión por parte de Knuth que las CPUs multinúcleo dejen de existir a estas alturas.
Escalado de rendimiento de un solo hilo
Creo que si hicieran un núcleo equivalente a una CPU de 8 núcleos, ese núcleo tendría un 800% más de IPC por lo que se obtendría todo el rendimiento en todos los programas, no sólo en los que están optimizados para mu
Sí, es cierto. Si fuera posible construir una CPU así en absoluto, sería muy sorprendente. Pero creo que es literalmente imposible con el mismo proceso de fabricación de semiconductores (es decir, la misma calidad/eficiencia de los transistores). Desde luego, no es posible con el mismo presupuesto de energía y la misma superficie de matriz que una CPU de 8 núcleos, aunque se ahorraría en lógica para pegar los núcleos y no se necesitaría tanto espacio para las cachés privadas por núcleo.
Incluso si se permite el aumento de la frecuencia (ya que el criterio real es el trabajo por segundo, no el trabajo por reloj), hacer incluso una CPU 2 veces más rápida sería un gran desafío.
Si fuera posible en cualquier lugar cerca de el mismo presupuesto de energía y área de la matriz (por lo tanto, el coste de fabricación) para construir una CPU de este tipo, sí los proveedores de CPU ya las estarían construyendo de esa manera.
En concreto, el ¿Más núcleos o núcleos más anchos? para conocer los antecedentes necesarios para entender esta respuesta; comienza de forma sencilla con el funcionamiento de las CPUs con canalización en orden, y luego con las superescalares (múltiples instrucciones por reloj). A continuación, explica cómo nos topamos con el muro de la energía justo en la era P4, lo que llevó al fin del escalado de frecuencia fácil, dejando principalmente el IPC y la realización de más trabajo por instrucción (por ejemplo, SIMD) como el camino a seguir, incluso con transistores más pequeños.
La ampliación de un pipeline (máximo de instrucciones por reloj) suele aumentar su coste en función de la anchura al cuadrado . Ese coste se mide en área de la matriz y/o en energía, para una mayor comprobación de dependencias paralelas (detección de riesgos), y un planificador más amplio fuera de orden para encontrar instrucciones listas para ejecutar. Y más puertos de lectura/escritura en el archivo de registro y la caché si quieres ejecutar instrucciones que no sean nop
. Especialmente si tienes instrucciones de 3 entradas como FMA o add-with-carry (2 registros + flags).
También hay rendimientos de IPC decrecientes para hacer CPUs más anchas La mayoría de las cargas de trabajo tienen un ILP (paralelismo a nivel de instrucciones) limitado a pequeña escala y de corto alcance para que las CPUs lo exploten, por lo que hacer el núcleo más amplio no lo hace aumentar el IPC (instrucciones por reloj) si el IPC ya está limitado a menos de la anchura del núcleo por las cadenas de dependencia, los fallos de bifurcación, los fallos de caché u otros atascos. Seguro que se obtendría un aumento de velocidad en algunos bucles desenrollados con iteraciones independientes, pero eso no es lo que hace la mayor parte del código. Las instrucciones de comparación y ramificación representan el 20% de la mezcla de instrucciones en el código "típico", según creo. (Creo que he leído cifras del 15 al 25% para varios conjuntos de datos).
Además, un fallo en la caché que bloquea todas las instrucciones dependientes (y luego todo una vez que se alcanza la capacidad del ROB) cuesta más para una CPU más amplia. (El coste de oportunidad de dejar más unidades de ejecución ociosas; más trabajo potencial que no se realiza). O un fallo de bifurcación provoca igualmente una burbuja.
Para obtener 8 veces el IPC, necesitaríamos al menos 8 veces más precisión en la predicción de bifurcaciones y en las tasas de éxito de la caché . (No estoy seguro de que las matemáticas funcionen realmente así, y depende de lo ramificada que sea la carga de trabajo).
Pero, en cualquier caso, las tasas de éxito de la caché no escalan bien con la capacidad de la caché más allá de cierto punto para la mayoría de las cargas de trabajo. Y el prefetching HW es inteligente, pero no puede ser que inteligente. Y con un IPC 8 veces mayor, los predictores de bifurcación deben producir 8 veces más predicciones por ciclo, además de ser más precisos. (Ningún diseño actual de x86-64 puede manejar más de una bifurcación por reloj, e incluso las bifurcaciones consecutivas son un cuello de botella para los predictores en los Intel recientes, a menos que se trate de la misma bifurcación de bucle que se ejecuta repetidamente. Por lo tanto, es probable que el código con ramas sea un problema, frente a encontrar más ILP en bloques de código en línea recta, por ejemplo, en bucles desenrollados).
Las técnicas actuales para construir CPUs de ejecución fuera de orden sólo pueden encontrar ILP en rangos cortos . Por ejemplo, el tamaño del ROB de Skylake es de 224 uops de dominio fusionado, el planificador de uops no ejecutadas es de 97 de dominio no fusionado. Véase Comprensión del impacto de lfence en un bucle con dos cadenas de dependencia largas, para longitudes crecientes para un caso en el que el tamaño del planificador es el factor limitante para extraer ILP de 2 cadenas largas de instrucciones, si consiguen también largo. Y/o ver esto respuesta más general e introductoria ).
Así que encontrar el ILP entre dos bucles largos separados no es algo que podamos hacer con el hardware. La recompilación binaria dinámica para la fusión de bucles podría ser posible en algunos casos, pero es difícil y no es algo que las CPUs puedan hacer realmente a menos que sigan el camino de Transmeta Crusoe. (capa de emulación x86 sobre una ISA interna diferente; en ese caso VLIW). Pero los diseños x86 modernos estándar con cachés uop y Los decodificadores potentes no son fáciles de superar para la mayoría de los códigos.
Y fuera de x86, todos los ISA que aún se utilizan son relativamente fáciles de descodificar, por lo que no hay ninguna motivación para la recompilación dinámica que no sean las optimizaciones a larga distancia. TL:DR: la esperanza de compiladores mágicos que puedan exponer más ILP al hardware no funcionó para Itanium IA-64 y es poco probable que funcione para una CPU superancha para cualquier ISA existente con un modelo de ejecución en serie.
Si tuvieras una CPU superamplia, definitivamente querrías que soportara SMT para poder mantenerla alimentada con trabajo que hacer ejecutando múltiples hilos de baja ILP.
Dado que Skylake tiene actualmente 4 uops de ancho (y alcanza un IPC real de 2 a 3 uops por reloj, o incluso más cerca de 4 en código de alto rendimiento), una hipotética CPU 8 veces más ancha tendría 32 de ancho.
Ser capaz de tallar de nuevo en 8 o 16 CPUs lógicas que dinámicamente compartir esos recursos de ejecución sería fantástico: los hilos no instalados obtienen todo el ancho de banda del front-end y el rendimiento del back-end.
Pero con 8 núcleos separados, cuando un hilo se atasca no hay nada más para mantener alimentadas las unidades de ejecución; los otros hilos no se benefician.
La ejecución suele ser en ráfaga: se detiene a la espera de la carga de un fallo de caché y, una vez que llega, muchas instrucciones en paralelo pueden utilizar ese resultado. Con una CPU superamplia, esa ráfaga puede ir más rápido y, de hecho, puede ayudar con el SMT.
Pero no podemos tener CPUs mágicas súper anchas
Así que para ganar rendimiento tenemos que exponer el paralelismo al hardware en forma de paralelismo a nivel de hilo . Por lo general, los compiladores no saben muy bien cuándo y cómo utilizar hilos, salvo en casos sencillos como los bucles muy grandes. (OpenMP, o gcc -ftree-parallelize-loops
). Sigue siendo necesario el ingenio humano para reelaborar el código y conseguir que se haga un trabajo útil en paralelo, ya que la comunicación entre hilos es cara, al igual que el inicio de los mismos.
El TLP es un paralelismo de grano grueso, a diferencia del ILP de grano fino dentro de un único hilo de ejecución que el HW puede explotar.
CPUs destinadas a cargas de trabajo interactivas (como los núcleos de gama alta Intel / AMD x86, y Apple / ARM AArch64) definitivamente sí que se ven afectados por los rendimientos decrecientes del escalado del IPC, ya que el rendimiento de un solo hilo sigue siendo tan valioso cuando la latencia importa, no sólo el rendimiento para los problemas masivamente paralelos.
Poder ejecutar 8 copias de un juego en paralelo a 15fps cada una es mucho menos valioso que poder ejecutar una copia a 45fps. Los fabricantes de CPUs lo saben y por eso las CPUs modernas utilizan la ejecución fuera de orden, a pesar de que supone un coste considerable de energía y superficie. (Pero las GPU no lo hacen porque su carga de trabajo ya es masivamente paralela).
El hardware multinúcleo Xeon Phi de Intel (Knight's Landing / Knight's Mill) es un interesante punto intermedio: ejecución fuera de orden muy limitada y SMT para mantener los núcleos de 2 de ancho alimentados con instrucciones AVX512 SIMD para hacer números. Los núcleos se basan en la arquitectura Silvermont de bajo consumo de Intel. (Ejecución fuera de orden pero con una pequeña ventana de reordenación, mucho menor que la familia Sandybridge de núcleo grande. Y un pipeline más estrecho).
actualización: diseños híbridos / big.LITTLE como ARM, o recientemente Intel Alder Lake, tienen algunos núcleos de rendimiento para el trabajo no paralelo, y algunos núcleos de eficiencia (optimizados para el rendimiento, y baratos para despertar para cosas fáciles pero frecuentes como la decodificación de los siguientes cuadros de un archivo de audio). Ver mi respuesta en ¿Cuáles son los núcleos de rendimiento y eficiencia de la 12ª generación de CPUs Alder Lake de Intel?
Por cierto, todo esto es ortogonal a SIMD. Conseguir más trabajo por instrucción siempre ayuda, si es posible para su problema.
Modelos de precios
Los modelos de precios del software se basan en el panorama actual del hardware.
Los modelos de licencia por núcleo se generalizaron (y son relevantes incluso para los ordenadores de sobremesa de un solo zócalo) con la llegada de las CPU multinúcleo. Antes de eso, solo era relevante para servidores y grandes estaciones de trabajo.
Si el software no necesitara varios núcleos para ejecutarse a la máxima velocidad, no habría forma de venderlo más barato a personas que no le sacan tanto partido porque lo ejecutan en una CPU más débil. A no ser que el ecosistema de software/hardware desarrollara controles en los "canales SMT" que permitieran configurar un ancho de ejecución máximo para el código que se ejecuta en ese núcleo lógico. (De nuevo, imaginando un mundo en el que las CPUs escalan en anchura de canalización en lugar de múltiples núcleos separados).