multithreading performance multicore gpgpu parallel-processing

multithreading - GPGPU vs. Multicore?



performance parallel-processing (2)

¿Cuáles son las principales diferencias prácticas entre GPGPU y la programación de CPU multinúcleo / multiproceso regular, desde la perspectiva del programador? Específicamente:

  • ¿Qué tipos de problemas se adaptan mejor a los multinúcleos regulares y qué tipos son más adecuados para GPGPU?

  • ¿Cuáles son las diferencias clave en el modelo de programación?

  • ¿Cuáles son las principales diferencias de hardware subyacentes que requieren alguna diferencia en el modelo de programación?

  • ¿Cuál es típicamente más fácil de usar y por cuánto?

  • ¿Es práctico, a largo plazo, implementar bibliotecas de paralelismo de alto nivel para la GPU, como la biblioteca paralela de tareas de Microsoft o el paralelismo estándar de D''s ?

  • Si la computación GPU es tan espectacularmente eficiente, ¿por qué las CPU no se diseñan más como GPU?


Incluso en una CPU multi-core, sus unidades de trabajo van a ser mucho más grandes que en una GPGPU. Las GPGPU son apropiadas para problemas que se escalan muy bien, con cada porción de trabajo siendo increíblemente pequeña. Una GPGPU tiene una latencia mucho mayor porque debe mover datos al sistema de memoria de la GPU antes de poder acceder a ella. Sin embargo, una vez que los datos estén allí, su rendimiento, si el problema es apropiadamente escalable, será mucho más alto con una GPGPU. En mi experiencia, el problema con la programación GPGPU es la latencia en la obtención de datos de la memoria normal a la GPGPU.

Además, las GPGPU son horribles a la hora de comunicarse entre procesos de trabajo si los procesos de trabajo no tienen un enrutamiento de esfera de localidad. Si intenta comunicarse a través de la GPGPU, sentirá mucho dolor. Por este motivo, las bibliotecas estándar de MPI no son adecuadas para la programación de GPGPU.

Todas las computadoras no están diseñadas como GPU porque las GPU son fantásticas para cálculos de alta latencia y alto rendimiento que son intrínsecamente paralelos y se pueden descomponer fácilmente. La mayor parte de lo que hace la CPU no es inherentemente paralela y no escala a miles o millones de trabajadores simultáneos de manera muy eficiente. Afortunadamente, la programación de gráficos sí y es por eso que todo esto comenzó en las GPU. La gente ha encontrado cada vez más problemas que pueden parecer problemas gráficos, lo que ha llevado al aumento de la programación de GPGPU. Sin embargo, la programación de GPGPU solo vale realmente su tiempo si es apropiado para su dominio problemático.


Interesante pregunta. Investigué este problema, por lo que mi respuesta se basa en algunas referencias y experiencias personales.

¿Qué tipos de problemas se adaptan mejor a los multinúcleos regulares y qué tipos son más adecuados para GPGPU?

Como dijo @Jared. GPGPU está diseñado para cargas de trabajo de rendimiento muy regular, por ejemplo, gráficos, multiplicación matriz-matriz densa, filtros simples de Photoshop, etc. Son buenos para tolerar largas latencias porque están diseñados inherentemente para tolerar el muestreo de Textura, una operación de más de 1000 ciclos. Los núcleos GPU tienen una gran cantidad de subprocesos: cuando un hilo desencadena una operación de latencia larga (por ejemplo, acceso a memoria), ese subproceso se pone en suspensión (y otros subprocesos continúan funcionando) hasta que finaliza la operación de latencia larga. Esto permite que las GPU mantengan sus unidades de ejecución ocupadas mucho más que los núcleos tradicionales.

Las GPU son malas en el manejo de sucursales porque a las GPU les gusta agrupar "hilos" (carriles SIMD si no son nVidia) en urdimbres y enviarlos por la tubería juntos para ahorrar en la potencia de búsqueda / decodificación de instrucciones. Si los hilos encuentran una rama, pueden divergir, por ejemplo, 2 hilos en una urdimbre de 8 hilos pueden tomar la rama, mientras que los otros 6 pueden no tomarla. Ahora la urdimbre se debe dividir en dos urdimbres de tamaño 2 y 6. Si su núcleo tiene 8 carriles SIMD (razón por la cual la urdimbre original pagó 8 hilos), ahora sus dos urdimbres recién formadas funcionarán de manera ineficiente. La urdimbre de 2 hilos funcionará al 25% de eficiencia y la urdimbre de 6 hilos funcionará al 75% de eficiencia. Puedes imaginar que si una GPU continúa encontrando ramas anidadas, su eficiencia es muy baja. Por lo tanto, las GPU no son buenas para manejar ramas y, por lo tanto, el código con ramas no se debe ejecutar en GPU.

Las GPU también son malas para enhebrar cooperativas. Si los hilos necesitan comunicarse entre sí, las GPU no funcionarán bien porque la sincronización no está bien soportada en las GPU (pero nVidia está presente).

Por lo tanto, el peor código para GPU es código con menos paralelismo o código con muchas ramas o sincronización.

¿Cuáles son las diferencias clave en el modelo de programación?

Las GPU no admiten interrupciones y excepciones. Para mí, esa es la mayor diferencia. Aparte de eso, CUDA no es muy diferente de C. Puedes escribir un programa CUDA en el que envías el código a la GPU y lo ejecutas allí. Accedes a la memoria en CUDA de forma un poco diferente, pero una vez más eso no es fundamental para nuestra discusión.

¿Cuáles son las principales diferencias de hardware subyacentes que requieren alguna diferencia en el modelo de programación?

Ya los mencioné. La más grande es la naturaleza SIMD de las GPU que requiere que el código se escriba de forma muy regular, sin ramificaciones ni comunicación entre hilos. Esto es parte de por qué, por ejemplo, CUDA restringe el número de ramas anidadas en el código.

¿Cuál es típicamente más fácil de usar y por cuánto?

Depende de lo que está codificando y cuál es su objetivo.

Código fácilmente vectorizable: la CPU es más fácil de codificar pero de bajo rendimiento. La GPU es un poco más difícil de codificar, pero proporciona un gran beneficio para el dinero. Para todos los demás, la CPU es más fácil y, a menudo, un mejor rendimiento también.

¿Es práctico, a largo plazo, implementar bibliotecas de paralelismo de alto nivel para la GPU, como la biblioteca paralela de tareas de Microsoft o el paralelismo estándar de D''s?

El paralelismo de tarea, por definición, requiere una comunicación de subprocesos y también tiene ramas. La idea de las tareas es que diferentes hilos hacen cosas diferentes. Las GPU están diseñadas para muchos hilos que hacen cosas idénticas. No construiría bibliotecas de paralelismos de tareas para GPU.

Si la computación GPU es tan espectacularmente eficiente, ¿por qué las CPU no se diseñan más como GPU?

Muchos de los problemas en el mundo son ramificados e irregulares. Miles de ejemplos. Algoritmos de búsqueda de gráficos, sistemas operativos, navegadores web, etc. Solo para agregar: incluso los gráficos se vuelven cada vez más ramificados y de propósito general como cada generación, por lo que las GPU se parecerán cada vez más a las CPU. No digo que se conviertan en CPUs, pero se volverán más programables. El modelo correcto está en algún punto intermedio entre las CPU ineficientes y las GPU muy especializadas.