Je cours un projet utilisant Boost MPI (1.55) sur Open MPI (1.6.1) sur un cluster de calcul.Ouvrir MPI et Boost MPI en utilisant trop de handles de fichiers
Notre cluster a des nœuds qui ont 64 processeurs et nous engendrons un seul processus MPI sur chacun. La plupart de nos communications se font entre des processus individuels, chacun ayant une série de requêtes irecv() ouvertes (pour des balises différentes) et les envois sont bloqués en utilisant send().
Le problème que nous obtenons est que, après un court laps de temps de traitement (habituellement de moins de 10 minutes), nous obtenons cette erreur qui est à l'origine du programme à la fin:
[btl_tcp_component.c:1114:mca_btl_tcp_component_accept_handler] accept() failed: Too many open files in system (23).
débogage plus approfondi montre que ce sont les sockets réseau qui prennent ces handles de fichiers, et nous atteignons notre limite d'OS de 65536 poignées de fichiers ouvertes. La plupart d'entre elles sont dans le statut "TIME_WAIT", ce qui est apparemment ce que TCP fait (habituellement) 60 secondes après la fermeture d'un socket (afin d'intercepter les paquets en retard). J'avais l'impression qu'Open MPI ne fermait pas les sockets (http://www.open-mpi.org/faq/?category=tcp#tcp-socket-closing) et gardait simplement les sockets N^2 ouvertes pour que tous les processus puissent se parler. De toute évidence 65536 est bien au-delà de 64^2 (la cause la plus fréquente de cette erreur impliquant MPI est simplement que la limite de fichier est inférieure à N^2) et la plupart de ces sockets étaient dans un statut récemment fermé. Notre code C++ est trop grand pour tenir ici, mais j'en ai écrit une version simplifiée pour au moins montrer notre implémentation et voir s'il y a des problèmes avec notre technique. Y a-t-il quelque chose dans notre utilisation de MPI qui provoquerait la fermeture et la réouverture d'un trop grand nombre de sockets par OpenMPI?
namespace mpi = boost::mpi;
mpi::communicator world;
bool poll(ourDataType data, mpi::request & dataReq, ourDataType2 work, mpi::request workReq) {
if(dataReq.test()) {
processData(data); // do a bunch of work
dataReq = world.irecv(mpi::any_source, DATATAG, data);
return true;
}
if(workReq.test()) {
int target = assess(work);
world.send(target, DATATAG, dowork);
world.irecv(mpi::any_source, WORKTAG, data);
return true;
}
return false;
}
bool receiveFinish(mpi::request finishReq) {
if (finishReq.test()) {
world.send(0, RESULTS, results);
resetSelf();
finishReq = world.irecv(0, FINISH);
return true;
}
return false;
}
void run() {
ourDataType data;
mpi::request dataReq = world.irecv(mpi::any_source, DATATAG, data);
ourDataType2 work;
mpi::request workReq = world.irecv(mpi::any_source, WORKTAG, work);
mpi::request finishReq = world.irecv(0, FINISH); // the root process can call a halt
while(!receiveFinish(finishReq)) {
bool doWeContinue = poll(data, dataReq);
if(doWeContinue) {
continue;
}
// otherwise we do other work
results = otherwork();
world.send(0, RESULTS, results);
}
}
Oh mon cher C++, alors s'il vous plaît prenez ce qui suit avec l'énorme avertissement que je ne comprends pas ce langage ... De toute façon, je ne vois pas mpi_wait ou mpi_test - chaque fois que vous avez une communication mpi non bloquante une attente correspondante. Mon soupçon est que sans ces sockets ne sont pas fermés, mais je dois souligner que c'est une conjecture que l'attente/test pourrait être ailleurs, ou C++ pourrait être encore plus bizarre que je pense actuellement. –
Ouais @IanBush, C++ n'a pas été trop amical avec nous. Avec la couche Boost MPI en haut, les instructions comme dataReq.test() sont analogues à mpi_test sur cet irecv particulier. Je ne suis pas sûr s'il y a aussi un besoin d'attendre s'il y a un sondage régulier avec test? – Marc