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
VecView
yMatView
), y compárela con la salida conocida con algo comondiff
onumdiff
. 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 simplediff
, 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).
mpiexec
para ejecutarlo e incluir llamadas como PETScInitialize
/ PETScFinalize
en 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.
RHSFunction
y RHSJacobian
en ${PETSC_DIR}/src/ts/examples/tutorials/ex.2
) de forma aislada.