首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MPI2 / MPI3:考虑同步的MPI_allgather与MPI单向通信

MPI2 / MPI3:考虑同步的MPI_allgather与MPI单向通信
EN

Stack Overflow用户
提问于 2014-07-11 14:31:29
回答 1查看 722关注 0票数 1

我正在使用MPI-2编写一个优化程序,在该程序中,我需要在所有进程之间共享一个长度相同的std::vector (概念上)。该向量保存了当前发现的问题的最佳k解决方案,并且每次由多个MPI进程中的一个找到新的最佳解决方案时都会更新。每个过程在寻找新的解决方案上所花费的时间通常变化很大。

我的问题是,考虑到同步和等待中的性能问题,每次找到新的最佳解决方案时,我是否应该使用MPI集合(如MPI_allgather );还是应该使用MPI-2中的单边通信来在所有进程中维护“共享”向量。

特别是,如果我使用MPI_allgather,进程是否会提前空闲完成作业,并等待与其他进程的某种同步?

我在MPI点对点通信(upd:以及UPC)方面有一些工作经验,但在实际编码中没有使用集体或单边通信。我搜索了一下,找到了有关MPI_allgathers的相关问题/答案,例如Allgather,以及关于单向通信Creating a counter that stays synchronized across MPI processes的问题/答案。但我很难分辨出这两种方法的确切区别。

谢谢,

-最新消息

特别是,我在底层有来自Creating a counter that stays synchronized across MPI processes的代码示例,它使用单向维护单个int“共享”。我试图将它调整为泛型类型,但不知道如何使它工作,因为我很难理解原始代码,也不知道它为什么维护数组data,以及如何将MPI_Accumulate概括为用户函数(就像简单地用新的向量替换旧向量)。

模板//注意:t只能是基本类型(不是指针、引用或结构),例如int和double。结构mpi_array { typedef::向量向量;MPI_Win win;

代码语言:javascript
复制
   int  rank;
代码语言:javascript
复制
   int  size;
代码语言:javascript
复制
   Vector val;
代码语言:javascript
复制
   Vector \*hostvals;  };

单边通信计数器代码:

代码语言:javascript
复制
#include <mpi.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

struct mpi_counter_t {
    MPI_Win win;
    int  hostrank ;
    int  myval;
    int *data;
    int rank, size;
};

struct mpi_counter_t *create_counter(int hostrank) {
    struct mpi_counter_t *count;

    count = (struct mpi_counter_t *)malloc(sizeof(struct mpi_counter_t));
    count->hostrank = hostrank;
    MPI_Comm_rank(MPI_COMM_WORLD, &(count->rank));
    MPI_Comm_size(MPI_COMM_WORLD, &(count->size));

    if (count->rank == hostrank) {
        MPI_Alloc_mem(count->size * sizeof(int), MPI_INFO_NULL, &(count->data));
        for (int i=0; i<count->size; i++) count->data[i] = 0;
        MPI_Win_create(count->data, count->size * sizeof(int), sizeof(int),
                       MPI_INFO_NULL, MPI_COMM_WORLD, &(count->win));
    } else {
        count->data = NULL;
        MPI_Win_create(count->data, 0, 1,
                       MPI_INFO_NULL, MPI_COMM_WORLD, &(count->win));
    }
    count -> myval = 0;

    return count;
}

int increment_counter(struct mpi_counter_t *count, int increment) {
    int *vals = (int *)malloc( count->size * sizeof(int) );
    int val;

    MPI_Win_lock(MPI_LOCK_EXCLUSIVE, count->hostrank, 0, count->win);

    for (int i=0; i<count->size; i++) {

        if (i == count->rank) {
            MPI_Accumulate(&increment, 1, MPI_INT, 0, i, 1, MPI_INT, MPI_SUM,
                           count->win);
        } else {
            MPI_Get(&vals[i], 1, MPI_INT, 0, i, 1, MPI_INT, count->win);
        }
    }

    MPI_Win_unlock(0, count->win);
    count->myval += increment;

    vals[count->rank] = count->myval;
    val = 0;
    for (int i=0; i<count->size; i++)
        val += vals[i];

    free(vals);
    return val;
}

void delete_counter(struct mpi_counter_t **count) {
    if ((*count)->rank == (*count)->hostrank) {
        MPI_Free_mem((*count)->data);
    }
    MPI_Win_free(&((*count)->win));
    free((*count));
    *count = NULL;

    return;
}

void print_counter(struct mpi_counter_t *count) {
    if (count->rank == count->hostrank) {
        for (int i=0; i<count->size; i++) {
            printf("%2d ", count->data[i]);
        }
        puts("");
    }
}

int test1() {
    struct mpi_counter_t *c;
    int rank;
    int result;

    c = create_counter(0);

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    result = increment_counter(c, 1);
    printf("%d got counter %d\n", rank, result);

    MPI_Barrier(MPI_COMM_WORLD);
    print_counter(c);
    delete_counter(&c);
}


int test2() {
    const int WORKITEMS=50;

    struct mpi_counter_t *c;
    int rank;
    int result = 0;

    c = create_counter(0);

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    srandom(rank);

    while (result < WORKITEMS) {
        result = increment_counter(c, 1);
        if (result <= WORKITEMS) {
             printf("%d working on item %d...\n", rank, result);
             sleep(random() % 10);
         } else {
             printf("%d done\n", rank);
         }
    }

    MPI_Barrier(MPI_COMM_WORLD);
    print_counter(c);
    delete_counter(&c);
}

int main(int argc, char **argv) {

    MPI_Init(&argc, &argv);

    test1();
    test2();

    MPI_Finalize();
}
EN

回答 1

Stack Overflow用户

发布于 2014-07-11 17:41:10

您担心某些进程可能在其他进程之前进入MPI_ALLGATHER是有效的,但在任何具有同步的应用程序中都是如此,而不仅仅是那些显式使用集体通信的应用程序。

然而,你可能会对单边操作有误解。它们没有为您提供并行全局地址空间(PGAS)模型,其中所有内容都是同步的。相反,它们只是给您提供了一种直接解决远程进程内存的方法。每个进程的内存仍然是分开的。另外,如果你要从一个点升级到其他的MPI,我不会仅仅局限于MPI-2函数。在MPI-3中有一些新的东西,它也改善了集体和单方面(特别是后者)。

尽管如此,如果你从来没有使用过任何东西,除了点对点,单边对你来说将是一个很大的飞跃。您可能需要进行更多的中间步骤,并首先检查集体。如果你仍然对你的性能不满意,你可以看一看单面章节,但是它非常复杂,大多数人通常会使用一些位于单面之上的东西,而不是直接使用它(比如一些PGAS语言)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24700168

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档