MPI_Scatter of 2D array and malloc - c

I'm trying to write a program in C with the MPI library, in which the master process creates a 2D-array and distributes its rows of to the other processes. The matrix has dimensions p*p, in which p is the number of processes.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>
int **createMatrix (int nrows, int ncols) {
int **matrix;
int h, i, j;
if (( matrix = malloc(nrows*sizeof(int*))) == NULL) {
printf("Malloc error");
exit(1);
}
for (h=0; h<nrows; h++) {
if (( matrix[h] = malloc( ncols * sizeof(int))) == NULL) {
printf("Malloc error 2");
exit(1);
}
}
for (i=0; i<ncols; i++) {
for (j=0; j<nrows; j++) {
matrix[i][j] = ((i*nrows) + j);
}
}
return matrix;
}
void printArray (int *row, int nElements) {
int i;
for (i=0; i<nElements; i++) {
printf("%d ", row[i]);
}
printf("\n");
}
void printMatrix (int **matrix, int nrows, int ncols) {
int i;
for (i=0; i<nrows; i++) {
printArray(matrix[i], ncols);
}
}
int main (int argc, char **argv) {
if (MPI_Init(&argc, &argv) != MPI_SUCCESS) {
perror("Error initializing MPI");
exit(1);
}
int p, id;
MPI_Comm_size(MPI_COMM_WORLD, &p); // Get number of processes
MPI_Comm_rank(MPI_COMM_WORLD, &id); // Get own ID
int **matrix;
if (id == 0) {
matrix = createMatrix(p, p); // Master process creates matrix
printf("Initial matrix:\n");
printMatrix(matrix, p, p);
}
int *procRow = malloc(sizeof(int) * p); // received row will contain p integers
if (procRow == NULL) {
perror("Error in malloc 3");
exit(1);
}
if (MPI_Scatter(*matrix, p, MPI_INT, // send one row, which contains p integers
procRow, p, MPI_INT, // receive one row, which contains p integers
0, MPI_COMM_WORLD) != MPI_SUCCESS) {
perror("Scatter error");
exit(1);
}
printf("Process %d received elements: ", id);
printArray(procRow, p);
MPI_Finalize();
return 0;
}
The output I receive when running this code is
$ mpirun -np 4 test
Initial matrix:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
Process 0 received elements: 0 1 2 3
Process 1 received elements: 1 50 32 97
Process 2 received elements: -1217693696 1 -1217684120 156314784
Process 3 received elements: 1 7172196 0 0
Process 0 apparently receives the correct input, but the other processes show numbers I can't make sense of. Also note that the numbers of process 1 and 3 are consistent over multiple runs of the program, whereas the numbers of process 2 change in each run.
It seems to me that there's something wrong in my memory allocating or pointer usage, but I'm quite new to programming in C. Could anyone explain to me how and why this output is produced? Secondary, obviously, I'm also interested in how to solve my issue :) thanks in advance!

I think you have fundamentally misunderstood what the scatter operation does and how MPI expects memory to be allocated and used.
MPI_Scatter takes the source array and splits it into pieces, sending a unique piece to each member of the MPI communicator. In your example, you would need your matrix to be an allocation of contiguous p*p elements in linear memory, which would send p values to each process. Your source "matrix" is an array of pointers. There is no guarantee that the rows are sequentially arranged in memory, and MPI_Scatter doesn't know how to traverse the array of pointers you have passed it. As a result, the call is simply reading beyond the end of the first row you passed by indirection of the matrix pointer, treating whatever follows that in memory as data. That is why you get garbage values in the processes which receive the data after the first row.
All MPI data copy routines expect that source and destination memory are "flat" linear arrays. Multidimensional C arrays should be stored in row major order not in arrays of pointers as you have done here. A cheap and nasty hack of your example to illustrate a scatter call working correctly would be like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>
int *createMatrix (int nrows, int ncols) {
int *matrix;
int h, i, j;
if (( matrix = malloc(nrows*ncols*sizeof(int))) == NULL) {
printf("Malloc error");
exit(1);
}
for (h=0; h<nrows*ncols; h++) {
matrix[h] = h+1;
}
return matrix;
}
void printArray (int *row, int nElements) {
int i;
for (i=0; i<nElements; i++) {
printf("%d ", row[i]);
}
printf("\n");
}
int main (int argc, char **argv) {
if (MPI_Init(&argc, &argv) != MPI_SUCCESS) {
perror("Error initializing MPI");
exit(1);
}
int p, id;
MPI_Comm_size(MPI_COMM_WORLD, &p); // Get number of processes
MPI_Comm_rank(MPI_COMM_WORLD, &id); // Get own ID
int *matrix;
if (id == 0) {
matrix = createMatrix(p, p); // Master process creates matrix
printf("Initial matrix:\n");
printArray(matrix, p*p);
}
int *procRow = malloc(sizeof(int) * p); // received row will contain p integers
if (procRow == NULL) {
perror("Error in malloc 3");
exit(1);
}
if (MPI_Scatter(matrix, p, MPI_INT, // send one row, which contains p integers
procRow, p, MPI_INT, // receive one row, which contains p integers
0, MPI_COMM_WORLD) != MPI_SUCCESS) {
perror("Scatter error");
exit(1);
}
printf("Process %d received elements: ", id);
printArray(procRow, p);
MPI_Finalize();
return 0;
}
which does this:
$ mpicc -o scatter scatter.c
$ mpiexec -np 4 scatter
Initial matrix:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Process 0 received elements: 1 2 3 4
Process 1 received elements: 5 6 7 8
Process 2 received elements: 9 10 11 12
Process 3 received elements: 13 14 15 16
ie. when you pass the data stored in linear memory, it works. The equivalent row major array would be statically allocated like this:
int matrix[4][4] = { { 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 },
{ 13, 14, 15, 16 } };
Note the difference between a statically allocated two dimensional array, and the array of pointers which your code allocated dynamically. They are not at all the same thing, even though they look superficially similar.

Related

What's causing SIGSEV when my matrix is a certain size?

Just having an issue here with SIGSEV.
The role of this program is to build a matrix of n * n, which is the first command line argument, and then furthermore fills out the matrix from integers sourced from command line arguments.
The output then consists of the main diagonal of this matrix summed together
Example:
1 2 3
4 5 6
7 8 9
1 + 5 + 9 = 15
Sample input:
./file-name 3 1 2 3 4 5 6 7 8 9
Sample output:
15
However I'm very confused, as it works with all matrices under size 5, but once I go over, I get this address boundary error. Anyone know why?
Error:
fish: Job 1, './file-name 5...' terminated by signal SIGSEV (Address boundary error)
Code:
/* Description: Takes integer arguments from command line
* First argument signafies matrix's size, (n * n)
* Remaining arguments fill matrix.
* Then the main diagonal of the matrix is summed
* and outputted
* Input: Multiple integers as cmd line arguments, first signifies
* matrix size (n * n)
* Output: A single integer, the sum of the diagonals
*
*/
// Includes
#include <stdio.h>
#include <stdlib.h>
// Function Prototypes
void fill_matrix(int **matrix, int n, char **argv);
int sum_diag_matrix(int **matrix, int n);
// Main Function
int main(int argc, char **argv) {
// Take cmd line args
int n = atoi(argv[1]);
// Assign and allocate double pointer enough memory for matrix of size n
int **matrix = (int **) malloc(n * sizeof(int));
// Assign pointers inside double pointer of matrix enough memory for vector of size n
for ( int i = 0; i < n; ++i ) {
*(matrix + i) = (int *) malloc(n * sizeof(int));
}
// Call fill_matrix function to fill our matrix from cmd line args
fill_matrix(matrix, n, argv);
// Assign total to the return of our sum_diag_matrix function
int total = sum_diag_matrix(matrix, n);
// Output our total
printf("%i\n", total);
// Return 0 to signal script running correctly
return 0;
}
// Fill matrix function fills the matrix of passed size n from passed array
void fill_matrix(int **matrix, int n, char **arr) {
// Initialize element integer to keep track of what element we're on
int element = 0;
// Nested loop iterates over matrix, filling out the values from the given array
for ( int i = 0; i < n; ++i) {
for ( int j = 0; j < n; ++j) {
*(*(matrix + i) + j) = atoi(arr[element + 2]);
printf("%i\n", *(*(matrix + i) + j));
element++;
}
}
// Return nothing for void
return;
}
// Sum diag matrix function sums the main diagonal of the matrix passed of passed size n
int sum_diag_matrix(int **matrix, int n) {
// Initialize total to keep track of sum
int total = 0;
// Iterate over diagonal elements of matrix
for ( int i = 0; i < n; ++i) {
total += *(*(matrix + i) + i);
}
// Return total sum
return total;
}
I'm new to pointers and such, so I'm trying to apply them everywhere, so potentially it could be that? Regardless I'm not too sure and I'm slightly stumped.
Any help would be appreciated!
-fsanitize=address is usually a great tool in debugging these kinds of problems. Even with the input you claim works, it spots the problem:
==1==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000018 at pc 0x000000401284 bp 0x7fff8ff3b540 sp 0x7fff8ff3b538
WRITE of size 8 at 0x602000000018 thread T0
#0 0x401283 in main /app/example.c:28
#1 0x7fd9788e9082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
#2 0x40111d in _start (/app/output.s+0x40111d)
0x60200000001c is located 0 bytes to the right of 12-byte region [0x602000000010,0x60200000001c)
allocated by thread T0 here:
#0 0x7fd978b72bbf in malloc (/opt/compiler-explorer/gcc-12.2.0/lib64/libasan.so.8+0xbbbbf)
#1 0x40122c in main /app/example.c:25
#2 0x7fd9788e9082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
SUMMARY: AddressSanitizer: heap-buffer-overflow /app/example.c:28 in main
Shadow bytes around the buggy address:
It says that at line 28, we're exceeding the memory allocated at line 25.
int **matrix = (int **) malloc(n * sizeof(int)); // Line 25
// Assign pointers inside double pointer of matrix enough memory for vector of size n
for ( int i = 0; i < n; ++i ) {
*(matrix + i) = (int *) malloc(n * sizeof(int)); // Line 28
}
Immediately, we see you use sizeof(int) and assign to int **, which is wrong. Fixed:
int **matrix = (int **) malloc(n * sizeof(int *));
(Also, you leak the memory on exit, which isn't a problem in systems with virtual memory like your desktop PC.)
Using the following macro would would also have caught the problem.
#define MALLOC(t, n) ( (t*)malloc(sizeof(t) * n) )
#define REALLOC(p, t, n) ( (t*)realloc(p, sizeof(t) * n) )
int **matrix = MALLOC(int*, n); // Warns if `int` is used instead of `int*`.
for ( int i = 0; i < n; ++i ) {
matrix[i] = MALLOC(int, n);
}

Why is realloc not resizing the memory of my array? [duplicate]

This question already has answers here:
C - Accessing data AFTER memory has been free()ed?
(2 answers)
Closed 2 years ago.
I'm studying C and I'm seeing something that it's not clear to me.
Here's the code:
#include <stdlib.h>
#include <stdio.h>
int main(void) {
printf("I'm using malloc\n");
int size = 10000000;
int *arr = (int *)malloc(size * sizeof(int));
if (arr == NULL) {
printf("memory could not be allocated\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < size; i++) {
arr[i] = i;
}
printf("Check the memory of the process\n");
int c;
scanf("%d", &c);
printf("I'm using realloc\n");
int *newArr = realloc(arr, 5 * sizeof(int));
if (newArr == NULL) {
printf("memory could not be allocated\n");
exit(EXIT_FAILURE);
}
int d;
printf("Check the memory of the process\n");
scanf("%d", &d);
for (int i = 0; i < 15; i++) {
printf("%d\n", arr[i]);
}
free(newArr);
}
If I check the process running with top, I can see that the memory of the process shrinks because of the realloc operation, what I wasn't expecting is that the last for loop is actually printing the first 15 numbers from arr. I was expecting an error due to missing elements from 5 to 15.
I'm using malloc
Check the memory of the process
45
I'm using realloc
Check the memory of the process
45
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Can you explain to me how this is working?
After the reallocation, you forgot to assign arr with newArr and then you print values form the invalid arr. (UB no 1)
Secondly, even if you assign it (or only change the arr to newArr) in the printf you will access elements outside the array bounds - which is UB no 2

MPI Segmentationi fault MPI_Scatter using C

I am new in this area and use OpenMPI and C. I try to find out why my code leads to an Segmentatioin fault. I red already a lot about MPI but I did not find any help. It took me already hours. So I decided to ask here for help.
I get the expected result of my code. But I also get every time an error message.
Is it right how I use MPI_Scatter in my case?
Here is my simple code:
#include <stdio.h>
#include "mpi.h"
#include <stdlib.h>
const int MASTER_RANK = 0;
#define DIM 3
int main(int argc, char* argv[])
{
int numProc, rank;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numProc);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int n = 9;
double *m;
double *m_client;
m_client = (double *)malloc(3);
if(rank == MASTER_RANK)
{
m = (double* )malloc(n);
for(int i=0; i<n; i++)
{
m[i] = (double)i+1.0;
}
}
MPI_Scatter(m, 3, MPI_DOUBLE, m_client, 3, MPI_DOUBLE, MASTER_RANK, MPI_COMM_WORLD);
printf("Process %d:\n", rank);
for(int i=0; i < 3; i++)
{
printf(" (%lf", m_client[i]);
m_client[i] += 1000*rank;
printf(" -> %lf)", m_client[i]);
printf("\n");
}
printf( "\n" );
MPI_Gather(m_client, 3, MPI_DOUBLE, m, 3, MPI_DOUBLE, MASTER_RANK, MPI_COMM_WORLD);
if(rank == MASTER_RANK)
{
printf("Master: Received= \n");
for(int i=0; i<numProc; i++)
{
for(int j=0; j < 3; j++)
{
int idx = i*3 + j;
printf("%lf ", m[idx]);
}
printf("from Process %d\n", i);
}
}
free(m);
free(m_client);
MPI_Finalize();
exit(0);
}
I build my MPI file by using mpicc mpifile.c -o mpifile and run it with mpirun -np 3 ./mpifile. I use 3 processes.
The error I get is:
[Samuel-Z97-HD3:14361] *** Process received signal ***
[Samuel-Z97-HD3:14361] Signal: Segmentation fault (11)
[Samuel-Z97-HD3:14361] Signal code: (128)
[Samuel-Z97-HD3:14361] Failing at address: (nil)
I am using Ubuntu and vim / Geany.
Your code has two problems.
Both your malloc() calls are having wrong sizes. You should allocate number of bytes instead of number of doubles. E.g. instead of calling malloc(3), call malloc(3*sizeof(double)).
Another problem is that your variable m should be initialized to NULL. Alternatively, you could surround free(m) with if(rank == MASTER_RANK). As is, a non-master process calls free(m) where m is uninitialized and could contain arbitrary value.

Scattering a contiguous 2D Array using MPI

I don't seem to get this right, i want to scatter a 2D block and just print the scattered parts, this is for testing purpose
Here's what I'm trying to do ...
#include <stdio.h>
#include <stdlib.h>
#include "mpi/mpi.h"
void print2D(int**, int, int);
int main(int argc, char* argv[])
{
int rank, pSize, r1, c1, rowsPerProcess, i, j;
int** matA = NULL, **partMat = NULL;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &pSize);
if(rank == 0)
{
scanf("%d%d", &r1, &c1);
rowsPerProcess = r1/pSize; // number of rows assigned to each process (Assume this produces no remainder)
//Contiguous allocation
int* mat1D = (int*)malloc(r1 * c1 * sizeof(int));
matA = (int**)malloc(r1 * sizeof(int*));
for(i=0; i<r1; i++)
matA[i] = &mat1D[i * c1];
for(i=0; i<r1; i++) //Fill the 2D array
for(j=0; j<c1; j++)
matA[i][j] = i + j;
printf("Original Matrix:\n");
print2D(matA, r1, c1);
}
MPI_Bcast(&c1, 1, MPI_INT, 0, MPI_COMM_WORLD); //Columns
MPI_Bcast(&rowsPerProcess, 1, MPI_INT, 0, MPI_COMM_WORLD); //Rows in every process
//Again, contiguous allocation for the partial 2D array
int* partMat1D = (int*)malloc(rowsPerProcess * c1 * sizeof(int));
partMat = (int**)malloc(rowsPerProcess * sizeof(int*));
for(i=0; i<rowsPerProcess; i++)
partMat[i] = &partMat1D[i * c1];
MPI_Scatter(&(matA[0][0]), rowsPerProcess * c1, MPI_INT, &(partMat[0][0]),
rowsPerProcess * c1, MPI_INT, 0, MPI_COMM_WORLD);
printf("FROM PROCESS %d:\n", rank);
print2D(partMat, rowsPerProcess, c1);
MPI_Finalize();
return 0;
}
void print2D(int** mat, int row, int col)
{
if(mat != NULL)
{
int i, j;
for(i=0; i<row; i++)
{
for(j=0; j<col; j++)
printf("%d ", mat[i][j]);
printf("\n");
}
}
}
and I receive a segmentation fault error on running this with 4 processes
e.g.
8 3
Original Matrix:
0 1 2
1 2 3
2 3 4
3 4 5
4 5 6
5 6 7
6 7 8
7 8 9
FROM PROCESS 0:
0 1 2
1 2 3
===================================================================================
= BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
= PID 2637 RUNNING AT minix-VirtualBox
= 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
Only process 0 print its part correctly.
Am i using MPI_Scatter wrong? how do i fix this?
how do i scatter this 2D block right?
On the non-master processes, you initialize matA to NULL, and then proceed to evaluate the expression &matA[0][0]. This dereferences matA, crashing your process even before it enters MPI_Scatter().
Since you are programming in C, you can avoid those double pointers: C has quite good multidimensional array support built in since C99, and you can use it to make your life much easier. Just declare matA as a pointer to a line array
int (*matA)[c1];
then allocate an array of r1 rows for it
matA = malloc(r1*sizeof(*matA));
After that you can fill your array with the same code as you used in your code above:
for(i=0; i<r1; i++) //Fill the 2D array
for(j=0; j<c1; j++)
matA[i][j] = i + j;
Also, since your 2D array needs only one malloc() call, you can also dispose it off with a single free() call:
free(matA);
Note: You cannot do this in C++, it does not support variable length arrays the way C does, and probably never will. This is one of the few points where C is much more powerful than C++.

How to use functions with arrays correctly

This is a small program that I wrote to add 2 square matrices.
When i input the second matrix the values of the first are altered and the result is subsequently false. It works quite well for 2x2 matrices,But not for any bigger matrix.
The algorithm works well without the use of functions.
Please help me solve this problem.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
int n;
void PrintMatrix(int P[n][n])
{
int i,j;
for(i=0;i<n;i++)
{
printf("\n");
for(j=0;j<n;j++)
{
printf("%d\t", P[i][j]);
}
}printf("\n");
}
void ReadMatrix(int P[n][n])
{
int i,j;
for(i=0;i<n;i++)
{
printf("input row %d\n", i+1);
for(j=0;j<n;j++)
{
scanf("%d", &P[i][j]);
}
}
}
void AddMatrix(int P[n][n], int Q[n][n], int Result[n][n])
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
Result[i][j]=P[i][j]+Q[i][j];
}
}
}
int main()
{
int i,j;
int A[n][n];
int B[n][n];
int Sum[n][n];
printf("input matrix size:");
scanf("%d", &n);
printf("input first matrix\n");
ReadMatrix(A);
PrintMatrix(A);
printf("input second matrix\n");
ReadMatrix(B);
PrintMatrix(B);
AddMatrix(A,B,Sum);
PrintMatrix(Sum);
return 0;
}
You can define your own matrix type with a struct, such as for example:
typedef struct
{
int* data;
size_t width;
size_t height
} matrix_t;
Or if you have a modern C compiler, you can write the functions like
void func (size_t width, size_t height, int matrix[width][height])
But the struct version is probably to prefer.
EDIT
As for why your program is buggy, you must initialize n to a value. If you declare the arrays as variable-length arrays of size [n][n] after the point where you read n from the user, it should work fine.
if you run this under gdb here is something you'll find
(gdb) p A
$14 = 0x7fffffffdfb0
(gdb) p B
$15 = 0x7fffffffdfa0
irrespective of whatever "n" you choose the array base address always differ by 16 that is integer 2 x 2 matrix works
but if i Input length as 3 the program crashes. There is memory corruption.
before doing input
(gdb) x/12 A
0x7fffffffdfb0: 0 0 -255260739 52
0x7fffffffdfc0: -1 -1 -1 -1
0x7fffffffdfd0: -8272 32767 -1 -1
after input:
x/12 0x7fffffffdfb0
0x7fffffffdfb0: 1 2 3 4
0x7fffffffdfc0: 5 6 7 8
0x7fffffffdfd0: 9 32767 -1 -1
is fine as i gave values 1 2 3 4 5 6 7 8 9
but
p A
$16 = 0x7fff00000009
is this accessing it causes segmentation fault in PrintMatrix.
now if you change your program to this
int main()
{
int i,j;
printf("input matrix size:");
scanf("%d", &n);
int A[n][n];
int B[n][n];
int Sum[n][n];
your problems are solved and you are good to go

Resources