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();
}