Armadillo Solve () est-il sûr pour les threads?

86

Dans mon code, j'ai une boucle dans laquelle je construis et sur un système linéaire déterminé et j'essaye de le résoudre:

#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);
        }
    }
}

Parfois, de manière assez aléatoire, le programme se bloque ou les résultats dans le vecteur de solution sont NaN. Et si je mets fais ça:

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

alors ces problèmes ne semblent plus se produire.

Lorsqu'il se bloque, il le fait car certains threads attendent à la barrière 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

Et les autres fils sont coincés à l'intérieur d'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

Comme vous pouvez le voir sur le stacktrace, ma version d'Armadillo utilise atlas. Et d'après cette documentation, l'atlas semble être thread-safe: ftp://lsec.cc.ac.cn/netlib/atlas/faq.html#tsafe

Mise à jour du 11/09/2015

J'ai enfin eu le temps d'exécuter d'autres tests, sur la base des suggestions de Vladimir F.

Lorsque je compile le tatou avec le BLAS d'ATLAS, je suis toujours capable de reproduire puis se bloque et les NaN. Lorsqu'il se bloque, la seule chose qui change dans le stacktrace est l'appel à 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

Compiler sans ATLAS, uniquement avec netlib BLAS et LAPACK, j'ai pu reproduire les NaN mais pas les blocages.

Dans les deux cas, entourant solve()avec #pragmaomp critique je n'ai aucun problème

maxdebayser
la source
1
/Usr/lib64/libblas.so.3 fait-il partie de l'atlas? Pourquoi il ne se trouve pas dans / usr / lib64 / atlas?
Vladimir F
1
Non, dans opensuse, cela fait partie du package liblas3 et en redhat, cela fait partie du package blas.
maxdebayser
2
Vous ne pouvez alors utiliser aucune garantie d'ATLAS lorsque vous utilisez le BLAS par défaut.
Vladimir F
2
Avez-vous résolu ce problème? Sinon, quels packages sont installés et pourriez-vous s'il vous plaît poster la commande que vous avez utilisée pour compiler le programme?
vindvaki
3
Vous pouvez également essayer d'utiliser OpenBLAS au lieu d'Atlas.
mtall

Réponses:

2

Êtes-vous sûr que vos systèmes sont surdéterminés? solve_uddans votre trace de pile dit le contraire. Bien que vous ayez solve_odaussi, et probablement cela n'a rien à voir avec le problème. Mais cela ne fait pas de mal de trouver pourquoi cela se produit et de le réparer si vous pensez que les systèmes devraient être od.

Armadillo Solve () est-il sûr pour les threads?

Cela dépend, je pense, de votre version de lapack, voyez aussi ceci . Regarder le code de solve_odtoutes les variables accédées semble être local. Notez l'avertissement dans le code:

REMARQUE: la fonction dgels () de la bibliothèque lapack fournie par ATLAS 3.6 semble avoir des problèmes

Ainsi, il semble que cela ne lapack::gelspeut que vous causer des problèmes. Si la réparation de lapack n'est pas possible, une solution de contournement consiste à empiler vos systèmes et à résoudre un seul grand système. Ce serait probablement encore plus efficace si vos systèmes individuels étaient petits.

pompier
la source
1

La sécurité des threads de la solve()fonction d'Armadillo dépend (uniquement) de la bibliothèque BLAS que vous utilisez. Les implémentations LAPACK sont thread-safe lorsque BLAS l'est. La solve()fonction Armadillo n'est pas thread-safe lors de la liaison à la bibliothèque BLAS de référence . Cependant, il est thread-safe lors de l'utilisation d' OpenBLAS . De plus, ATLAS fournit une implémentation BLAS qui mentionne également qu'il est thread-safe , et Intel MKL est également thread-safe. , mais je n'ai aucune expérience avec Armadillo lié à ces bibliothèques.

Bien sûr, cela ne s'applique que lorsque vous exécutez à solve()partir de plusieurs threads avec des données différentes.

André Offringa
la source