I'm trying to work with 2D arrays and MPI_Scatterv. When I call MPI_Scatterv I get
================================================================================
= BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
= PID 5790 RUNNING AT ubuntu
= EXIT CODE: 139
= CLEANING UP REMAINING PROCESSES
= YOU CAN IGNORE THE BELOW CLEANUP MESSAGES
================================================================================
YOUR APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault (signal 11)
This typically refers to a problem with your application.
Please see the FAQ page for debugging suggestions
If I use C99 2D arrays it works, but not with malloc. I want to know where I'm wrong with malloc. I can't use linearized 2D array, so I can't create array like array[i*columns+j]
Here is a test program:
int **alloc2d(int n, int m) {
int i;
int **array = malloc(n * sizeof(int*));
array[0] = malloc(n * m * sizeof(int));
for(i = 1; i < n; i++)
array[i] = array[i-1] + m;
return array;
}
int *genSendc(int dim, int numprocs) {
int* sendc = (int*)malloc(sizeof(int)*numprocs);
int i;
int subsize = dim/numprocs;
for(i=0; i<numprocs; ++i)
sendc[i] = subsize;
for(i=0; i<dim-subsize*numprocs; ++i)
sendc[i]+=1;
return sendc;
}
int *genDispl(int numprocs, int*sendc) {
int* displ = (int*)malloc(sizeof(int)*numprocs);
int i;
displ[0]=0;
for(i=1; i<numprocs; ++i)
displ[i] = displ[i-1]+sendc[i-1];
return displ;
}
int main(int argc, char *argv[]){
int numprocs, rank, i, j, N=5, M=4;
int* displMat, *sendcMat;
int **txMatrix, **rxMatrix;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
sendcMat = genSendc(N, numprocs);
for(i=0; i<numprocs; ++i)
sendcMat[i] *= M;
displMat = genDispl(numprocs, sendcMat);
rxMatrix = alloc2d(sendcMat[rank]/M, M);
if (rank == 0) {
srand(time(NULL));
txMatrix = alloc2d(N, M);
for (i=0; i < N; ++i)
for(j=0; j < M; ++j)
txMatrix [i][j] = (rand() % 10)+1;
}
MPI_Scatterv(&txMatrix[0][0], sendcMat, displMat, MPI_INT, &rxMatrix[0][0], sendcMat[rank], MPI_INT, 0, MPI_COMM_WORLD);
MPI_Finalize();
}
If I print rxMatrix after MPI_Scatterv, the program prints Rank0 sub-matrix and then it crashes with segmentation fault. Where am I wrong?
This expression invokes undefined behavior if txMatrix is not properly initialized.
&txMatrix[0][0]
While the first argument to MPI_Scatterv is inconsequential on non-root ranks*, just evaluating the expression can cause a segfault. Just use an if/else for root/nonroot and pass NULL for the latter.
*: at least per the standard, I've seen this be bugged in MPI implementations.
Related
I am a novice C programmer trying to write a function that dynamically allocates space for a 2D array. I am getting a segmentation fault when running this code & i'm not sure why.
#include <stdio.h>
#include <stdlib.h>
int allocate_space_2D_array(int **arr, int r, int c) {
int i,j;
arr = malloc(sizeof(int *) * r);
for (i = 0; i < r; i++)
arr[i] = malloc(sizeof(int *) * c);
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
printf("%p", arr[r][c]);
}
printf("\n");
}
return arr;
}
I expected to be able to print out and see the contiguous memory locations of each spot in the array, but I am never reaching that point in my code, because when I run it, i get a segmentation fault. Would appreciate any help.
Seeing your program i see 3 errors one while you allocate memory for 2D-array,one while you're printing and another one is how you declare the function.
First malloc is ok,the second one is wrong cause you already allocated memory for r(size of row) pointers so it's just like if you have * arr[r],so to allocate memory correctly now you should allocate memory just for int and not for int*.
Second error while printing you put as index for row and column the values r and c,but r and c are the size of matrix , as we know the size of an array or 2D-array goes from 0 to size-1,in your case goes from 0 to r-1 and from 0 to c-1.
Third error you should declare the function not as int but as int** cause you want to return a matrix so the return type is not int but int**.
I change your code to make it work correctly,it should be work.
int** allocate_space_2D_array(int **arr, int r, int c) {
int i,j;
arr = malloc(sizeof(int *) * r);
for (i = 0; i < r; i++)
arr[i] = malloc(sizeof(int ) * c);
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
printf("%p", arr[i][j]);
}
printf("\n");
}
return arr;
}
I am new to programming and am trying to use two functions for matrix (2D array) operations, where the output of one function is the input for the next.
However, I do not find a way to correctly deliver the values from one function to another. When I print the outputs of the first function in main (), they are correct, but when I input them into the 2nd function and print them, the values make no sense. I have tried it a lot of ways, but it probably fails due to my lack of understanding double pointers.
I am thankful for any hint or advise!
#include <stdio.h>
#include <stdlib.h>
int** td (int r_in, int c_in, int r_p, int c_p, int input[][c_in],int params[][c_p]){
int i, j, k;
int**y_td;
// memory allocation
y_td = (int*)malloc(sizeof(int*)*r_in);
for (i=0; i < r_in; i++){
y_td[i] = (int*)malloc(sizeof(int)*c_p);
}
//
for (i=0; i < r_in; i++){
for (j=0; j < c_p; j++){
y_td[i][j]=0; // Initialization
for (k=0; k < c_in; k++){
y_td[i][j]+= input[i][k]*params[k][j];
}
}
}
return y_td;
}
int** cnv (int r_in, int c_in, int filter, int f_size, int input[][c_in], int params[][f_size][c_in]){
int x,i,j,k,l,m,n;
int min_len = ((r_in < f_size)? r_in:f_size);
int max_len = ((r_in > f_size)? r_in:f_size);
int r_out = max_len - min_len + 1;//rows_out
int kernel;
int** y_cnv;
// Print input to check if it was correctly transmitted to the function
printf("Input CV (should be equal to TD result):\n");
for (i=0;i<r_in;i++){
for (j=0;j<c_in;j++){
printf("%d ", input[i][j]);
}
printf("\n");
}
printf("\n\n");
//memory allocation
y_cnv = (int*)malloc(sizeof(int*)*r_out);
for (i=0; i < r_out; i++){
y_cnv[i] = (int*)malloc(sizeof(int)*filter);
}
//
for (i=0; i < filter; i++){
for (k=0; k < r_out; k++){
y_cnv [k][i]=0; //initialize
}
for (j = 0; j < c_in; j++){
for (n = min_len-1; n < max_len; n++){
x = n-min_len+1;
for (m= 0; m < r_in; m++){
kernel = (((n-m) < min_len && (n-m) >= 0)? params[i][n-m][j]:0);
y_cnv[x][i] += input[m][j]*kernel;
}
}
}
}
return y_cnv;
}
int main() {
// create test arrays
int A [4][2]= {{1,1},{2,2},{3,3},{4,4}};
int B [2][3]= {{1,2,3},{2,3,4}};
int C [2][2][3]= {{{1,1,1},{2,2,2}},{{3,3,3},{4,4,4}}};
int** matrix;
int i, j;
matrix = td(4,2,2,3,A,B);
// print the result of first function, which is input in 2nd function
printf("The TD result is:\n");
for (i=0;i<4;i++){
for (j=0;j<3;j++){
printf("%d ",matrix[i][j]);
}
printf("\n");
}
printf("\n\n");
matrix = cnv(4,3,2,2,matrix,C);
return 0;
}
I expect the matrix printed in main () after the first function td () to be the same as when I read it in the second function cnv () and print it there, but it is not.
take a look at this question. You were hit by the same underlying problem.
Turning
int** cnv (int r_in, int c_in, int filter, int f_size, int input[][c_in], int params[][f_size][c_in])
into
int** cnv (int r_in, int c_in, int filter, int f_size, int** input, int params[][f_size][c_in])
fixes the problem you asked for.
The reason is that you allocate an array of pointers called y_td in your first function. Each of this pointers is a number naming a memory segment where you stored some real numbers. By using int input[][c_in] you tell the computer to interpret these pointers as integer numbers and when you print them you get the addresses in memory instead of the expected values, because then input[x][y] is translated to *((int *)input+x*c_in+y).
Please allow me one more comment: You should follow the comments below the question and care for all compiler warnings: If there is a warning you should treat it as an compiler error unless you exactly know what you are doing, especially in C. Your code contains some possible problem sources like the one above.
I'm trying to make an MPI matrix multiplication program but the scatter function doesn't seem to be working for me. Only one row is getting scattered and the rest of the cores receive garbage value.
Also when calling the display_matrix() function before I MPI_Init() seems to be running 4 threads instead of 1 (I have quad core CPU). Why is this happening even before initialisation?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include<mpi.h>
int **matrix_generator(int row,int col);
int **multiply_matrices(int **matrix_A,int **matrix_B,int rowsA, int colsA,int rowsB,int colsB);
void display_matrix(int **matrixA,int rows,int cols);
void main(int argc,char *argv[])
{
srand(time(0));
int **matrix_A,**matrix_B,**matrix_result,*scattered_matrix,*gathered_matrix, rowsA,colsA,rowsB,colsB,world_rank,world_size,i,j;
rowsA = atoi(argv[1]);
colsA = atoi(argv[2]);
rowsB = atoi(argv[3]);
colsB = atoi(argv[4]);
scattered_matrix = (int *)malloc(sizeof(int) * rowsA*colsA/4);
if (argc != 5)
{
fprintf(stderr,"Usage: mpirun -np <No. of processors> ./a.out <Rows A> <Columns A> <Rows B> <Columns B>\n");
exit(-1);
}
else if(colsA != rowsB)
{
printf("Check the dimensions of the matrices!\n\n");
}
matrix_A = matrix_generator(rowsA,colsA);
matrix_B = matrix_generator(rowsB,colsB);
display_matrix(matrix_A,rowsA,colsA);
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
MPI_Scatter(matrix_A, rowsA*colsA/4, MPI_INT, scattered_matrix, rowsA*colsA/4, MPI_INT, 0, MPI_COMM_WORLD);
for(i=0;i<world_size;i++)
{
printf("Scattering data %d from root to: %d \n",scattered_matrix[i],world_rank);
}
MPI_Barrier(MPI_COMM_WORLD);
MPI_Finalize();
}
int **matrix_generator(int row, int col)
{
int i, j, **intMatrix;
intMatrix = (int **)malloc(sizeof(int *) * row);
for (i = 0; i < row; i++)
{
intMatrix[i] = (int *)malloc(sizeof(int *) * col);
for (j = 0;j<col;j++)
{
intMatrix[i][j]=rand()%10;
}
}
return intMatrix;
}
void display_matrix(int **matrix, int rows,int cols)
{
int i,j;
for (i = 0; i < rows; i = i + 1)
{
for (j = 0; j < cols; j = j + 1)
printf("%d ",matrix[i][j]);
printf("\n");
}
}
The main issue is your matrices are not allocated in contiguous memory (see the comment section for a link)
The MPI standard does not specify what happens before an app invokes MPI_Init().
The two main MPI implementations choose to spawn all the tasks when mpirun is invoked (that means there are 4 independent processes first, and they "join" into a single MPI job when they all call MPI_Init()).
That being said, once upon a time, a vendor chose to have mpirun start a single MPI task, and they use their own remote-fork when MPI_Init() is called.
Bottom line, if you want to write portable code, do as less as possible (and never print anything) before MPI_Init() is called.
I know this has been answered many times before and there is a comprehensive answer here which I have read and attempted to use but I just can't get my code to work for some reason.
I have stripped my code down a bit to make it a bit easier to follow, but basically what I am trying to do is have each process initialise a sub-array and work on it, then put the whole big array back together on rank 0. MPI_Gatherv is giving me a segfault and I cannot figure out why.
Any help would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <mpi.h>
#define N 32
void init_lattice(double **site, int row, int col){
int i,j;
for(i=0; i<row; i++){
for(j=0; j<col; j++){
site[i][j]=(drand48()/4294967295.0 + 0.5)*2*M_PI;
}
}
}
int main(int argc, char *argv[]){
int nprocs, rank;
MPI_Init(&argc, &argv);
MPI_Comm_size (MPI_COMM_WORLD, &nprocs);
MPI_Comm_rank (MPI_COMM_WORLD, &rank);
int dim = 2;
int grid[dim];
grid[0]=0;
grid[1]=0;
// Assign the grid dimensions
MPI_Dims_create(nprocs, dim, grid);
printf("Dim grid: length: %d, width: %d\n", grid[0], grid[1]);
// The new communicator
MPI_Comm comm_grid;
// Allow cyclic behavior
int periodic[dim];
periodic[0] = 1;
periodic[1] = 1;
// Create the communicator
MPI_Cart_create(MPI_COMM_WORLD, dim, grid, periodic, 0, &comm_grid);
int block_len, block_width;
block_len = N/grid[1];
block_width = N/grid[0];
int i, j;
//Create lattice subset
double *data = (double *) malloc (block_len * block_width * sizeof(double));
double **site = (double **) malloc (block_len * sizeof(double *));
for (i = 0; i < block_len; i++)
site[i] = & (data[i * block_width]);
//Initialise lattice
init_lattice(site, block_len, block_width);
MPI_Datatype newtype, subtype;
int sizes[dim];
sizes[0]=N;
sizes[1]=N;
int subsizes[dim];
subsizes[0] = block_len;
subsizes[1] = block_width;
int starts[dim];
starts[0] = 0;
starts[1] = 0;
MPI_Type_create_subarray(2, sizes, subsizes, starts, MPI_ORDER_C, MPI_DOUBLE, &newtype);
MPI_Type_create_resized(newtype, 0, N/grid[1]*sizeof(double), &subtype);
MPI_Type_commit(&subtype);
int sendcounts[grid[0]*grid[1]];
int displs[grid[0]*grid[1]];
if (rank == 0) {
for (i=0; i<grid[0]*grid[1]; i++) sendcounts[i] = 1;
int disp = 0;
for (i=0; i<grid[0]; i++) {
for (j=0; j<grid[1]; j++) {
displs[i*grid[0]+j] = disp;
disp += 1;
}
disp += ((N/grid[1])-1)*grid[0];
}
}
//Create global lattice
double *global_data = (double *) malloc (N * N * sizeof(double));
double **global_site = (double **) malloc (N * sizeof(double *));
for (i = 0; i < N; i++)
global_site[i] = & (global_data[i * N]);
MPI_Gatherv(&(site[0][0]), N*N/(grid[0]*grid[1]), MPI_DOUBLE, &(global_site[0][0]), sendcounts, displs, subtype, 0, MPI_COMM_WORLD);
if(rank==0){
printf("Rank: %d\n", rank);
for(i=0; i<N; i++){
for(j=0; j<N; j++){
printf("%.2lf ", global_site[i][j]);
}
printf("\n");
}
}
return 0;
}
EDIT:
Ok so I have changed my array allocations to contiguous memory and everything is working as it should now. Thanks talonmies!
The fundamental problem here is that MPI expects all allocations to be contiguous blocks of memory. Your site and global_site arrays are not, they are arrays of pointers. The MPI routines are just reading past the end of each individual row allocation and causing your segfault.
If you want to allocate an n x n array to use with the MPI then you need to replace this:
double **global_site;
if(rank==0){
global_site = malloc(sizeof(double *)*(N));
for(i=0; i<N; i++)
global_site[i] = malloc(sizeof(double)*(N));
}
with something like this:
double *global_site = malloc(sizeof(double)*(N * N));
You will obviously need to adjust the rest of your code accordingly.
It seems the only reason you are actually using arrays of pointers is for the convenience of [i][j] style 2D indexing. If you use linear or pitched linear memory, you can easily make a little preprocessor macro or helper function which can give you that style of indexing into row or column major ordered storage which is still compatible with MPI.
I was experimenting some basic C code that defines an int matrix with pointers.
typedef int **Matrix;
Matrix createMatrix(int lines, int columns) {
int i, j;
Matrix m = (Matrix) malloc(sizeof(int) * lines * columns);
for (i = 0; i < lines; ++i) {
for (j = 0; j < columns; ++j) {
m[i][j] = 0;
}
}
return m;
}
int main(int argc, char**argv) {
Matrix m = createMatrix(5, 10);
// ...
if (m[2][3] == 20) {
// ...
}
return 0;
}
However, these m[i][j] accesses are throwing segmentation faults. What's wrong here? Too many asterisks?
I was convinced that a pointer to a pointer to an int was effectively the same as a matrix.
Your allocation of the Matrix data item assumes you're accessing it linearly with a single index. If you want to access it with two indices, e.g., m[1][1] you need to allocate each dimension:
Matrix m = malloc(sizeof(int *) * lines);
for ( int i = 0; i < lines; i++ )
m[i] = malloc(sizeof(int) * columns);
Note also that you should not type cast malloc.