4.11 搜索(Scan) BACKWARDFORWARD


MPI_SCAN(sendbuf, recvbuf, count, datatype, op, comm)
 IN   sendbuf    发送消息缓冲区的起始地址(可变)
 OUT  recvbuf    接收消息缓冲区的起始地址(可变)
 IN   count      输入缓冲区中元素的个数(整型)
 IN   datatype   输入缓冲区中元素的类型(句柄)
 IN   op         操作(句柄)
 IN   comm       通信子(句柄)

int MPI_Scan(void* sendbuf, void* recvbuf, int count,
             MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
MPI_SCAN(SENDBUF, RECVBUF, COUNT, DATATYPE, OP, COMM, IERROR)
    <type> SENDBUF(*), RECVBUF(*)
    INTEGER COUNT, DATATYPE, OP, COMM, IERROR

MPI_SCAN常用于对分布于组中的数据作前置归约操作.此操作将序列号为0,... ,i(包括i)的进程发送缓冲区的值的归约结果存入序列号为i 的进程的接收消息缓冲区中,这种操作支持的类型、语义以及对发送及接收缓冲区的限制和MPI_REDUCE相同.

4.11.1 使用MPI_SCAN的例子

例4.22: 本例用一个用户自定义的操作进行段扫描,一个段扫描将一组值和一组逻辑量作为输入,其中逻辑值将输入分割成不同的段.例如对于以下数据:

操作符产生的结果是:

这里

注意这是一个非交换操作.它的C代码如下:

    typedef struct {
        double val;
        int log;
    } SegScanPair;
    /* 用户自定义的函数 */
    void segScan(SegScanPair *in, SegScanPair *inout, int *len,
                 MPI_Datatype *dptr)
    {
        int i;
        SegScanPair c;

        for (i=0; i<*len; ++i) {
            if (in->log == inout->log)
               c.val = in->val + inout->val;
            else
               c.val = inout->val;
            c.log = inout->log;
            *inout = c;
            in++; inout++;
        }
    }


注意用户自定义操作的参数inout与操作的右端操作数相对应,当使用这个操作符时,应注意将它描述成一个非交换的,如下所示:

    int i,base;
    SeqScanPair a, answer;
    MPI_Op myOp;
    MPI_Datatype type[2] = {MPI_DOUBLE, MPI_INT};
    MPI_Aint disp[2];
    int blocklen[2] = {1, 1};
    MPI_Datatype sspair;

    /* 告之MPI SegScanPair类型是如何定义的 */
    MPI_Address(a, disp);
    MPI_Address(a.log, disp+1);
    base = disp[0];
    for (i=0; i<2; ++i) disp[i] -= base;
    MPI_Type_struct(2, blocklen, disp, type, &sspair);
    MPI_Type_commit(&sspair);
    /* 生成段扫描的用户op */
    MPI_Op_create(segScan, False, &myOp);
    ......
    MPI_Scan(a, answer, 1, sspair, myOp, root, comm);


Copyright: NPACT BACKWARDFORWARD