Computación de alto rendimiento: ¿Cuáles son las principales diferencias en las clases de problemas que pueden acelerarse de manera efectiva utilizando GPGPU (por ejemplo, CUDA), multiprocesamiento simétrico (por ejemplo, OpenMP) y paso de mensajes (por ejemplo, MPI) respectivamente?

tl; dr: desplazarse hacia abajo.

Un determinado problema podría consistir en varios subproblemas, cada uno de los cuales podría abordarse mejor mediante diferentes esquemas de paralelización. Por lo tanto, los métodos a menudo se pueden combinar. Tenga esto en mente cuando lea lo siguiente.


GPGPU
Una GPGPU es un procesador vectorial. Eso significa que si eres capaz de vectorizar el problema, Cuda u OpenCL probablemente pueden darte una alta velocidad. Aquí hay un ejemplo ridículamente simple en pseudocódigo:

  matriz = [1, 2, 3, 4, .... 1000]
 para i en [0, 1, 2, ... 999]:
     matriz [i] = matriz [i] ^ 2 + 2 

Claramente, la matriz ya está vectorizada, y esperaríamos que una clase de GPU pudiera entender esto:

  array = piecewise_gpu_array ([1, 2, 3, 4, .... 1000])
 matriz = matriz ^ 2 + 2 

Si puede reescribir su código en esta forma vectorial, entonces GPGPU es el camino a seguir.

Una GPGPU está diseñada para manejar muchas operaciones numéricas simples de una sola vez. Dentro de un bucle, solo se realiza una operación a la vez. En una GPGPU, si el problema es vectorizable, puede distribuir todos los cálculos a su propia unidad de procesamiento individual. Estos realizarán los cálculos en paralelo.

En general, si puede poner su problema en forma de vector, es muy recomendable utilizar este método. Puede esperar aceleraciones locas. La G en GPU, como sabes, significa Gráfico . Buenos ejemplos de problemas de vectores son los algoritmos de trazado de rayos o enjambres de partículas, que se utilizan en la mayoría de los juegos de computadora modernos.

Para problemas simples, debería ser capaz de acelerar en cientos o incluso miles.

Un inconveniente de GPGPU es la transferencia de datos entre la CPU y la GPGPU. Esto es increíblemente lento, y podría ser una razón para no usar este enfoque. Sin embargo, si los cálculos toman mucho más tiempo que la transferencia, entonces está bien.

Como comentario: por supuesto, su GPGPU no necesariamente tiene tantas unidades de procesamiento como el tamaño de su problema, pero es un enfoque estándar para programar como si tuviera una cantidad infinita de procesadores.


Multiprocesamiento (memoria compartida)
El multiprocesamiento es probablemente el esquema de paralelización más simple que existe. Casi siempre se puede usar, pero no se escala a grandes grupos.

Tomando prestada alguna notación C ++ OpenMP, podemos paralelizar el programa desde arriba escribiendo algo ala (todavía pseudo código, por supuesto)

  matriz = [1, 2, 3, 4, .... 1000]
 #pragma omp paralelo para
 para i en [0, 1, 2, ... 999]:
     matriz [i] = matriz [i] ^ 2 + 2 

El bucle for se extiende sobre los núcleos de CPU que tenemos disponibles.

El multiprocesamiento es excelente y fácil de usar. El inconveniente está escalando. Rara vez se ve el multiprocesamiento utilizado para más de 64 núcleos debido a problemas de uso compartido de memoria.

Entonces, ¿cuándo desea usarlo? Cuando todo lo que necesita es una aceleración máxima del número de núcleos que tiene disponibles en una sola computadora .
Esta no es una técnica utilizada para redes de computadoras. Sin embargo, combinado con una técnica de red puede resultar realmente útil. Puede usar un esquema diferente para dividir el problema entre las computadoras y luego multiprocesamiento para dividir aún más entre los núcleos dentro de las computadoras.


Interfaz de paso de mensajes
Use esto cuando nada más sea suficiente. MPI es extremadamente escalable. Los grupos más grandes del mundo (con más de un millón de núcleos) usan MPI para la paralelización. El inconveniente es que requiere más tiempo para programar. La mayoría de los problemas paralelizables serán paralelizables por MPI. Entonces, las únicas preocupaciones son: ¿es fácil (suficiente) de hacer? ¿Realmente necesito esta aceleración? ¿Es mi clúster lo suficientemente grande como para que esto tenga sentido?

De nuevo, veamos el ejemplo de arriba.

  si procesador == 0
     matriz = [1, 2, 3, 4, .... 1000]
     para i en [0, 1, 2, ... 999]:
         envío sin bloqueo (matriz [i], procesador = i)

 mensaje = bloqueo_recibir (procesador = 0)
 envío sin bloqueo (mensaje ^ 2 + 2, procesador = 0)

 si procesador == 0
     para i en [0, 1, 2, ... 999]:
         array [i] = block_receive (procesador = i) 

(Esto es muy, muy pseudo-codificación. ¡Es solo para mantener el ejemplo simple! También supongo que tenemos al menos 1000 procesadores)

Con MPI tiene control total sobre qué CPU hace qué, y tiene control total sobre, por ejemplo, la ocultación de latencia. Con todo, MPI es impresionante, pero mucho más trabajo.


TL; DR

Use GPGPU si puede vectorizar el problema y la transferencia de datos a la GPU lleva menos tiempo que realizar el cálculo en sí.

Utilice el multiprocesamiento si solo necesita acelerar la cantidad de núcleos que tiene en su computadora. No utilizar para redes de computadoras.

MPI siempre se puede usar, pero es mucho más trabajo. Se escala a tantas computadoras como quieras.

Las diferencias superficiales ya se han descrito. Creo que es útil pensar en las propiedades que cada modelo puede aprovechar.

Primero, piense en su aplicación como un gráfico de flujo de datos realmente grande: las operaciones atómicas de hardware particulares (multiplicación, lo que sea) dependen de los operandos, y esos son el producto de otras operaciones, etc. Una propiedad importante es el “ancho” de este gráfico de flujo de datos – especialmente cuando hay patrones regulares, como calcular una operación particular en una secuencia regular de datos (vectorización).

  • para las GPU, desea una vectorización muy amplia (decenas de miles) y patrones de acceso muy regulares. idealmente, algo así como, bueno, gráficos: ejecutar un programa independiente corto (sombreador) para cada píxel dentro de un polígono. Los sombreadores pueden ejecutar condicionales, pero duelen si los sombreadores cercanos toman caminos diferentes (divergencia). (mover datos entre el host y la GPU no es un gran problema: es principalmente una cuestión de latencia, lo que hace que los cálculos cortos sean ineficientes. Los sistemas mundanos pueden hacer más que unos pocos GB / s). Vale la pena señalar que las CPU convencionales tienen soporte de hardware para la vectorización.
  • para subprocesos en CPU, básicamente desea que muchos cálculos involucren nodos de flujo de datos con un despliegue muy alto. es decir: una gran cantidad de datos que son de solo lectura o, principalmente, ya que la actualización de los datos compartidos es lo que mata el rendimiento de cualquier programa enhebrado. con el enhebrado no necesita una vectorización amplia de O (10,000), y la divergencia no es un problema en absoluto.
  • MPI es compartido, nada: tiene un montón de programas completamente independientes en ejecución, que pueden intercambiar mensajes. Por supuesto, existe la antigua dualidad entre la mensajería y la memoria compartida (enviar es como escribir, etc.). pero hay una gran asimetría: un mensaje tarda aproximadamente 1 us, pero una lectura de memoria compartida tarda 50 ns más o menos (suponiendo una falta de caché). Por lo tanto, es mucho más eficiente tener subprocesos que acceden a la memoria compartida en su mayoría leída, en lugar de enviar explícitamente esos valores. en otras palabras, importa cuán limpiamente pueda particionar su gráfico de flujo de datos para evitar mensajes a lo largo de la ruta crítica.

Conceptualmente, la ruta más “virtuosa” es probablemente usar MPI primero, luego enhebrar, luego vectorización / GPU. Esto se debe a que MPI lo obliga a ser bastante explícito sobre el flujo de datos, y luego el enhebrado le permite optimizar eso mediante la memoria compartida de lectura, luego la vectorización / GPU le permite aprovechar los gráficos secundarios altamente regulares e independientes.

Está preguntando acerca de tres modelos de programación aquí, pero están vinculados a los tipos de hardware. Por lo tanto, también debe considerar el hardware en la ecuación.

Mírelos en el contexto de un “clúster”: cada nodo en el clúster es probablemente un SMP, que consiste en al menos un chip multinúcleo. Un solo multinúcleo es un SMP, y múltiples “sockets” en un nodo del clúster generalmente se comportan como un SMP. En los grupos con los que trabajo, un nodo tiene 12 o 16 núcleos, distribuidos en 2 o 4 zócalos (chips), que pueden acceder a la memoria del otro. Hay muchos modelos de programación de “subprocesos” que pueden usar esta SMP-ness; el único con el que estoy realmente familiarizado es OpenMP, pero hay pThreads, Cilk, TBB, & c. Por cierto, el hecho de que este nodo sea físicamente un SMP no significa que tenga que programarlo como tal; Mira mi siguiente punto.

Tal nodo no es más poderoso que una PC robusta, por lo que si tiene un problema realmente grande, deja que miles de tales nodos trabajen juntos al conectarlos a alguna red, generalmente infiniband. No hay compiladores que puedan transformar un programa simple en un programa para un clúster, así que ahí es donde necesita MPI: usted especifica cómo pasan los datos a través de la red.

Ahora tiene un clúster con nodos SMP, por lo que podría hacer un enfoque híbrido de programación SMP / multiproceso en el nodo y MPI entre nodos. Como comenta Greg Lindahl, eso a menudo no es óptimo: sufre de la sobrecarga de la gestión de subprocesos, y tiene su propia versión de la ley de Amdahl, en el sentido de que se penaliza por secciones que son paralelas a MPI pero no a SMP. Por lo tanto, las personas a menudo ignoran la parte SMP y solo programan 1000 nodos por 16 núcleos SMP como si fueran 16,000 procesadores independientes, y generan tantas tareas MPI. Por lo general, la cantidad de memoria por núcleo es suficiente para que esto sea factible.

GPU De alguna manera son ortogonales a esta historia. Si tiene un clúster como se describe anteriormente, puede adjuntar una GPU a cada nodo y puede acelerar su código híbrido MPI / OpenMP al incluir núcleos CUDA.

Pero ahora hablemos de la superposición. MPI es necesario si tiene un problema realmente grande; supongamos que su problema cabe en un par de conciertos, entonces tiene la pregunta de programarlo en una biblioteca de subprocesos (incluido OpenMP), o de adjuntar una GPU y 1. resolverlo completamente en la GPU, o 2. encontrar alguna división del trabajo entre CPU y GPU. Para esto, lo remito a la respuesta de Julius Bier Kirkegaard, quien ha esbozado para qué tipo de operaciones se puede emplear una GPU útilmente.

Estos no son exclusivos, a menudo los 3 se usan juntos.

Casi siempre ocurre que combinar MPI y OpenMP es una mala idea, pero la gente todavía lo hace.

More Interesting

¿Cuál es el lenguaje de programación potente y fácil de hoy y de mañana?

¿Qué se necesita para ser investigador en informática, además de un doctorado? ¿Qué equipo necesita un investigador?

¿Cuánta similitud existe entre hacer compiladores y construir un analizador sintáctico que entienda un lenguaje natural?

¿Cuáles son los principales temas de investigación o proyectos que se relacionan entre la visión por computadora y la implementación de hardware en FPGA?

¿Cuáles son los mejores grupos de investigación de visión por computadora en Europa?

¿Cuáles son algunos de los temas que combinarían temas de informática y biología?

¿Me pueden ayudar a decidir si debo obtener un doctorado en informática teórica?

¿Se realiza más investigación de CS en la academia o la industria?

¿Cuáles son los códigos de simulación de última generación en dinámica de fluidos computacional?

¿Cuál debo elegir entre IIIT Allahabad IT y Jadavpur University CSE si estoy interesado en la codificación y la investigación en ciencias de la computación?

¿Cuán "ciegos" son los revisores de conferencias académicas? ¿Pueden los profesores y / o estudiantes de posgrado a menudo reconocer a los autores del trabajo, a pesar de que las revisiones son técnicamente "ciegas"?

¿Cuáles son los documentos de lectura obligatoria en el campo de la visión por computadora para un estudiante en la investigación en el campo?

¿Cuáles son algunas direcciones de investigación recientes en análisis y reconocimiento de rostros?

¿Cómo empiezo a aprender informática distribuida?

Doctorado en Informática: ¿Cuáles son las mejores ideas de temas de investigación de doctorado en HCI?