2009-12-26 32 views
20

Mi aplicación unix/windows C++ ya está paralelizada utilizando MPI: el trabajo se divide en N cpus y cada fragmento se ejecuta en paralelo, bastante eficiente, muy buena escala de velocidad, el trabajo se hace bien .memoria compartida, MPI y sistemas de colas

Pero algunos de los datos se repiten en cada proceso, y por razones técnicas, estos datos no se pueden dividir fácilmente en MPI (...). Por ejemplo:

  • 5 Gb de datos estáticos, exactamente lo mismo cargado para cada proceso
  • 4 Gb de datos que puede ser distribuido en MPI, se utilizan los más CPU, más pequeño este RAM por CPU es .

En un trabajo de 4 CPU, esto significaría al menos una carga de RAM de 20Gb, la mayor parte de la memoria 'desperdiciada', esto es horrible.

Estoy pensando en utilizar la memoria compartida para reducir la carga general, el trozo "estático" se cargará una sola vez por computadora.

Por lo tanto, la pregunta principal es:

  • ¿Hay alguna manera estándar MPI para compartir la memoria en un nodo? Algún tipo de biblioteca disponible + gratuita?

    • De lo contrario, utilizaría boost.interprocess y usaría las llamadas MPI para distribuir los identificadores de memoria compartida local.
    • La memoria compartida sería leída por un "maestro local" en cada nodo, y compartida de solo lectura. No es necesario ningún tipo de semáforo/sincronización, porque no cambiará.
  • ¿Hay algún problema de rendimiento o problemas particulares de los que tenga cuidado?

    • (No habrá ningún "cadenas" o estructuras de datos excesivamente extraños, todo puede reducirse a arreglos y apuntadores estructura)
  • El trabajo se ejecuta en un PBS (o SGE) sistema de colas, en el caso de una salida impura del proceso, me pregunto si esas limpiarán la memoria compartida específica del nodo.

+0

Después de las respuestas hasta ahora, pruebas y lecturas adicionales, los archivos mapeados en memoria podrían ser la opción más fácil: - Solo el proceso maestro MPI necesitaría "preparar" el archivo de memoria, que será mapeado por todos los procesos. - Dado que el archivo será de solo lectura, no hay necesidad de preocuparse por la coherencia del contenido. - No hay idea sobre el rendimiento aunque ... tal vez solo el experimento diga. – Blklight

+0

El rendimiento depende completamente de su plataforma. Sus detalles son escasos, pero dado sus CPU y RAM disponibles, no debería tener un gran problema. El único lugar donde fallan los archivos mmapped es si necesita cambiar la memoria compartida (sus datos distribuidos), no necesita que los contenidos de la memoria compartida sean persistentes, y solo necesita RAM compartida. En ese caso, su sistema perderá mucho tiempo escribiendo todos sus cambios de memoria en el disco. –

+0

Estaba ausente y no pude elegir en la respuesta final, la que obtuvo más votos :) Pero bueno, muchas buenas respuestas, pero nada que responda exactamente a lo que estaba buscando, así que supongo que no hay una gran cantidad de respuestas. -forma estandarizada para hacer esto! – Blklight

Respuesta

9

Un enfoque cada vez más común en el cómputo de alto rendimiento (HPC) es híbrido MPI/programas OpenMP. Es decir. tiene procesos N MPI y cada proceso MPI tiene M hilos.Este enfoque se correlaciona bien con clústeres que consisten en nodos multiprocesador de memoria compartida.

Cambiar a un esquema de paralelización jerárquica obviamente requiere algunos cambios más o menos invasivos, OTOH si se realiza correctamente puede aumentar el rendimiento y la escalabilidad del código, además de reducir el consumo de memoria para los datos replicados.

Dependiendo de la implementación de MPI, puede o no poder realizar llamadas MPI desde todos los hilos. Esto se especifica mediante los argumentos required y provided a la función MPI_Init_Thread() a la que debe llamar en lugar de MPI_Init(). Los valores posibles son

 
{ MPI_THREAD_SINGLE} 
    Only one thread will execute. 
{ MPI_THREAD_FUNNELED} 
    The process may be multi-threaded, but only the main thread will make MPI calls (all MPI calls are ``funneled'' to the main thread). 
{ MPI_THREAD_SERIALIZED} 
    The process may be multi-threaded, and multiple threads may make MPI calls, but only one at a time: MPI calls are not made concurrently from two distinct threads (all MPI calls are ``serialized''). 
{ MPI_THREAD_MULTIPLE} 
    Multiple threads may call MPI, with no restrictions. 

En mi experiencia, las implementaciones modernas como Open MPI MPI apoyan la MPI_THREAD_MULTIPLE más flexible. Si usa bibliotecas MPI antiguas o alguna arquitectura especializada, es posible que esté peor.

Por supuesto, no es necesario que enhebre con OpenMP, esa es la opción más popular en HPC. Puede usar, p. la biblioteca de hilos Boost, la biblioteca Intel TBB, o los subprocesos pthreads o windows para ese asunto.

+0

Si cambia el código para que tenga varios subprocesos en cada nodo de múltiples procesadores de memoria compartida, asegúrese de escribir su programación de subprocesos cuidadosamente para tener en cuenta la localidad de memoria caché y otra arquitectura de memoria. – stephan

+2

No estoy seguro de que el enfoque híbrido sea cada vez más común. Aquí hay un ejemplo de la evidencia de que puede no ser un enfoque que valga la pena tomar: http://www.pdc.kth.se/education/historical/2008/PRACE-P2S2/coursework/handouts.html#hybrid Sí, es un concepto agradable, pero en la práctica tiene un valor dudoso comparado con el esfuerzo requerido para modificar su aplicación. –

+0

esta respuesta no aborda ninguno de los problemas en la pregunta – lurscher

0

No sé mucho sobre unix, y no sé qué es MPI. Pero en Windows, lo que está describiendo es una coincidencia exacta para un objeto de mapeo de archivos.

Si estos datos están incrustados en su .EXE o en un .DLL que se carga, se compartirá automáticamente entre todos los procesos. El desmontaje de su proceso, incluso como resultado de un bloqueo no causará fugas o bloqueos inéditos de sus datos. sin embargo, un .dll de 9 Gb suena un poco dudoso. Entonces esto probablemente no funcione para ti.

Sin embargo, puede poner sus datos en un archivo, luego CreateFileMapping y MapViewOfFile en él. La asignación puede ser de solo lectura, y puede asignar todo o parte del archivo a la memoria. Todos los procesos compartirán páginas asignadas al mismo objeto subyacente CreateFileMapping. es una buena práctica cerrar vistas de un mapa y cerrar identificadores, pero si no lo hace, el sistema operativo lo hará por usted en el momento del cierre.

Tenga en cuenta que a menos que esté ejecutando x64, no podrá asignar un archivo de 5 Gb en una sola vista (o incluso un archivo de 2 Gb, 1 Gb podría funcionar). Pero dado que estás hablando de que esto ya está funcionando, supongo que ya solo eres x64.

+0

De la documentación, infiero boost.interprocess permisos para hacer esto, de forma multiplataforma (no es necesario #ifdef) y con código "limpio". Y hay una opción específica de Windows que permite exactamente lo que describes. Pero la cuestión principal aquí no es la implementación técnica del sistema de memoria compartida, sino cómo hacerlo limpiamente cuando tienes 128 instancias de tus aplicaciones distribuidas en máquinas de 8 núcleos :-) – Blklight

+1

No estoy seguro de por qué Eso sería un problema. ¿Estás diciendo que quieres compartir en varias _máquinas_. Estoy bastante seguro de que cada máquina va a ver solo su propia RAM, y que todos los núcleos en una máquina comparten una vista de la memoria RAM de esas máquinas. –

0

Si almacena sus datos estáticos en un archivo, puede usar mmap en Unix para obtener acceso aleatorio a los datos. Los datos serán localizados cuando usted necesite acceder a un bit de datos en particular. Todo lo que tendrá que hacer es superponer cualquier estructura binaria a los datos del archivo. Este es el equivalente de Unix de CreateFileMapping y MapViewOfFile mencionado anteriormente.

Incidentalmente, glibc usa mmap cuando uno llama a malloc para solicitar más de una página de datos.

+0

El umbral glibc malloc mmap es de forma predeterminada 128 kB, que no tiene el mismo tamaño que una página. – janneb

7

No he trabajado con MPI, pero si es como otras bibliotecas de IPC que he visto que ocultan si otros hilos/procesos/lo que sea están en la misma máquina o en máquinas diferentes, entonces no podrá garantizar compartida memoria. Sí, podría manejar la memoria compartida entre dos nodos en la misma máquina, si esa máquina proporcionara memoria compartida. Pero tratar de compartir memoria entre nodos en diferentes máquinas sería muy difícil en el mejor de los casos, debido a los complejos problemas de coherencia planteados. Esperaría que simplemente no se implemente.

En la práctica, si necesita compartir memoria entre nodos, su mejor opción es hacer eso fuera de MPI. no creo que necesite utilizar la memoria compartida de estilo boost.interprocess, ya que no está describiendo una situación en la que los diferentes nodos realizan cambios precisos en la memoria compartida; es de solo lectura o particionado.

Las respuestas de John y deus cubren cómo mapear en un archivo, que es definitivamente lo que quieres hacer para los datos estáticos de 5 Gb (giga bit?). Los datos por CPU suenan como lo mismo, y solo necesita enviar un mensaje a cada nodo indicándole qué parte del archivo debe captar. El sistema operativo debería encargarse de asignar la memoria virtual a la memoria física de los archivos.

En cuanto a la limpieza ... Supongo que no hace ninguna limpieza de memoria compartida, pero los archivos mmap ed deben limpiarse ya que los archivos están cerrados (lo que debería liberar sus asignaciones de memoria) cuando se limpia un proceso . No tengo idea de qué advertencias CreateFileMapping etc. tienen.

La "memoria compartida" real (es decir, boost.interprocess) no se limpia cuando un proceso se apaga. Si es posible, recomiendo intentar matar un proceso y ver lo que queda atrás.

0

Tuve algunos proyectos con MPI en SHUT.

que sé, hay muchas maneras de distribuir un problema utilizando MPI, tal vez pueda encontrar otra solución que no requiere de memoria compartida, mi proyecto fue resolver una ecuación 7.000.000 y 7.000.000 variable de

si puede explicar su problema, trataría de ayudarlo

+0

Por supuesto, la parte "estática" del problema podría ser paralelizada mejor, pero el tiempo de desarrollo sería enorme. La mayor parte de la memoria del problema "completo" es posible cargar * una vez * en cada nodo de cálculo. Por lo tanto, mi objetivo es compartir la memoria y apuntar la mejor técnica para hacerlo. – Blklight

+0

Lo que me gustaría saber es qué clase de problema estaba resolviendo con 7 * 10^6 variables. –

2

Con MPI-2 tiene RMA (acceso a memoria remota) a través de funciones como MPI_Put y MPI_Get. Si utiliza estas características, si su instalación MPI las admite, sin duda le ayudaría a reducir el consumo total de memoria de su programa. El costo se agrega complejidad en la codificación, pero eso es parte de la diversión de la programación paralela. Por otra parte, te mantiene en el dominio de MPI.

+0

¿No aumentaría eso enormemente la latencia de los accesos a la memoria compartida? ¿O es MPI_Get simplemente un alias para una búsqueda directa en el bus de memoria? – Crashworks

+0

@Crashworks Sí, MPI-2 RMA no es realmente más rápido que el envío/recepción tradicional. En muchos casos más lento, debido a la necesidad de registrar ventanas de memoria. En principio, en el futuro con soporte de hardware de red especial podría ser más rápido, pero hoy hay pocas razones para usarlo. – janneb

+0

Sí de hecho. Pero quizás una razón para usar MPI2 RMA es hacer programación de memoria compartida dentro del paradigma MPI, sin tener que recurrir a funciones de nivel inferior como archivos mapeados en memoria o bibliotecas IPC. El costo de un rendimiento de ejecución marginalmente mejor puede ser un rendimiento de desarrollo mucho más bajo. Me pregunto qué está haciendo el PO de todo esto. –

0

Me encontré con este problema en el pequeño cuando utilicé MPI hace unos años.

No estoy seguro de que la SGE comprenda los archivos mapeados en la memoria. Si está distribuyendo contra un clúster Beowulf, sospecho que tendrá problemas de coherencia. ¿Podría hablar un poco sobre su arquitectura multiprocesador?

Mi enfoque de borrador sería configurar una arquitectura donde cada parte de los datos es propiedad de una CPU definida. Habría dos hilos: un hilo sería un hablante bidireccional MPI y un hilo para calcular el resultado. Tenga en cuenta que MPI y los hilos no siempre funcionan bien juntos.

+0

Sí, los datos son propiedad de una sola CPU y de solo lectura. No hay problema de coherencia aquí. Por lo tanto, el archivo mapeado en memoria podría ser una opción fácil. – Blklight

+0

De acuerdo. Pero eso va a depender de tu arquitectura. los archivos memmapped son mejores en una arquitectura de memoria compartida. No estoy seguro de * cómo * lo harías con un clúster Beowulf. –

Cuestiones relacionadas