はじめに
これはMPI Advent Calendar 2017の7日目の記事です。「この辺でもう遠慮しようと思います」とか書いた気がしますがあれは嘘です。
並列コードを書くまでもない自明並列、いわゆる「バカパラ」をしたいときが結構あります。例えば大量のデータを処理したい、多数のフレームのレンダリングをしたい、などです。こんな要望に例えば「バルクジョブ」という形でシステム側で対応してくれているサイトもありますが、単純並列の場合は、MPIのラッパーを書いて、実行したいプログラムをstd::system
で呼び出す、ということをよくやります。
しかし、この子プロセスとして呼び出されるコードが、普通のシリアルプログラムではなく、MPIがリンクされた並列コードだと問題を起こすため、それについて紹介します。サンプルコードは
に置いておきます。
サンプルコード
まず、親プロセス側(呼び出し側)としてこんなコードを書きます。
#include <cstdio>
#include <cstdlib>
#include <mpi.h>
int main(int argc, char **argv) {
MPI_Init(&argc, &argv);
std::system("./b.out");
MPI_Finalize();
}
単にstd::system
でb.out
を実行するだけのコードです。
子プロセス側(呼び出され側)としてこんなコードを書いてみます。
#include <cstdio>
#include <mpi.h>
int main(int argc, char **argv) {
MPI_Init(&argc, &argv);
printf("Hello World\n");
MPI_Finalize();
}
何もせず、"Hello World"と表示するだけのコードです。ただしMPI_Init
とMPI_Finalize
は呼び出します。
さて、これをコンパイル、実行します。以下はMac上のOpen MPIの場合です。
$ mpicxx a.cpp -o a.out
$ mpicxx b.cpp -o b.out
$ mpiexec -np 2 ./a.out
Hello World
Hello World # ← ここでプログラム実行が止まり、正常終了しない
一応コードは実行できますが、最後で止まってしまいます。ここでCtrl+Cを押すとSIGSEGVを吐いて異常終了します。
別サイトでIntel MPIで実行してみると、やはり実行はできますが最後に
===================================================================================
= BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
= PID XXXX RUNNING AT hostname
= EXIT CODE: 13
= CLEANING UP REMAINING PROCESSES
= YOU CAN IGNORE THE BELOW CLEANUP MESSAGES
===================================================================================
みたいなエラーを吐いて死にます。
まとめ
MPIプログラムからstd::systemを使って子プロセスを大量に実行する、というのはよくやっていたのですが、子プロセスとしてMPIプログラムを実行すると異常終了する、というのは知らなかったのでシェアしてみました。よく考えると、MPIを多段実行していることになり、MPI_Finalizeがおかしくなるのはわかる気がしますが、実際そう言われるまでは気が付きませんでした。