如何正确设置 MPI_scatterv 中的“发送计数”和“位移”参数?

Posted

技术标签:

【中文标题】如何正确设置 MPI_scatterv 中的“发送计数”和“位移”参数?【英文标题】:How do I correctly set the "send counts" and "displacement" arguments in MPI_scatterv? 【发布时间】:2019-08-24 09:34:19 【问题描述】:

我正在尝试使用 MPI_Scatterv 在“n”个进程之间拆分二维数组的行。阻止我的两个论点是“send_counts”和“displacements”。我知道这些数组的作用的教科书定义,但我需要一种方法来动态创建这些数组以接受任何长度的二维数组,尤其是不能被进程数整除的二维数组行。

这种方法的灵感来源于这里(构建send_counts和displacement数组): https://gist.github.com/ehamberg/1263868 我理解这种方法,但我想知道这种实现是否仅适用于二维数组(矩阵)。

问题: 问题是否与二维数组不连续有关?

有关数据类型的内存块的位移是否正确(即我的位移应该是 4,因为浮点数是 4 个字节的内存?)

#include <iostream>
#include <fstream>
#include <sstream>
#include "mpi.h"
#include <stdio.h>


#define ROW 75 
#define COL 5

void importData(std::string str, float (*dest)[75][5], int length) 

std::ifstream infile(str);

int i = 0;
int j = 0;

std::string a;

while (getline(infile, a)) 

    std::stringstream ss(a);
    std::string token;
    i = 0;


    while (getline(ss, token, ',')) 

        if (i < length) 

            (*dest)[i][j] = strtof(token.c_str(), NULL);
        

        else 

            i++;
        

        j++;

    


 





int main(int argc, char **argv)


float iris[75][5] =   ;

importData("Iris.test", &iris, 5);


int rank, comm_sz;

int sum = 0;

int rem = (ROW*COL) % comm_sz;

int * send_counts;
int * displs;


MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);


int row[1000];




send_counts = (int *)malloc(sizeof(float)*comm_sz);
displs = (int *)malloc(sizeof(float)*comm_sz);


// calculate send counts and displacements
for (int i = 0; i < comm_sz; i++) 
    send_counts[i] = (ROW*ROW) / comm_sz;
    if (rem > 0) 
        send_counts[i]++;
        rem--;
    

    displs[i] = sum;
    sum += send_counts[i];




if (rank == 0)





// Scatter the big table to everybody's little table, scattering the rows
MPI_Scatterv(iris, send_counts, displs, MPI_FLOAT, row, 100, MPI_FLOAT, 0, 
MPI_COMM_WORLD);
//                              displacements      recv buffer, recv count
std::cout << "%d: " << rank << std::endl;

for (int i = 0; i < send_counts[rank]; i++) 
    std::cout << "%f\t" << row[i] << std::endl;


MPI_Finalize();




我希望“n”个进程中的每一个都打印出传递数组的一部分行。

这是我得到的错误:

MPI_Scatterv 发生错误 按进程报告 [2187067393,0] 在通讯器 MPI_COMM_WORLD MPI_ERR_TRUNCATE:消息被截断 MPI_ERRORS_ARE_FATAL(此通信器中的进程现在将中止, 并且可能是您的 MPI 工作)

**注意:数据文件共75行,每行5个浮点数,逗号分隔

【问题讨论】:

通过 MPI 发送的 2D 数组应实现为 1D 数组。这也不是minimal reproducible example,请把它归结为实际问题(即使是0值,写这样的东西也很容易)。 【参考方案1】:

问题是您发送的内容(例如sendcountssendtype)与您收到的内容(例如recvcountrecvtype)之间的签名不匹配。

在您的情况下,由于您收到(硬编码)100 MPI_FLOAT 并且您发送MPI_FLOAT,因此只有在所有send_counts[i] == 100 时它才能工作。

我想正确的解决方法是更改​​recvcount 的值。在等级i 上,它应该与根等级上的send_counts[i] 具有相同的值(例如,在您的情况下为等级0

【讨论】:

我可以用以下语句替换硬编码的 100:send_counts[0]。会这样吗? 这仅适用于等级0send_counts[rank] 应该可以解决问题。 这导致了分段错误(地址未映射到对象)。我检查了 send_counts 的内容,里面有可笑的数字(5626、10972 等)。看来 send_counts 的这个算法对我不起作用 如果你发minimal reproducible example,我去看看 我发现一个问题部分解决了我的问题***.com/questions/9269399/… 我想我的答案就在那里。如果我得到一些东西,我会发布

以上是关于如何正确设置 MPI_scatterv 中的“发送计数”和“位移”参数?的主要内容,如果未能解决你的问题,请参考以下文章

如何正确地从本地主机发送电子邮件 [关闭]

如何在 NestJS 中正确设置配置?

使用 Pear Mail 发送纯文本和 html 电子邮件(如何设置“Content-Type”并正确使用边界)

如何正确发送推送通知

Swift:如何将单元格发送到 TableView 中的正确部分?

如何正确使用 Angular 中的 Observable 将数组数据从父级发送到子级?