通过MPI_Recv接收char数组会导致输出图像部分变黑

时间:2019-01-05 16:37:22

标签: c++ mpi

我正在计算一张图片,并且正在使用OpenMPI将循环分布到几个内核上。 每个核心都正确计算了循环的一部分,但是合并了 核心0上的两个数组都导致部分图片为黑色。 enter image description here enter image description here

我不知道发送/接收char数组是否破坏了数据或 如果我的合并不正确。 (我的虚拟机有2个内核)。

#include <iostream>
#include <cstdlib>
#include <cmath>
#include <xmmintrin.h>

#include "complex.h"

#include "lodepng.h"

using namespace std;

#include <sys/time.h>
#include <mpi.h>


int julia(int width, int height, int x, int y, const complex &c, const int max_iter) {
    /*
     * calculates the number of iterations (between 0 and 255) for a pixel (x,y)
     */
    complex z(1.5f * (x - width / 2) / (0.5f * width), (y - height / 2) / (0.5f * height));

    int n = 0;
    for (int i = 0; ((z.abs() < 2.0f) && (i < max_iter)); i++) {
        float tmp = z.re() * z.re() - z.im() * z.im() + c.re();
        z.set_im(2.0f * z.re() * z.im() + c.im());
        z.set_re(tmp);
        n++;
    }
    return max_iter - n;
}


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

    int rank, num_procs;
    //Initialize the infrastructure necessary for coomunication
    MPI_Init(&argc, &argv);
    //Identify this process 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    //Find out how many processes are active
    MPI_Comm_size(MPI_COMM_WORLD, &num_procs);

    const complex c(-0.7, 0.27015); // pretty
    // const complex c( -0.8, 0.156); // alternative complex number

    const int width = 2 * 1024, height = 2 * 1024; // image size

    int max_iter = 256;

    // Allocate aligned image buffer
    unsigned char *image = NULL;
    int err = posix_memalign((void **) &image, 64, width * height * 4 * sizeof(unsigned char));
    if (err){
        cout << "[Error] Couldn't allocate memory for regular Image." << endl;
    }



    int count = height / num_procs;
    int remainder = height % num_procs;
    int start, stop;
    if (rank < remainder) {
        // The first 'remainder' ranks get 'count + 1' tasks each
        start = rank * (count + 1);
        stop = start + count;
    } else {
        // The remaining 'size - remainder' ranks get 'count' task each
        start = rank * count + remainder;
        stop = start + (count - 1);
    }
    /*
     * Creates a pictures of a julia set
     */
    cout << "--------------------- " << endl;
    cout << "my rank " << rank << endl;
    cout << "number of procs " << num_procs << endl;
    cout << "start " << start << endl;
    cout << "end  " << stop << endl;
    cout << "--------------------- "<< endl;
    // iterate over image pixels and calculate their value
    for (int y = start; y <= stop; y++) {
        for (int x = 0; x < width; x++) {

            int a = julia(width, height, x, y, c, max_iter);

            image[4 * width * y + 4 * (x + 0) + 0] = a; // R
            image[4 * width * y + 4 * (x + 0) + 1] = a; // G
            image[4 * width * y + 4 * (x + 0) + 2] = a; // B
            image[4 * width * y + 4 * (x + 0) + 3] = 255;  // Alpha
        }
    }

    if(rank != 0)
    {
        //send image to rank 0
        MPI_Send(image, sizeof(image), MPI_UNSIGNED_CHAR, 0, 0, MPI_COMM_WORLD);
    }

    if(rank == 0 && (num_procs > 0))
    {
        // Allocate aligned image buffer
        unsigned char *lImage = (unsigned char *) malloc(width * height * 4 * sizeof(unsigned char));       
        /*
        unsigned char *lImage = NULL;
        int err = posix_memalign((void **) &lImage, 64, width * height * 4 * sizeof(unsigned char));
        if (err){
            cout << "[Error] Couldn't allocate memory for regular Image." << endl;
        }
        */              

        for(int i = 1; i < num_procs; i++)
        {
                //lImage receives the image array from process i
                MPI_Recv(lImage, sizeof(lImage), MPI_UNSIGNED_CHAR, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

                //calculate start and stop for the following for loop
                int lCount = height / num_procs;
                int lRemainder = height % num_procs;
                int lStart, lStop;
                if (i < lRemainder) {
                    // The first 'remainder' ranks get 'count + 1' tasks each
                    lStart = i * (lCount + 1);
                    lStop = lStart + lCount;
                } else {
                    // The remaining 'size - remainder' ranks get 'count' task each
                    lStart = i * lCount + lRemainder;
                    lStop = lStart + (lCount - 1);
                }

                cout << "--------inside loop----------- " << endl;
                cout << "my rank " << i << endl;
                cout << "start " << lStart << endl;
                cout << "end  " << lStop << endl;
                cout << "--------------------- "<< endl;

                for (int y = lStart; y <= lStop; y++) {
                    for (int x = 0; x < width; x++) {

                        image[4 * width * y + 4 * (x + 0) + 0] = lImage[4 * width * y + 4 * (x + 0) + 0]; // R
                        image[4 * width * y + 4 * (x + 0) + 1] = lImage[4 * width * y + 4 * (x + 0) + 1]; // G
                        image[4 * width * y + 4 * (x + 0) + 2] = lImage[4 * width * y + 4 * (x + 0) + 2]; // B
                        image[4 * width * y + 4 * (x + 0) + 3] = 255;  // Alpha
                    }
                }
            //receive image of the rank i
            //merge received image array and rank 0 image array
        }
        free(lImage);
    }

    if(rank == 0)
    {   
        /*Encode the image*/
        unsigned error = lodepng_encode32_file("julia_openmp0.png", image, width, height);
        if (error) {
            std::cout << "[Error] " << error << " : " << lodepng_error_text(error) << std::endl;
        }
    }
    if(rank == 1)
    {   
        /*Encode the image*/
        unsigned error = lodepng_encode32_file("julia_openmp1.png", image, width, height);
        if (error) {
            std::cout << "[Error] " << error << " : " << lodepng_error_text(error) << std::endl;
        }
    }


    /*cleanup*/
    free(image);

        /* Tear down the communication infrastructure */
    MPI_Finalize();
    return 0;

1 个答案:

答案 0 :(得分:0)

对不起,我没有机会进行适当的检查,但我认为这可以归结为这一行:

MPI_Recv(lImage, sizeof(lImage), MPI_UNSIGNED_CHAR, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

您正在尝试以特定顺序接收消息(过程1,过程2),而您实际上并不知道首先准备好哪个消息。并且MPI_Recv的接收操作被阻止。您可以尝试以不依赖于计算顺序的方式来重写逻辑吗?一种方法是使用MPI_Gather()。另一种选择是在您发送的消息中包含进程号,然后使用MPI_ANY_SOURCE接收下一条传入消息,并在循环中使用进程号正确处理该阻止。