I'm just starting out with MPI programming and decided to make a simple distributed qsort using OpenMPI. To distribute parts of the array I want to sort I'm trying to use MPI_Scatterv, however the following code segfaults on me:

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

#define ARRAY_SIZE 26
#define BUFFER_SIZE 2048

int main(int argc, char** argv) {
    int my_rank, nr_procs;

    int* data_in, *data_out;
    int* sizes;
    int* offsets;

    srand(time(0));

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &nr_procs);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    // everybody generates the control tables
    int nr_workers = nr_procs-1;
    sizes = malloc(sizeof(int)*nr_workers);
    offsets = malloc(sizeof(int)*nr_workers);

    int nr_elems = ARRAY_SIZE/nr_workers;

    // basic distribution
    for (int i = 0; i < nr_workers; ++i) {
        sizes[i] = nr_elems;
    }
    // distribute the remainder
    int left = ARRAY_SIZE%nr_workers;
    int curr_worker = 0;
    while (left) {
        ++sizes[curr_worker];
        curr_worker = (++curr_worker)%nr_workers;
        --left;
    }   
    // offsets
    int curr_offset = 0;
    for (int i = 0; i < nr_workers; ++i) {
        offsets[i] = curr_offset;
        curr_offset += sizes[i];
    }


    if (my_rank == 0) {
        // root
        data_in = malloc(sizeof(int)*ARRAY_SIZE);
        data_out = malloc(sizeof(int)*ARRAY_SIZE);
        for (int i = 0; i < ARRAY_SIZE; ++i) {
            data_in[i] = rand();
        }

        for (int i = 0; i < nr_workers; ++i) {
            printf("%d at %d\n", sizes[i], offsets[i]);
        }

        MPI_Scatterv (data_in, sizes, offsets, MPI_INT, data_out, ARRAY_SIZE, MPI_INT, 0, MPI_COMM_WORLD);


    } else {
        // worker
        printf("%d has %d elements!\n",my_rank, sizes[my_rank-1]);
        // alloc the input buffer
        data_in = malloc(sizeof(int)*sizes[my_rank-1]);

        MPI_Scatterv(NULL, NULL, NULL, MPI_INT, data_in, sizes[my_rank-1], MPI_INT, 0, MPI_COMM_WORLD);

        printf("%d got:\n", my_rank);
        for (int i = 0; i < sizes[my_rank-1]; ++i) {
            printf("%d ", data_in[i]);
        }
        printf("\n");
    }

    MPI_Finalize();
    return 0;
}

How would I go about using Scatterv? Am I doing something wrong with allocating my input buffer from inside the worker code?

有帮助吗?

解决方案

I changed some part in your code to get something working.

MPI_Scatter() will send data to every processors, including himself. According to your program, processor 0 expects ARRAY_SIZE integers, but sizes[0] is much smaller. There are other problems on other processus : MPI_Scatter will send sizes[my_rank] integers, but sizes[my_rank-1] will be expected...

Here is a code that scatters data_in from 0 to all processors, including 0. Therefore i added 1 to nr_workers :

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

#define ARRAY_SIZE 26
#define BUFFER_SIZE 2048

int main(int argc, char** argv) {
    int my_rank, nr_procs;

    int* data_in, *data_out;
    int* sizes;
    int* offsets;

    srand(time(0));

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &nr_procs);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    // everybody generates the control tables
    int nr_workers = nr_procs;
    sizes = malloc(sizeof(int)*nr_workers);
    offsets = malloc(sizeof(int)*nr_workers);

    int nr_elems = ARRAY_SIZE/nr_workers;

    // basic distribution
    for (int i = 0; i < nr_workers; ++i) {
        sizes[i] = nr_elems;
    }
    // distribute the remainder
    int left = ARRAY_SIZE%nr_workers;
    int curr_worker = 0;
    while (left) {
        ++sizes[curr_worker];
        curr_worker = (++curr_worker)%nr_workers;
        --left;
    }   
    // offsets
    int curr_offset = 0;
    for (int i = 0; i < nr_workers; ++i) {
        offsets[i] = curr_offset;
        curr_offset += sizes[i];
    }

    if (my_rank == 0) {
        // root
        data_in = malloc(sizeof(int)*ARRAY_SIZE);

        for (int i = 0; i < ARRAY_SIZE; ++i) {
            data_in[i] = rand();
            printf("%d %d \n",i,data_in[i]);
        }

        for (int i = 0; i < nr_workers; ++i) {
            printf("%d at %d\n", sizes[i], offsets[i]);
        }


    } else {
        printf("%d has %d elements!\n",my_rank, sizes[my_rank]);
    }
    data_out = malloc(sizeof(int)*sizes[my_rank]);

    MPI_Scatterv (data_in, sizes, offsets, MPI_INT, data_out, sizes[my_rank], MPI_INT, 0, MPI_COMM_WORLD);

    printf("%d got:\n", my_rank);
    for (int i = 0; i < sizes[my_rank]; ++i) {
        printf("%d ", data_out[i]);
    }
    printf("\n");
    free(data_out);
    if(my_rank==0){
        free(data_in);
    }
    MPI_Finalize();
    return 0;
}

Regarding memory managment, data_in and data_out should be freed at the end of the code.

Is it what you wanted to do ? Good luck with qsort ! I think you are not the first one to sort integers using MPI. See parallel sort using mpi. Your way to generate random numbers on the 0 processus and then scatter them is the right way to go. I think you will be interrested by his TD_Trier() function for communication. Even if you change tri_fusion(T, 0, size - 1); for qsort(...)...

Bye,

Francis

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top