使用 MPI_Pack 和 Unpack 以及 MPI_send 和 Receive 时收到的垃圾值

Garbage value recieved while using MPI_Pack and Unpack along with MPI_send and Recieve

我正在尝试将矩阵的一部分从一个进程发送到另一个进程。这是给定的矩阵

它有 10 行和 8 列。我试图在 MPI_Pack() 的帮助下将一半的列(4 到 7)[注意--> 矩阵是 0 索引]从进程 0 发送到进程 1。为此,我使用以下代码

 double snd_buf[4][r];   //r is the number of rows
    double recv_buf[4][r];
    double buf[4][r];

   MPI_Request request[c];    //c is the number of columns
    MPI_Request request1[c];
    MPI_Status status[c];

//packing and sending the data
        if(myrank==0)
            {
                //we will send the half of the matrix to process 2
                for(int j=4;j<c;j++)
                {
                    position=0; //reassigning position after each and every send
                    
                    for(int i=0;i<r;i++)
                    {
                        MPI_Pack(&mat[i][j], 1 , MPI_DOUBLE,snd_buf[j-4],80,&position,MPI_COMM_WORLD);
                    }
                }
                
                
                //sending all the buffers
                for(int j=4;j<c;j++)
                {
                    MPI_Send (snd_buf[j-4], 10 , MPI_PACKED, 1 /*dest*/ , j /*tag*/ , MPI_COMM_WORLD);
                }
                
                
                
            } 

为了接收,我使用了以下代码。

if(myrank==1)
        {
        
             for(j=4;j<c;j++)
             {      
                 MPI_Recv(recv_buf[j-4], 10, MPI_PACKED, 0 /*src*/ , j /*tag*/, MPI_COMM_WORLD,&status[j]);
                 
             }
            
            for(int j=4; j<c;j++)
            {
                position=0;
                 for(int i=0;i<r;i++)
                 {
                    MPI_Unpack(recv_buf[j-4],80,&position,&buf[j-4][i], 1/*outcount*/, MPI_DOUBLE, MPI_COMM_WORLD);
                 }
            }
}

但是当我打印 recv_buf 的值时,在某些情况下我只得到每行的第一个元素,后跟 0,在某些情况下还有一些垃圾值。下面给出的是 recv_buf.

的内容

示例 1:

示例 2:

我也检查了我的 snd_buf[],但它很好地包装了所有值。

我没有得到我要去的地方,在 recv_buf 中得到这些 0,有时甚至是垃圾值。请帮忙。

第一个

double snd_buf[4][r];   //r is the number of rows
double recv_buf[4][r];
double buf[4][r];

我想你的意思是:

double snd_buf[r][4];   //r is the number of rows
double recv_buf[r][4];
double buf[r][4];

来自source 可以阅读:

MPI_Pack - Packs data of a given datatype into contiguous memory.

您滥用了 packing/unpacking 功能。您无需打包要发送的每个元素,只需将行与要发送的列打包即可。由于行在内存中是连续分配的,因此您可以一次性打包它们,无需单独打包每一列。此外,您正在对 send:

执行多次调用
   for(int j=0;j<c;j++){
      MPI_Send (snd_buf[j-4], 10 , MPI_PACKED, 1 /*dest*/ , j /*tag*/ , MPI_COMM_WORLD);
  }

打包的要点是将所有内容打包到一个缓冲区中,然后 send/recv 一次完成。如果你要执行多个 MPI_Send 那么打包没有太大好处,你最好直接 sending/receiving 列而不需要打包任何东西,如下:

if(myrank==0){
   for(int i=0;i<r;i++) // Send 4 columns of each row
       MPI_Send (&mat[i], 4, MPI_DOUBLE, 1, i, MPI_COMM_WORLD);
       
 }
 ...
 if(myrank==1){
    for(int i=0;i<r;i++){ // receive 4 columns of each row
      MPI_Recv(&mat[i], 4, MPI_DOUBLE, 0, i ...);
  }

除其他外,这些是您需要在逻辑中修正才能使其正常工作的基本错误。


话虽这么说,但通过发送一半的行而不是一半的列来解决这个问题更容易也更有效。

您可以先分配一个 continuously 2D array(或简单地将矩阵表示为一个数组),并且一次调用仅分配 send/recv 一半的行。

这是一个说明该方法的玩具示例(它仅适用于两个进程,并且不能用于生产):

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"

#define ROWS 10
#define COLS 8

int main( int argc, char *argv[])
{
     MPI_Status status;
     MPI_Init(&argc, &argv);    
     int myrank, size; //size will take care of number of processes 
     MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
     MPI_Comm_size(MPI_COMM_WORLD, &size);
         
     if(myrank == 0){
        int (*arr)[COLS] = malloc(sizeof *arr * ROWS);
        // Just faking some data
        for(int i = 0; i < ROWS; i++)
           for(int j = 0; j < COLS; j++)
              arr[i][j] = i;
            
        MPI_Send(&arr[ROWS/2], ROWS/2 * COLS, MPI_INT, 1, 0, MPI_COMM_WORLD);
    }else{    
        int (*arr)[COLS] = malloc(sizeof *arr * ROWS/2);
        MPI_Recv(arr, ROWS/2 * COLS, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
        for(int i = 0; i < ROWS/2; i++){
           for(int j = 0; j < COLS; j++)
               printf("%d ",arr[i][j]);
           printf("\n");
        }
    }
   MPI_Finalize();
   return 0;
}

输入:

0 0 0 0 0 0 0 0 
1 1 1 1 1 1 1 1 
2 2 2 2 2 2 2 2 
3 3 3 3 3 3 3 3 
4 4 4 4 4 4 4 4 
5 5 5 5 5 5 5 5 
6 6 6 6 6 6 6 6 
7 7 7 7 7 7 7 7 
8 8 8 8 8 8 8 8 
9 9 9 9 9 9 9 9 

输出:

5 5 5 5 5 5 5 5 
6 6 6 6 6 6 6 6 
7 7 7 7 7 7 7 7 
8 8 8 8 8 8 8 8 
9 9 9 9 9 9 9 9 

要针对多个进程扩展此方法,您应该替换 点对点 通信例程( MPI_SendMPI_Recv) 通过集体通信例程 MPI_Scatterv:

Scatters a buffer in parts to all processes in a communicator

MPI_GatherV

Gathers into specified locations from all processes in a group