Home > Net >  "Segmentation Fault" error when running MPI with more than one process - C
"Segmentation Fault" error when running MPI with more than one process - C

Time:05-25

I'm writing a Generator that generates words in parallel with MPI.

When I run the generator with a single process as below, it gives the desired outputs without any problems.

    mpirun -np 1 ./bin/gen_data 2

And the output is:

<<<==========GENERATION TEST START=========>>>
VT
BBZPTFTQ
WORD 0 : VT
WORD 1 : BBZPTFTQ
That took 0.000014 seconds
<<<===========GENERATION TEST END==========>>>

When I increase the number of processes, for example, when it is two, I get an error as follows:

<<<==========GENERATION TEST START=========>>>
MTBVLUWXB
DVP
WORD 0 : DVP
[fati:17967] *** Process received signal ***
[fati:17967] Signal: Segmentation fault (11)
[fati:17967] Signal code:  (128)
[fati:17967] Failing at address: (nil)
[fati:17967] [ 0] /lib/x86_64-linux-gnu/libc.so.6( 0x43090)[0x7f978851f090]
[fati:17967] [ 1] ./bin/gen_data( 0xdf81)[0x5582c661bf81]
[fati:17967] [ 2] ./bin/gen_data( 0xe039)[0x5582c661c039]
[fati:17967] [ 3] ./bin/gen_data( 0xe3b1)[0x5582c661c3b1]
[fati:17967] [ 4] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main 0xf3) 
[0x7f9788500083]
[fati:17967] [ 5] ./bin/gen_data( 0xd78e)[0x5582c661b78e]
[fati:17967] *** End of error message ***
--------------------------------------------------------------------------
Primary job  terminated normally, but 1 process returned
a non-zero exit code. Per user-direction, the job has been aborted.
--------------------------------------------------------------------------
--------------------------------------------------------------------------
mpirun noticed that process rank 0 with PID 0 on node fati exited on signal 11 
(Segmentation fault).
--------------------------------------------------------------------------

Here are my codes:

Generator.cpp

#include "Generator.hpp"

int Generator::MAX_STR_LEN = 10;
int Generator::MIN_STR_LEN = 2;
int Generator::DATASET_SIZE = 50000;
char *Generator::LETTERS = (char *)malloc(Generator::LETTER_COUNT * sizeof (char));
int Generator::WORLD_SIZE = 1;
int *Generator::SCATTER_SEND_BUFFER = nullptr;
char **Generator::ALL_WORDS = nullptr;
int Generator::ELEMENTS_PER_PROC = DATASET_SIZE;


void Generator::validate(int argc, char **argv){

    if (Generator::WORLD_SIZE > 100)
        throw invalid_argument("WORLD_SIZE can be 100 at max");

    if (Generator::WORLD_SIZE < 1)
        throw invalid_argument("WORLD_SIZE can't be lowest from 1");
        
    if (argc < 2)
        throw invalid_argument("CLI arguments must have 2 arguments at least");

    Generator::DATASET_SIZE = atoi(argv[1]);

    if (strlen(argv[1]) > 7 || Generator::DATASET_SIZE > 1000000)
        throw invalid_argument("MPI_DATASET_SIZE can be 1M at max");

    if (Generator::DATASET_SIZE <= 0)
        throw invalid_argument("MPI_DATASET_SIZE can't be zero or negative");
    

    Generator::MAX_STR_LEN = 10;
    if (argc > 2)
       Generator::MAX_STR_LEN = atoi(argv[2]);

    if (Generator::MAX_STR_LEN > 100)
        throw invalid_argument("MAX_STR_LEN can be 100 at max");

    if (Generator::MAX_STR_LEN < 2)
        throw invalid_argument("MAX_STR_LEN can't be lowest from 2");

    Generator::MIN_STR_LEN = 2;
    if (argc > 3)
       Generator::MIN_STR_LEN = atoi(argv[3]);

    if (Generator::MIN_STR_LEN > 99)
        throw invalid_argument("MIN_STR_LEN can be 99 at max");

    if (Generator::MIN_STR_LEN < 1)
        throw invalid_argument("MIN_STR_LEN can't be lowest from 1");

    if (Generator::MIN_STR_LEN >= Generator::MAX_STR_LEN)
        throw invalid_argument("MIN_STR_LEN has to be lowest from MAX_STR_LEN");

    Generator::ELEMENTS_PER_PROC = Generator::DATASET_SIZE / Generator::WORLD_SIZE;

}

void Generator::createLetters(){
    for (int i = 0; i < Generator::LETTER_COUNT; i  )
        Generator::LETTERS[i] = 'A'   i;
}


Generator::Generator(int argc, char **argv){
    Generator::validate(argc, argv);
    Generator::createLetters();
}

Generator::Generator(){}

void Generator::Allocate2DArray(char ***arr, int row, int col){
    *arr = (char **)malloc(row * sizeof(char*));
    for (int i = 0; i < row; i  )
        (*arr)[i] = (char *)malloc(col * sizeof(char));
}

void Generator::CreateSendData(){
    Generator::SCATTER_SEND_BUFFER = (int *)malloc(Generator::WORLD_SIZE * sizeof(int));
    for (int i = 0; i < Generator::WORLD_SIZE; i  )
        SCATTER_SEND_BUFFER[i] = Generator::ELEMENTS_PER_PROC;
}

void Generator::CreateWord(char **word){
    int len = rand() % (Generator::MAX_STR_LEN - Generator::MIN_STR_LEN   1)   Generator::MIN_STR_LEN;
    *word = (char *)malloc((Generator::MAX_STR_LEN) * sizeof(char));
    int i = 0;
    for (; i < len; i  )
    {
        int r = rand() % LETTER_COUNT;
        (*word)[i] = Generator::LETTERS[r];
    }
    if (len != MAX_STR_LEN)
        (*word)[i] = '\0';
}

void Generator::CreateWords(char **arr, int buff_size){
    for (int i = 0; i < buff_size; i  ){
        char *word;
        Generator::CreateWord(&word);
        arr[i] = word;
    }
}

void Generator::WorkingTime(double start_time, double end_time){
    printf("That took %f seconds\n", end_time - start_time);
}

void Generator::WriteWord(char *word){
    for (int i = 0; i < Generator::MAX_STR_LEN; i  )
    {
        if (word[i] == '\0')
            break;
        cout << word[i];
    }
    
    cout << endl;
}

void Generator::WriteWords(){
    for (int i = 0; i < Generator::DATASET_SIZE; i  ){
        cout << "WORD " << i << " : ";
        // assert(ALL_WORDS[i] != NULL);
        Generator::WriteWord(Generator::ALL_WORDS[i]);
    }
}

void Generator::WriteWords(char **arr, int buff_size){
    for (int i = 0; i < buff_size; i  )
        Generator::WriteWord(arr[i]);
}

TestGenerate.cpp

#include "Generator.hpp"
#include "Util.hpp"
#include <mpi.h>
#include <unistd.h>
int main(int argc, char **argv)
{

    Util::Clear();

    cout << "<<<==========GENERATION TEST START=========>>>" << endl;

    double start_time, end_time;

    MPI_Init(NULL, NULL);
    int world_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
    MPI_Comm_size(MPI_COMM_WORLD, &Generator::WORLD_SIZE);

    Generator *generator = new Generator(argc, argv);

    start_time = MPI_Wtime();

    Generator::SCATTER_SEND_BUFFER = NULL;
    Generator::CreateSendData();
    assert(Generator::SCATTER_SEND_BUFFER != NULL);

    int scatter_recv_buffer;
    MPI_Barrier(MPI_COMM_WORLD);

    MPI_Scatter(Generator::SCATTER_SEND_BUFFER, 1, MPI_INT, &scatter_recv_buffer, 1, MPI_INT, 0, MPI_COMM_WORLD);
    srand((world_rank   1) * time(0));

    char **words = NULL;
    Generator::Allocate2DArray(&words, scatter_recv_buffer, Generator::MAX_STR_LEN);
    Generator::CreateWords(words, scatter_recv_buffer);
    Generator::WriteWords(words, scatter_recv_buffer);

    if (world_rank == 0)
        Generator::Allocate2DArray(&Generator::ALL_WORDS, Generator::DATASET_SIZE, Generator::MAX_STR_LEN);

    MPI_Gather(words, scatter_recv_buffer * Generator::MAX_STR_LEN, MPI_CHAR, Generator::ALL_WORDS, scatter_recv_buffer * Generator::MAX_STR_LEN, MPI_CHAR, 0, MPI_COMM_WORLD);

    if (world_rank == 0)
    {
        end_time = MPI_Wtime();
        Generator::WriteWords();
        Generator::WorkingTime(start_time, end_time);
        cout << "<<<===========GENERATION TEST END==========>>>" << endl;
    }

    MPI_Finalize();
}

I'm probably having trouble gathering data with MPI_Gather. I need your help.

CodePudding user response:

Your basic problem is that Allocate2DArray does not create a 2D array: it creates a 1D array of 1D arrays. Thus you can not use it as an MPI buffer. MPI buffers can only be (using your specific case) char*.

CodePudding user response:

As @victor-eijkhout said MPI Buffers only take char* parameters.

And a 2d array is not needed to hold a string array at char pointers.

Here is the new Generator.cpp:

#include "Generator.hpp"

int Generator::MAX_STR_LEN = 10;
int Generator::MIN_STR_LEN = 2;
int Generator::DATASET_SIZE = 50000;
char *Generator::LETTERS = (char *)malloc(Generator::LETTER_COUNT * sizeof (char));
int Generator::WORLD_SIZE = 1;
int *Generator::SCATTER_SEND_BUFFER = nullptr;
char *Generator::ALL_WORDS = nullptr;
int Generator::ELEMENTS_PER_PROC = DATASET_SIZE;


void Generator::validate(int argc, char **argv){

    if (Generator::WORLD_SIZE > 100)
        throw invalid_argument("WORLD_SIZE can be 100 at max");

    if (Generator::WORLD_SIZE < 1)
        throw invalid_argument("WORLD_SIZE can't be lowest from 1");
        
    if (argc < 2)
        throw invalid_argument("CLI arguments must have 2 arguments at least");

    Generator::DATASET_SIZE = atoi(argv[1]);

    if (strlen(argv[1]) > 7 || Generator::DATASET_SIZE > 1000000)
        throw invalid_argument("MPI_DATASET_SIZE can be 1M at max");

    if (Generator::DATASET_SIZE <= 0)
        throw invalid_argument("MPI_DATASET_SIZE can't be zero or negative");
    

    Generator::MAX_STR_LEN = 10;
    if (argc > 2)
       Generator::MAX_STR_LEN = atoi(argv[2]);

    if (Generator::MAX_STR_LEN > 100)
        throw invalid_argument("MAX_STR_LEN can be 100 at max");

    if (Generator::MAX_STR_LEN < 2)
        throw invalid_argument("MAX_STR_LEN can't be lowest from 2");

    Generator::MIN_STR_LEN = 2;
    if (argc > 3)
       Generator::MIN_STR_LEN = atoi(argv[3]);

    if (Generator::MIN_STR_LEN > 99)
        throw invalid_argument("MIN_STR_LEN can be 99 at max");

    if (Generator::MIN_STR_LEN < 1)
        throw invalid_argument("MIN_STR_LEN can't be lowest from 1");

    if (Generator::MIN_STR_LEN >= Generator::MAX_STR_LEN)
        throw invalid_argument("MIN_STR_LEN has to be lowest from MAX_STR_LEN");

    Generator::ELEMENTS_PER_PROC = Generator::DATASET_SIZE / Generator::WORLD_SIZE;

}

void Generator::createLetters(){
    for (int i = 0; i < Generator::LETTER_COUNT; i  )
        Generator::LETTERS[i] = 'A'   i;
}


Generator::Generator(int argc, char **argv){
    Generator::validate(argc, argv);
    Generator::createLetters();
}

Generator::Generator(){}

// void Generator::Allocate2DArray(char ***arr, int row, int col){
//     *arr = (char **)malloc(row * sizeof(char*));
//     for (int i = 0; i < row; i  )
//         (*arr)[i] = (char *)malloc(col * sizeof(char));
// }

void Generator::CreateSendData(){
    Generator::SCATTER_SEND_BUFFER = (int *)malloc(Generator::WORLD_SIZE * sizeof(int));
    for (int i = 0; i < Generator::WORLD_SIZE; i  )
        SCATTER_SEND_BUFFER[i] = Generator::ELEMENTS_PER_PROC;
}

void Generator::CreateWord(char **word){
    int len = rand() % (Generator::MAX_STR_LEN - Generator::MIN_STR_LEN   1)   Generator::MIN_STR_LEN;
    *word = (char *)malloc((Generator::MAX_STR_LEN) * sizeof(char));
    int i = 0;
    for (; i < len; i  )
    {
        int r = rand() % LETTER_COUNT;
        (*word)[i] = Generator::LETTERS[r];
    }
    if (len != MAX_STR_LEN)
        (*word)[i] = '\0';
}

void Generator::CreateWords(char *arr, int buff_size){
    for (int i = 0; i < buff_size; i  ){
        char *word;
        Generator::CreateWord(&word);
        for (int j = 0; j < Generator::MAX_STR_LEN; j  )
        {
            arr[i*Generator::MAX_STR_LEN   j] = word[j];
            if (word[j] == '\0')
                break;
        }
    }
}

void Generator::WorkingTime(double start_time, double end_time){
    printf("That took %f seconds\n", end_time - start_time);
}

void Generator::WriteWord(char *word){
    for (int i = 0; i < Generator::MAX_STR_LEN; i  )
    {
        if (word[i] == '\0')
            break;
        cout << word[i];
    }
    
    cout << endl;
}

void Generator::WriteWords(){
    for (int i = 0; i < Generator::DATASET_SIZE; i  ){
        Generator::WriteWord((Generator::ALL_WORDS   i*Generator::MAX_STR_LEN));
    }
}

void Generator::WriteWords(char *arr, int buff_size){
    for (int i = 0; i < buff_size; i  )
        Generator::WriteWord((arr   i*Generator::MAX_STR_LEN));
}

TestGenerate.cpp

#include "Generator.hpp"
#include "Util.hpp"
#include <mpi.h>
#include <unistd.h>
int main(int argc, char **argv)
{

    Util::Clear();

    cout << "<<<==========GENERATION TEST START=========>>>" << endl;

    double start_time, end_time;

    MPI_Init(NULL, NULL);
    int world_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
    MPI_Comm_size(MPI_COMM_WORLD, &Generator::WORLD_SIZE);

    Generator *generator = new Generator(argc, argv);

    start_time = MPI_Wtime();

    Generator::SCATTER_SEND_BUFFER = NULL;
    Generator::CreateSendData();
    assert(Generator::SCATTER_SEND_BUFFER != NULL);

    int scatter_recv_buffer;
    MPI_Barrier(MPI_COMM_WORLD);

    MPI_Scatter(Generator::SCATTER_SEND_BUFFER, 1, MPI_INT, &scatter_recv_buffer, 1, MPI_INT, 0, MPI_COMM_WORLD);
    srand((world_rank   1) * time(0));

    char *words = (char *)malloc(sizeof(char) * scatter_recv_buffer * Generator::MAX_STR_LEN);
    Generator::CreateWords(words, scatter_recv_buffer);

    if (world_rank == 0)
        Generator::ALL_WORDS = (char *)malloc(sizeof(char) * Generator::DATASET_SIZE * Generator::MAX_STR_LEN);

    MPI_Barrier(MPI_COMM_WORLD);
    MPI_Gather(words, scatter_recv_buffer * Generator::MAX_STR_LEN, MPI_CHAR, Generator::ALL_WORDS, scatter_recv_buffer * Generator::MAX_STR_LEN, MPI_CHAR, 0, MPI_COMM_WORLD);

    if (world_rank == 0)
    {
        end_time = MPI_Wtime();
        Generator::WriteWords();
        Generator::WorkingTime(start_time, end_time);
        cout << "<<<===========GENERATION TEST END==========>>>" << endl;
    }

    MPI_Finalize();
}
  • Related