2

ここ数日間、MPI を使用して、C でフォールト トレラントなアプリケーションを作成する実験を行ってきました。エラー ハンドラを MPI_COMM_WORLD コミュニケータにアタッチして、ノードがダウンした場合 (クラッシュが原因の可能性があります) に備える方法を学ぼうとしています。 MPI_Finalize() を呼び出さずに終了しても、プログラムはこの状況から回復して計算を続行できます。

これまでに発生した問題は、エラー ハンドラー関数を通信にアタッチしてノードをクラッシュさせた後、MPI がエラー ハンドラーを呼び出さず、すべてのスレッドを強制的に終了させることです。

自分のアプリケーションの問題かなと思い、ネットでサンプルコードを探して実行してみましたが同じ状況で… 現在実行しようとしているサンプルコードは以下の通りです。(ここから入手しましたhttps://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&ved=0CC4QFjAA&url=http%3A%2F%2Fwww.shodor.org% 2Fmedia%2Fcontent%2F%2Fpetascale%2Fmaterials%2FdistributedMemory%2Fpresentations%2FMPI_Error_Example.pdf&ei=jq6KUv-BBcO30QW1oYGABg&usg=AFQjCNFa5L_Q6Irg3VrJ3fsQBIyqjBlSgA&sig2=8An4SqBvhCACx5YLwBmROA apologies for being in pdf but i didnt write it, so I now paste the same code below):

/* Template for creating a custom error handler for MPI and a simple program 
to demonstrate its' use. How much additional information you can obtain 
is determined by the MPI binding in use at build/run time. 

To illustrate that the program works correctly use -np 2 through -np 4.

To illustrate an MPI error set victim_mpi = 5 and use -np 6.

To illustrate a system error set victim_os = 5 and use -np 6.

2004-10-10 charliep created
2006-07-15 joshh  updated for the MPI2 standard
2007-02-20 mccoyjo  adapted for folding@clusters
2010-05-26 charliep cleaned-up/annotated for the petascale workshop 
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "mpi.h"

void ccg_mpi_error_handler(MPI_Comm *, int *, ...);

int main(int argc, char *argv[]) {
    MPI_Status status;
    MPI_Errhandler errhandler;
    int number, rank, size, next, from;
    const int tag = 201;
    const int server = 0;
    const int victim_mpi = 5;
    const int victim_os = 6;

    MPI_Comm bogus_communicator;
    MPI_Init(&argc, &argv);!
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    MPI_Comm_create_errhandler(&ccg_mpi_error_handler, &errhandler);
    MPI_Comm_set_errhandler(MPI_COMM_WORLD, errhandler);

    next = (rank + 1) % size;
    from = (rank + size - 1) % size;

    if (rank == server) {
        printf("Enter the number of times to go around the ring: ");
        fflush(stdout);
        scanf("%d", &number);                                              
        --number;
        printf("Process %d sending %d to %d\n", rank, number, next);
        MPI_Send(&number, 1, MPI_INT, next, tag, MPI_COMM_WORLD);
    }

    while (true) {
        MPI_Recv(&number, 1, MPI_INT, from, tag, MPI_COMM_WORLD, &status);
        printf("Process %d received %d\n", rank, number);
        if (rank == server) {
            number--;
            printf("Process 0 decremented number\n");
        }

        if (rank == victim_os) {
            int a[10];
            printf("Process %d about to segfault\n", rank);
            a[15565656] = 56;
        }

        if (rank == victim_mpi) {
            printf("Process %d about to go south\n", rank);
            printf("Process %d sending %d to %d\n", rank, number, next);
           MPI_Send(&number, 1, MPI_INT, next, tag, bogus_communicator);
        } else {
            printf("Process %d sending %d to %d\n", rank, number, next);
            MPI_Send(&number, 1, MPI_INT, next, tag, MPI_COMM_WORLD);
        }

        if (number == 0) {
            printf("Process %d exiting\n", rank);
            break;
        }
    }

    if (rank == server)
        MPI_Recv(&number, 1, MPI_INT, from, tag, MPI_COMM_WORLD, &status);

    MPI_Finalize();
    return 0;
}

void ccg_mpi_error_handler(MPI_Comm *communicator, int *error_code, ...) {
    char error_string[MPI_MAX_ERROR_STRING];
    int error_string_length;
    printf("ccg_mpi_error_handler: entry\n");
    printf("ccg_mpi_error_handler: error_code = %d\n", *error_code);
    MPI_Error_string(*error_code, error_string, &error_string_length);
    error_string[error_string_length] = '\0';
    printf("ccg_mpi_error_handler: error_string = %s\n", error_string);
    printf("ccg_mpi_error_handler: exit\n");
    exit(1);
}

プログラムは単純なトークン リングを実装し、コメントで説明されているパラメーターを指定すると、次のようになります。

    >>>>>>mpirun -np 6 example.exe
    Enter the number of times to go around the ring: 6
    Process 1 received 5
    Process 1 sending 5 to 2
    Process 2 received 5
    Process 2 sending 5 to 3
    Process 3 received 5
    Process 3 sending 5 to 4
    Process 4 received 5
    Process 4 sending 5 to 5
    Process 5 received 5
    Process 5 about to go south
    Process 5 sending 5 to 0
    Process 0 sending 5 to 1
    [HP-ENVY-dv6-Notebook-PC:09480] *** Process received signal *** 
    [HP-ENVY-dv6-Notebook-PC:09480] Signal: Segmentation fault (11)
    [HP-ENVY-dv6-Notebook-PC:09480] Signal code: Address not mapped (1) 
    [HP-ENVY-dv6-Notebook-PC:09480] Failing at address: 0xf0b397
    [HP-ENVY-dv6-Notebook-PC:09480] [ 0] /lib/x86_64-linux-gnu/libpthread.so.0(+0xfcb0) [0x7fc0ec688cb0]
    [HP-ENVY-dv6-Notebook-PC:09480] [ 1] /usr/lib/libmpi.so.0(PMPI_Send+0x74) [0x7fc0ec8f3704]
    [HP-ENVY-dv6-Notebook-PC:09480] [ 2] example.exe(main+0x23f) [0x400e63]
    [HP-ENVY-dv6-Notebook-PC:09480] [ 3] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7fc0ec2da76d]
    [HP-ENVY-dv6-Notebook-PC:09480] [ 4] example.exe() [0x400b69]
    [HP-ENVY-dv6-Notebook-PC:09480] *** End of error message *** 
    --------------------------------------------------------------------------
    mpirun noticed that process rank 5 with PID 9480 on node andres-HP-ENVY-dv6-Notebook-PC exited on signal 11 (Segmentation fault).
    --------------------------------------------------------------------------

明らかに、私が見る出力では、 のどれも実行さprintf()ccg_mpi_error_handler()ていないので、ハンドラーがまったく呼び出されなかったと思います。役に立つかどうかはわかりませんが、ubuntu linux 12.04 を実行していて、apt-get を使用して MPI をインストールしました。プログラムのコンパイルに使用したコマンドは次のとおりです。

mpicc err_example.c -o example.exe

また、私が行うmpicc -vと、次のようになります。

  Using built-in specs.
  COLLECT_GCC=/usr/bin/gcc
  COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6/lto-wrapper
  Target: x86_64-linux-gnu
  Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
  Thread model: posix
  gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)

助けていただければ幸いです。ありがとう...

4

2 に答える 2

5

MPI 標準では、MPI 実装が適切にエラーを処理できることさえ要求していません。MPI-3.0 の §8.3 からの次の抜粋がすべてを物語っています。

MPI 実装は、MPI 呼び出し中に発生するいくつかのエラーを処理できないか、または処理しないことを選択する場合があります。これらには、浮動小数点エラーやアクセス違反など、例外やトラップを生成するエラーが含まれる場合があります。MPI によって処理される一連のエラーは、実装に依存します。このようなエラーごとに、MPI 例外が生成されます。

上記のテキストは、このドキュメント内のエラー処理に関するテキストよりも優先されます。具体的には、エラーが処理されることを示すテキストは、処理される可能性があるものとして読み取られる必要があります。

(太字やイタリック体の使用を含め、元の書式が保持されます)

これには多くの理由がありますが、そのほとんどは、パフォーマンスと信頼性の間のある種のトレードオフに関係しています。さまざまなレベルでエラー チェックを行い、エラー状態を適切に処理すると、それほど多くないオーバーヘッドが発生し、ライブラリ コード ベースが非常に複雑になります。

とはいえ、すべての MPI ライブラリが同じように作成されているわけではありません。それらのいくつかは、他のものよりも優れた耐障害性を実装しています。たとえば、Intel MPI 4.1 での同じコード:

...
Process 5 about to go south
Process 5 sending 5 to 0
ccg_mpi_error_handler: entry
ccg_mpi_error_handler: error_code = 403287557
ccg_mpi_error_handler: error_string = Invalid communicator, error stack:
MPI_Send(186): MPI_Send(buf=0x7fffa32a7308, count=1, MPI_INT, dest=0, tag=201, comm=0x0) failed
MPI_Send(87).: Invalid communicator
ccg_mpi_error_handler: exit

この場合のエラー メッセージの形式は、Open MPI を使用していることを示しています。Open MPI のフォールト トレランスは実験的なものであり (OMPI 開発者の 1 人である Jeff Squyres が時々 Stack Overflow を訪れています - 彼はより明確な答えを提供することができます)、ライブラリのビルド時にオプションを使用して明示的に有効にする必要があります。のように--enable-ft=LAM

デフォルトでは、MPICH もこのような状況を処理できません。

Process 5 about to go south
Process 5 sending 5 to 0

===================================================================================
=   BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
=   EXIT CODE: 139
=   CLEANING UP REMAINING PROCESSES
=   YOU CAN IGNORE THE BELOW CLEANUP MESSAGES
===================================================================================
YOUR APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault (signal 11)
This typically refers to a problem with your application.
Please see the FAQ page for debugging suggestions

現在、MPI は、エラーが検出されたときにプログラムの状態が一貫していることを保証していないことに注意してください。

エラーが検出された後の MPI の状態は未定義です。つまり、ユーザー定義のエラー ハンドラー (MPI_ERRORS_RETURN) を使用しても、エラーが検出された後もユーザーが MPI を引き続き使用できるとは限りません。これらのエラー ハンドラーの目的は、プログラムが終了する前に、ユーザーがユーザー定義のエラー メッセージを発行し、MPI とは関係のないアクション (I/O バッファーのフラッシュなど) を実行できるようにすることです。MPI 実装では、エラー後に MPI を自由に続行できますが、必須ではありません。

その理由の 1 つは、そのような「壊れた」コミュニケーターで集合操作を実行することが不可能になり、多くの内部 MPI メカニズムがすべてのランク間で集合情報を共有する必要があることです。ランスルー安定化(RTS)と呼ばれるはるかに優れたフォールト トレランス メカニズムが MPI-3.0 に含まれるよう提案されましたが、最終投票を通過しませんでした。RTS を使用すると、新しい MPI 呼び出しが追加されます。これにより、失敗したすべてのプロセスをまとめて削除することで、壊れたコミュニケーターから正常なコミュニケーターが作成され、残りのプロセスは新しいコミュニケーター内で動作し続けることができます。

免責事項: 私は Intel の社員ではなく、Intel の製品を支持するものではありません。IMPI が、Open MPI および MPICH のデフォルトのビルド構成よりも優れた、すぐに使用できるユーザー エラー処理の実装を提供する場合です。ビルドオプションを変更することで、両方のオープンソース実装で同等レベルのフォールトトレランスを実現できる可能性があります。または、将来的に適切な FT が登場する可能性があります (たとえば、Open MPI には RTS のプロトタイプ実装があります)。

于 2013-11-19T09:30:31.057 に答える