¿Es seguro el hilo de armadillo solve ()?

86

En mi código tengo un bucle en el que construyo un sistema lineal sobredeterminado y trato de resolverlo:

#pragma omp parallel for
for (int i = 0; i < n[0]+1; i++) {
    for (int j = 0; j < n[1]+1; j++) {
        for (int k = 0; k < n[2]+1; k++) {
            arma::mat A(max_points, 2);
            arma::mat y(max_points, 1);
            // initialize A and y

            arma::vec solution = solve(A,y);
        }
    }
}

A veces, de forma bastante aleatoria, el programa se bloquea o los resultados en el vector de solución son NaN. Y si pongo haz esto:

arma::vec solution;
#pragma omp critical 
{
    solution = solve(weights*A,weights*y);
}

entonces estos problemas ya no parecen suceder.

Cuando se cuelga, lo hace porque algunos subprocesos están esperando en la barrera OpenMP:

Thread 2 (Thread 0x7fe4325a5700 (LWP 39839)):
#0  0x00007fe44d3c2084 in gomp_team_barrier_wait_end () from /usr/lib64/gcc-4.9.2/lib64/gcc/x86_64-redhat-linux-gnu/4.9.2/libgomp.so.1
#1  0x00007fe44d3bf8c2 in gomp_thread_start () at ../.././libgomp/team.c:118
#2  0x0000003f64607851 in start_thread () from /lib64/libpthread.so.0
#3  0x0000003f642e890d in clone () from /lib64/libc.so.6

Y los otros hilos están atrapados dentro de Armadillo:

Thread 1 (Thread 0x7fe44afe2e60 (LWP 39800)):
#0  0x0000003ee541f748 in dscal_ () from /usr/lib64/libblas.so.3
#1  0x00007fe44c0d3666 in dlarfp_ () from /usr/lib64/atlas/liblapack.so.3
#2  0x00007fe44c058736 in dgelq2_ () from /usr/lib64/atlas/liblapack.so.3
#3  0x00007fe44c058ad9 in dgelqf_ () from /usr/lib64/atlas/liblapack.so.3
#4  0x00007fe44c059a32 in dgels_ () from /usr/lib64/atlas/liblapack.so.3
#5  0x00007fe44f09fb3d in bool arma::auxlib::solve_ud<double, arma::Glue<arma::Mat<double>, arma::Mat<double>, arma::glue_times> >(arma::Mat<double>&, arma::Mat<double>&, arma::Base<double, arma::Glue<arma::Mat<double>, arma::Mat<double>, arma::glue_times> > const&) () at /usr/include/armadillo_bits/lapack_wrapper.hpp:677
#6  0x00007fe44f0a0f87 in arma::Col<double>::Col<arma::Glue<arma::Glue<arma::Mat<double>, arma::Mat<double>, arma::glue_times>, arma::Glue<arma::Mat<double>, arma::Mat<double>, arma::glue_times>, arma::glue_solve> >(arma::Base<double, arma::Glue<arma::Glue<arma::Mat<double>, arma::Mat<double>, arma::glue_times>, arma::Glue<arma::Mat<double>, arma::Mat<double>, arma::glue_times>, arma::glue_solve> > const&) ()
at /usr/include/armadillo_bits/glue_solve_meat.hpp:39

Como puede ver en el stacktrace, mi versión de Armadillo usa atlas. Y de acuerdo con este atlas de documentación parece ser seguro para subprocesos: ftp://lsec.cc.ac.cn/netlib/atlas/faq.html#tsafe

Actualización 11/09/2015

Finalmente tuve algo de tiempo para realizar más pruebas, según las sugerencias de Vladimir F.

Cuando compilo armadillo con BLAS de ATLAS, todavía puedo reproducir y luego cuelga y los NaN. Cuando se cuelga, lo único que cambia en el stacktrace es la llamada a BLAS:

#0  0x0000003fa8054718 in ATL_dscal_xp1yp0aXbX@plt () from /usr/lib64/atlas/libatlas.so.3
#1  0x0000003fb05e7666 in dlarfp_ () from /usr/lib64/atlas/liblapack.so.3
#2  0x0000003fb0576a61 in dgeqr2_ () from /usr/lib64/atlas/liblapack.so.3
#3  0x0000003fb0576e06 in dgeqrf_ () from /usr/lib64/atlas/liblapack.so.3
#4  0x0000003fb056d7d1 in dgels_ () from /usr/lib64/atlas/liblapack.so.3
#5  0x00007ff8f3de4c34 in void arma::lapack::gels<double>(char*, int*, int*, int*, double*, int*, double*, int*, double*, int*, int*) () at /usr/include/armadillo_bits/lapack_wrapper.hpp:677
#6  0x00007ff8f3de1787 in bool arma::auxlib::solve_od<double, arma::Glue<arma::Mat<double>, arma::Mat<double>, arma::glue_times> >(arma::Mat<double>&, arma::Mat<double>&, arma::Base<double, arma::Glue<arma::Mat<double>, arma::Mat<double>, arma::glue_times> > const&) () at /usr/include/armadillo_bits/auxlib_meat.hpp:3434

Compilando sin ATLAS, solo con netlib BLAS y LAPACK, pude reproducir los NaN pero no los bloqueos.

En ambos casos, rodeando solve()con #pragmaomp crítico no tengo ningún problema

maxdebayser
fuente
1
¿Es /usr/lib64/libblas.so.3 parte del atlas? ¿Por qué no se encuentra en / usr / lib64 / atlas?
Vladimir F
1
No, en opensuse es parte del paquete liblas3 y en redhat es parte del paquete blas.
maxdebayser
2
Entonces no puede utilizar ninguna garantía de ATLAS cuando utiliza el BLAS predeterminado.
Vladimir F
2
¿Has resuelto esto? Si no es así, ¿qué paquetes están instalados? ¿Podría publicar el comando que utilizó para compilar el programa?
vindvaki
3
También puede intentar usar OpenBLAS en lugar de Atlas.
2015

Respuestas:

2

¿Estás seguro de que tus sistemas están sobre determinados? solve_uden su seguimiento de pila dice lo contrario. Aunque tú solve_odtambién, y probablemente eso no tenga nada que ver con el problema. Pero no está de más descubrir por qué está sucediendo y solucionarlo si cree que los sistemas deberían funcionar.

¿Es seguro el hilo de armadillo solve ()?

Eso creo que depende de tu versión de lapack, mira también esto . Mirar el código de solve_odtodas las variables a las que se accede parece ser local. Tenga en cuenta la advertencia en el código:

NOTA: la función dgels () en la biblioteca lapack proporcionada por ATLAS 3.6 parece tener problemas

Por lo tanto, parece que solo lapack::gelspuede causarle problemas. Si no es posible arreglar lapack, una solución es apilar sus sistemas y resolver un solo sistema grande. Eso probablemente sería aún más eficiente si sus sistemas individuales fueran pequeños.

hormiga de fuego
fuente
1

La seguridad del subproceso de la solve()función de Armadillo depende (solo) de la biblioteca BLAS que utilice. Las implementaciones de LAPACK son seguras para subprocesos cuando BLAS lo es. La solve()función Armadillo no es segura para subprocesos cuando se vincula a la biblioteca BLAS de referencia . Sin embargo, es seguro para subprocesos cuando se usa OpenBLAS . Además, ATLAS proporciona una implementación BLAS que también menciona que es seguro para subprocesos , y Intel MKL también es seguro para subprocesos , pero no tengo experiencia con Armadillo vinculado a esas bibliotecas.

Por supuesto, esto solo se aplica cuando se ejecuta solve()desde varios subprocesos con datos diferentes.

André Offringa
fuente