Estoy trabajando en un problema que se puede paralelizar usando una sola operación mpi_allgather o una operación mpi_scatter y una mpi_gather. Estas operaciones se llaman dentro de un ciclo while, por lo que se pueden llamar muchas veces.
En la implementación con un esquema MPI_allgather, estoy reuniendo un vector distribuido en todos los procesos para la resolución de matrices duplicadas. En la otra implementación, reúno el vector distribuido en un único procesador (el nodo raíz), resuelvo el sistema lineal en este procesador y luego vuelvo a dispersar el vector solución en todos los procesos.
Tengo curiosidad por saber si el costo de una operación de recolección total es significativamente mayor que las operaciones de dispersión y recolección combinadas. ¿La longitud del mensaje juega un papel importante en su complejidad? ¿Varía entre implementaciones de mpi?
Editar:
fuente
MPI_Scatter
seguido porMPI_Gather
no proporciona la misma comunicación semántica queMPI_Allgather
. ¿Quizás haya redundancia involucrada cuando expresa la operación de cualquier manera?MPI_Gather
seguido de aMPI_Bcast
?Respuestas:
Primero, la respuesta exacta depende de: (1) uso, es decir, argumentos de entrada de función, (2) calidad y detalles de implementación de MPI, y (3) el hardware que está utilizando. A menudo, (2) y (3) están relacionados, como cuando el proveedor de hardware optimiza MPI para su red.
En general, fusionar colectivos MPI es mejor para mensajes más pequeños, ya que los costos iniciales pueden no ser triviales y la sincronización que conlleva bloquear colectivos debe minimizarse si hay una variación en el tiempo de cómputo entre llamadas. Para mensajes más grandes, el objetivo debe ser minimizar la cantidad de datos que se envían.
Por ejemplo, en teoría,
MPI_Reduce_scatter_block
debería ser mejor que loMPI_Reduce
seguidoMPI_Scatter
, aunque el primero a menudo se implementa en términos del segundo, de modo que no haya una ventaja real. Existe una correlación entre la calidad de la implementación y la frecuencia de uso en la mayoría de las implementaciones de MPI, y los proveedores obviamente optimizan las funciones para las cuales esto es requerido por el contrato de la máquina.Por otro lado, si uno está en un Blue Gene, el
MPI_Reduce_scatter_block
usoMPI_Allreduce
, que hace más comunicación queMPI_Reduce
yMPI_Scatter
combinado, en realidad es bastante más rápido. Esto es algo que descubrí recientemente y es una violación interesante del principio de autoconsistencia de rendimiento en MPI (este principio se describe con más detalle en las "Pautas de rendimiento de MPI autoconsistentes" ).En el caso específico de dispersión + reunión versus reunión total, considere que en la primera, todos los datos deben ir hacia y desde un solo proceso, lo que lo convierte en el cuello de botella, mientras que en la reunión general, los datos pueden entrar y salir de todos los rangos inmediatamente , porque todos los rangos tienen algunos datos para enviar a todos los demás. Sin embargo, enviar datos desde todos los nodos a la vez no es necesariamente una buena idea en algunas redes.
Finalmente, la mejor manera de responder a esta pregunta es hacer lo siguiente en su código y responder la pregunta por experimento.
Una opción aún mejor es hacer que su código lo mida experimentalmente durante las dos primeras iteraciones, luego use el que sea más rápido para las iteraciones restantes:
fuente
Jeff tiene toda la razón acerca de que la única manera de estar seguro es medir: después de todo, somos científicos, y esta es una pregunta empírica, y brinda excelentes consejos sobre cómo implementar tales mediciones. Permítanme ahora ofrecer una visión contraria (o, tal vez, complementaria).
Hay que hacer una distinción entre escribir un código para ser ampliamente utilizado y ajustarlo a un fin específico. En general, estamos haciendo lo primero: crear nuestro código para que a) podamos usarlo en una amplia variedad de plataformas, yb) el código se pueda mantener y ampliar en los años venideros. Pero a veces estamos haciendo lo otro: tenemos un año de asignación en una máquina grande, y estamos aumentando el conjunto requerido de simulaciones grandes y necesitamos una cierta línea de base de rendimiento para obtener lo que necesitamos hacer durante el momento de la asignación otorgada.
Cuando estamos escribiendo código, hacer que sea ampliamente utilizable y mantenible es mucho más importante que reducir un pequeño porcentaje del tiempo de ejecución en una máquina en particular. En este caso, lo correcto es casi siempre usar la rutina que mejor describa lo que desea hacer: esta es generalmente la llamada más específica que puede hacer y que hace lo que desea. Por ejemplo, si un allgather o allgatherv directo hace lo que desea, debe usar eso en lugar de deshacerse de las operaciones de dispersión / recolección. Las razones son que:
En este caso bastante común, si descubre que algún colectivo MPI funciona de manera irrazonablemente lenta en su máquina, lo mejor que puede hacer es presentar un informe de error con el proveedor de mpi; no desea complicar su propio software tratando de evitar el código de la aplicación, lo que debería corregirse correctamente en el nivel de la biblioteca MPI.
Sin embargo . Si está en modo "sintonización": tiene un código que funciona, debe aumentar a escalas muy grandes en un corto período de tiempo (por ejemplo, una asignación de un año), y ha perfilado su código y descubrió que esta parte particular de su código es un cuello de botella, entonces tiene sentido comenzar a realizar estas afinaciones muy específicas. Esperemos que no sean partes a largo plazo de su código; idealmente, estos cambios permanecerán en alguna rama específica del proyecto de su repositorio, pero es posible que deba hacerlos. En ese caso, la codificación de dos enfoques diferentes que se distinguen por directivas de preprocesador, o un enfoque de "autoajuste" para un patrón de comunicación específico, puede tener mucho sentido.
Por lo tanto, no estoy en desacuerdo con Jeff, solo quiero agregar un contexto sobre cuándo debería preocuparse lo suficiente por esas preguntas de rendimiento relativo para modificar su código para tratarlo.
fuente