【问题标题】:How to Scatter then Reduce using MPI and c++如何使用 MPI 和 C++ 分散然后减少
【发布时间】:2017-11-29 06:22:42
【问题描述】:

我正在尝试并行计算向量的 norm2(可变大小)。我的方法是首先将向量分散在处理器中,计算每个子向量的平方和总和,然后减少结果并应用平方根。

这是我的代码:

#include <mpi.h>
#include <vector>
#include <iostream>
#include <cmath>

double SquareSum(std::vector<double> & v) {

double res;

for (std::vector<double>::iterator it = v.begin(); it != v.end(); it++){
    if (*it){
        res += (*it)*(*it);
    }
    else{
        it++;
    }
}

return res;
}




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

std::vector<double> numbers;
double val;
while (std::cin >> val) numbers.push_back(val);



MPI_Init(&argc,&argv);

int rank, size;

MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);

unsigned numbers_count = numbers.size();

MPI_Bcast(&numbers_count, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD);

unsigned local_share = numbers_count / size; // local_share is the floor function of numbers.size() / number of process


if (numbers_count % size > 0){
    ++local_share;  // if size is not a multiple of numbers.size() add 1 to local_share in order to make it "fit"
}

if (rank == 0){ 
numbers.resize(local_share*size); //resize numbers by adding null empty spot if necessary
}

//std::cout << "I'm" << rank << std::endl;
std::vector<double> local(local_share);

MPI_Scatter(&numbers, local_share, MPI_DOUBLE, &local, local_share, MPI_DOUBLE, 0, MPI_COMM_WORLD);

double par_sum = SquareSum(local);

double sum = 0;


MPI_Reduce(&par_sum, &sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

if (rank == 0){

    std::cout << "norm : " << std::sqrt(sum);
}
MPI_Finalize();
return 0;
}

当我尝试执行程序时出现此错误:

“mpiexec 注意到节点笔记本电脑上 PID 9823 的进程等级 2 在信号 11 上退出(分段错误)。”

我想分散有问题,但我不知道是什么。

感谢您的帮助

【问题讨论】:

  • &amp;numbers&amp;local 是向量对象的控制结构的地址,而不是它们包含的数据。请改用&amp;numbers[0]&amp;local[0]
  • 我更改了代码,我有同样的错误。但我做了一些研究,可能是由于记忆力不足。 (类似于 addind 交换)

标签: c++ mpi


【解决方案1】:

除了@Hristo Iliev 的评论:

numbers 的大小可能不是大小的倍数。然后,local_share 变为 numbers_count % size+1。它用作每个进程由MPI_Scatter() 检索的部分的大小。因此,散点矢量的大小必须为(numbers_count % size+1)*size。由于提供的向量numbers 可能太小,程序会尝试访问越界的元素,这会触发未定义的行为,例如分段错误。

两种解决方案:

  • 推回零直到numbers.size()%size==0。它修改了向量,这对于未来的使用并不实用,而且相当丑陋。
  • 使用MPI_Scatterv()

【讨论】:

  • 所以我没有改变任何东西,但由于某种原因现在它可以工作了。我将尝试使用 MPI_Scatterv() 实现。我知道 size 不可能是 size 的倍数,但是两个无符号 a,b 变量的除法相当于 floor(a/b)。这并不明显,这是真的,我会将它作为注释添加到我的代码中。感谢您的帮助。
  • 不客气!之所以称为未定义行为,是因为问题可能未被注意到,或者程序的结果可能是错误的,或者问题可能会因分段错误等痛苦的死亡而死亡:问题可能会在以后再次出现。即使 a/b 是 floor(a/b),(a/b+1)*b 也可能大于 a! (11/10+1)*10=20。如果你使用正确的计数和位移的 MPI_Scatterv(),问题就会解决!
猜你喜欢
  • 2017-02-28
  • 2012-05-10
  • 2014-06-23
  • 2015-05-30
  • 1970-01-01
  • 2020-08-17
  • 2014-03-10
  • 1970-01-01
  • 2011-06-09
相关资源
最近更新 更多