¿Alguna recomendación para marcos de pruebas unitarias compatibles con código / bibliotecas que usan MPI?

13

Por lo general, escribo código de serie, y cuando lo hago, escribo pruebas unitarias con un marco de prueba de estilo xUnit (MATLAB xUnit, PyUnit / nose o el marco de prueba C ++ de Google).

Basado en una búsqueda superficial de Google, no he visto mucho sobre cómo los profesionales unen el código de prueba que usa MPI. ¿Hay alguna mejor práctica para eso?

En comparación con las Estrategias para pruebas unitarias y desarrollo basado en pruebas , estoy buscando respuestas relacionadas con el software que debo usar para un marco de prueba (si existe, la respuesta podría ser "rodar su propio código", en el que ejemplos de casos de código de prueba personalizado serían útiles).

La mayor parte de lo que estoy tratando de probar son evaluaciones de funciones del lado derecho y rutinas de ensamblaje de matriz jacobiana para steppers de tiempo que integrarán PDE semi-discretos. Usaré PETSc, por lo que si hay algo específico de PETSc, sería útil además de marcos de prueba más generales.

Ediciones de aclaración:

Un ejemplo sería ${PETSC_DIR}/src/ts/examples/tutorials/ex2.c, donde me gustaría probar algo como RHSFunction(una evaluación de la función del lado derecho) yRHSJacobian(una evaluación matricial jacobiana). Estaría probando contra valores conocidos para el lado derecho ensamblado y la matriz jacobiana ensamblada; Puedo obtener estos valores analíticamente para algunas instancias de problemas simples. Estas funciones son funciones específicas de la aplicación que no ejercerán ninguna otra función de nivel de aplicación, pero podrían llamar a MPI si el ensamblaje de vector o matriz se realiza dentro de la función (como en el ejemplo PETSc vinculado anterior). Si escribo funciones que solo calculan porciones de vectores o matrices locales para un procesador, me gustaría probar la versión global ensamblada si es posible porque, siendo nuevo en la programación paralela, es más intuitivo para mí pensar en vectores globales y globales. matrices Estas pruebas se ejecutarían en pequeños tamaños de problemas y pequeños números de procesadores.

Se me ocurren algunas estrategias para hacer esto:

  • Una estrategia que probablemente no funcionará bien, basada en las búsquedas de Google que he hecho sobre este tema, sería construir una salida conocida, encontrar el error relativo / absoluto en paralelo y luego hacer comparaciones ingenuas. La salida probablemente será confusa : cualquiera que haya escrito un programa "Hola, mundo" con MPI sabe por qué, lo que limita la utilidad de realizar las pruebas unitarias. ( Este fue el ímpetu para hacer la pregunta ) . También parece haber algún truco potencial al llamar al marco de pruebas unitarias.
  • Escriba la salida en el archivo (en PETSc, por ejemplo, usando VecViewy MatView), y compárela con la salida conocida con algo como ndiffo numdiff. Mi instinto con este método de la experiencia previa al hacer pruebas unitarias con comparaciones de archivos es que será meticuloso y requerirá algo de filtrado. Sin embargo, parece que este método sería excelente para las pruebas de regresión, ya que podría reemplazar las utilidades anteriores por una simple diff, y no tener que preocuparme por hacer coincidir los formatos de texto. He deducido que esta estrategia es más o menos lo que sugieren WolfgangBangerth y Andybauer. PETSc también parece utilizar un enfoque similar para algunas de las pruebas que realiza.
  • Use un marco de prueba de unidad, reúna todo en el procesador con rango 0 de MPI y pídale que ejecute pruebas de unidad solo si el rango de procesador es 0. Podría hacer algo similar con las normas (probablemente sea aún más fácil de esa manera), aunque la compensación es que cualquier error devuelto me indicará que tengo un problema en mi cálculo, pero no qué elementos están en error. Entonces no necesito preocuparme de que cualquier salida de prueba de unidad sea confusa; Solo necesito preocuparme por llamar al marco de prueba de la unidad correctamente. PETSc parece usar comparaciones basadas en normas dentro de sus programas de ejemplo cuando hay soluciones exactas disponibles, pero no utiliza un marco de prueba de unidad cuando hace esas comparaciones (ni debería hacerlo necesariamente).
Geoff Oxberry
fuente
Solo estoy familiarizado con las suites de pruebas internas, por lo que no puedo recomendar nada. Dicho esto, ¿ninguna de estas suites de prueba le permite especificar cómo ejecutar el ejecutable que crea? Si lo hacen, debería ser trivial crear pruebas que funcionen para los programas MPI.
Bill Barth
Ellos deberían. En cualquier lenguaje compilado, es solo un ejecutable, por lo que no debería ser un problema usarlo mpiexecpara ejecutarlo e incluir llamadas como PETScInitialize/ PETScFinalizeen el código de configuración / desmontaje. (Presumiblemente, si no estuviera usando PETSc, reemplazaría esas llamadas con análogos de MPI_Init/ MPI_Finalize, dependiendo de las bibliotecas que esté usando). El marco de prueba de Google es un lanzamiento basado en la fuente, por lo que lo compilo junto con el código I escribir tampoco sería un problema.
Geoff Oxberry
Su descripción del problema me sugiere que está interesado en utilizar un marco de pruebas unitarias para ejecutar pruebas de integración / regresión. No hay nada de malo en eso per se, pero es posible que desee aclarar su pregunta un poco más. Creo que si le preguntaras a un experto en pruebas unitarias cómo escribir pruebas unitarias para tu código científico, te dirían que escribas pruebas de forma modular. Es decir, la mayoría de sus pruebas no tendrían llamadas MPI adecuadas en ellas.
Aron Ahmadia
Déjame ser más concreto. Algo que me gustaría probar en un pequeño problema con un pequeño número de procesadores (por ejemplo, 1-4) sería si mi matriz jacobiana ensamblada realmente da como resultado el jacobiano global adecuado. También me gustaría probar mi función del lado derecho contra un lado derecho global conocido. Cada prueba de este tipo debe ejercer todavía sólo una única función en la aplicación (por ejemplo, en PETSc, poniendo a prueba RHSFunctiony RHSJacobianen ${PETSC_DIR}/src/ts/examples/tutorials/ex.2) de forma aislada.
Geoff Oxberry
No creo que exista un marco que te ayude a hacer lo que quieres. Nos las hemos arreglado para hacer algunas cosas por nosotros en PyClaw (y Lisandro lo ha usado en mpi4py y petsc4py). ¿Has mirado el marco de prueba en mpich?
Aron Ahmadia

Respuestas:

8

Soy un usuario feliz de GoogleTest con un código MPI de C ++ en un entorno de compilación CMake / CTest:

  • ¡CMake instala / enlaza automáticamente googletest desde svn!
  • ¡Agregar pruebas es una frase!
  • ¡Escribir las pruebas es fácil! (¡y Google Mock es muy poderoso!)
  • ¡CTest puede pasar parámetros de línea de comandos a sus pruebas y exporta datos a CDash!

Así es como funciona. Un lote de pruebas unitarias que requieren mpi se escriben en algún my_mpi_test.cpparchivo que se ve así:

#include <gtest/gtest.h>
#include <boost/mpi.h>

/// Most testing libraries allow to define main yourself to override initialization.
int main(int argc, char* argv[]) {
    ::testing::InitGoogleTest(&argc, argv);  /// Set gtest environment
    mpi::environment env(argc, argv);  /// Set mpi environment
    return RUN_ALL_TESTS();  /// Execute all gtest tests
}

TEST(test_batch_name, test_name) {  /// Then you can create tests as usual,
  using namespace mpi;
  communicator world;  /// and use MPI inside your tests.
  /* ... test stuff here ... */
}

El CMakeLists.txt que agrega esta prueba es:

add_mpi_test(my_mpi 2)  # Uses 2 MPI processes

donde add_mpi_testenvuelve CMake's add_testdentro de mi raíz CMakeLists.txt:

function(add_mpi_test name no_mpi_proc)
  include_directories(${MY_TESTING_INCLUDES})
      # My test are all called name_test.cpp
      add_executable(${name} ${name}_test.cpp)
      add_dependencies(${name} googletest)
  # Make sure to link MPI here too:
  target_link_libraries(${name} ${MY_TESTING_LIBS})
  set(test_parameters ${MPIEXEC_NUMPROC_FLAG} ${no_mpi_proc} "./${name}")
      add_test(NAME ${name} COMMAND ${MPIEXEC} ${test_parameters})
endfunction(add_mpi_test)

Esta última parte no es necesaria, pero le permite agregar fácilmente pruebas mpi en una línea. Luego puede decidir si desea codificar el número de procesos MPI para cada prueba o leerlo a través de un parámetro de línea de comando para ctest.

gnzlbg
fuente
4

Existen varios paquetes de software habilitados para MPI que utilizan el conjunto de herramientas CMake para las pruebas. Los que puedo pensar en mi cabeza son Trilinos, VTK y ParaView. Creo que no querrás asumir que el ejecutable debe iniciarse con mpirun y / o mpiexec. CMake tiene soporte para especificar cómo iniciar correctamente el ejecutable junto con diferentes opciones, como el número máximo de procesos a usar y pre y post-flags, si es necesario.

Es posible que desee consultar la sección Sitios de HPC del panel de control de ParaView, donde las pruebas se ejecutan en una variedad de supercomputadoras NERSC y Argonne. Enterrados también hay la mayoría de las configuraciones que necesitarías especificar para que funcione en esas máquinas.

Como referencia, el panel de Trilinos tiene una amplia variedad de paquetes listados y para mí es bastante impresionante en su organización.

Divulgación completa: soy un empleado de Kitware y CMake es uno de los proyectos de código abierto en el que Kitware está involucrado.

andybauer
fuente
¡Gracias por la respuesta! He estado mirando CTest y no he encontrado ninguna documentación aparte de una descripción similar a una página de manual en el sitio web de KitWare. ¿Me puede recomendar algún tutorial disponible gratuitamente?
Geoff Oxberry
Hay mucha información en el wiki de CMake . Hay un montón de tutoriales para CMake, CTest y CPack allí. Encuentro la mayoría de mis respuestas a esas aplicaciones en Stack Overflow .
andybauer
andybauer - Gracias por la respuesta. ¿Le importaría editar su respuesta y divulgar su afiliación con KitWare?
Aron Ahmadia
3

Simplemente lanzamos nuestro propio código en el trato. II - en esencia, le decimos al framework que ejecute pruebas usando mpirun -np .... Anteriormente habíamos utilizado un esquema de prueba basado en Makefile (compilar, vincular, ejecutar la prueba, luego comparar el resultado con uno que se había guardado previamente) y puede encontrar esto aquí:

y para el contexto, los objetivos que no son MPI están aquí:

Estamos reescribiendo cosas usando CMake / CTest, con el desarrollo actual aquí:

Wolfgang Bangerth
fuente
Wolfgang, gracias por la respuesta! PETSc parece hacer algo similar.
Geoff Oxberry