Que no te la cuelen, más núcleos no quiere decir que el ordenador sea más potente
El hecho de escoger un procesador con más núcleos muchas veces no se convierte en un aumento de rendimiento en el mismo grado a la hora de usar ciertos programas. ¿Por qué ocurre dicho fenómeno y, por tanto, cuáles son las causas de ello? Os lo explicamos de manera detallada.
Uno de los motivos por los cuales usar versiones de programas más nuevas en el tiempo es que están pensadas para aprovechar mejor los procesadores con mayor número de núcleos. No olvidemos que con el paso del tiempo el número de núcleos en el procesador va aumentando. Sin embargo, ¿por qué no aumenta el rendimiento en los programas a la par?
Los programas nunca escalan con el número de núcleos
Es importante tener en cuenta que los programas que se ejecutan no tienen la habilidad de poder dividir sus procesos o tareas activos en cada momento, según la cantidad de hilos de ejecución que tenemos en nuestra CPU. Más que nada por el hecho que dicha división viene explicita en el código del programa, es decir, es producto de la habilidad del programador y del diseño de la aplicación.
En realidad, lo relevante a la hora de codificar un programa no es optimizarlo de cara a usar la mayor cantidad de núcleos posibles, sino para la latencia. Entendiendo esta última como el tiempo en que tarda un procesador en terminar una tarea medido en unidades de tiempo. Y es que el rendimiento de una CPU consiste en completar la mayor parte de tareas en el menor tiempo posible. Lo cual dependerá de su arquitectura primero y su velocidad de reloj después.
Sin embargo, lo que nos interesa de cara a la latencia es saber cuantas tareas puede terminar en un periodo dado, lo cual es la carga de trabajo y esta dependerá de la situación y la forma en la que hayan sido escritos los programas. Es decir, el rendimiento no solo depende del hardware, sino de lo bien o mal que haya sido escrito el software.
División del trabajo en varios núcleos
Ahora bien, si aumentamos la cantidad de núcleos de un sistema, entonces se hace posible dividir el trabajo en partes y que este se complete mucho más fácilmente. Es aquí donde entra la fórmula T/N donde T es la cantidad de tareas a realizar y N es la cantidad de hilos de ejecución que puede ejecutar el sistema. Obviamente, podríamos cargar el máximo número de trabajos en pocos núcleos y usar la fuerza bruta de estos para solucionarlos. El problema es que esta medida es contraproducente por el hecho que beneficia a las CPU más modernas, las cuales tienen un mayor rendimiento de forma individual en cada núcleo.
Sin embargo, dividir el trabajo en diferentes núcleos es un trabajo adicional que suele dar a un núcleo que hace de director de orquesta y ha de hacer las siguientes tareas:
- Ha de crear procesos y listas de tareas y tener un buen control de ello en cada momento.
- Han de saber predecir en cada momento cuando empieza y termina una tarea, incluyendo el tiempo en que se tarda en finalizar una y empezar otra.
- Los diferentes núcleos han de tener la capacidad de enviar una señal al núcleo principal para saber cuando empieza y termina un proceso.
Dicha solución fue adoptada por SONY, Toshiba e IBM en el Cell Broadband Engine, el procesador central de la PS3 donde un núcleo maestro se encargaba de dirigir al resto. Aunque mucho más atrás fue adoptado por la Jaguar de Atari. De cara a PS4 SONY no volvió a repetir dicho modelo y nadie lo ha implementado en el PC por el hecho de que es una pesadilla, sin embargo, es la forma más eficiente de dividir el trabajo.
No todo se puede ejecutar en varios núcleos
Sin nos preguntamos si podemos dividir cualquier tarea en subtareas que distribuir en un mayor número de núcleos de forma indefinida, la respuesta es no. En concreto, hemos de clasificar las tareas en tres tipos distintos:
- Las que se pueden paralelizar totalmente y, por tanto, dividir entre los diferentes núcleos que tiene el procesador central.
- Tareas que se pueden ejecutar parcialmente en paralelo.
- Partes del código que no se pueden ejecutar en paralelo.
En el primer caso, T/N se aplica al 100%, en el segundo caso, ya entramos en la llamada Ley de Amdahl donde la aceleración por aumentar el número de núcleos es parcial y en el tercero simplemente necesitamos toda la potencia de un único núcleo para dicha tarea,
Lo que diferencia a la CPU de las GPU en multihilo
Aquí llegamos a un punto diferencial, toda GPU o chip gráfico tiene una unidad de control que se encarga de leer las listas de comandos y repartirlas entre los diferentes núcleos de la GPU e incluso entre las diferentes unidades. Se trata de una implementación en el ámbito del hardware del caso anterior y funciona perfectamente en cualquier configuración donde se busca saturar, siempre y cuando haya trabajo, y, por tanto, mantener ocupadas la mayor cantidad de núcleos posible. Sin embargo, hemos de entender que el concepto hilo de ejecución en una GPU corresponde siempre a un dato correspondiente y su lista de instrucciones. Es decir, un píxel, vértice o cualquier dato.
Lo cual hace que se puedan paralelizar fácilmente. Es decir, si quisiéramos freír un huevo, el proceso en la CPU sería freír el huevo, el cual sería totalmente secuencial. En cambio, en el chip gráfico una tarea sería simplemente la de calentar aceite o echar huevo a la sartén. Todo ello no nos aceleraría el poder freír un huevo, pero si varios, es por ello que las GPU son mejores para realizar tareas como calcular millones de polígonos o píxeles al unísono, pero no para tareas secuenciales.