Changed project structure
This commit is contained in:
parent
c59f5a4b9b
commit
9256e535ff
2
LICENSE
2
LICENSE
|
@ -1,5 +1,5 @@
|
|||
MIT License
|
||||
Copyright (c) <year> <copyright holders>
|
||||
Copyright (c) 2016 Fabio Salvini
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
|
26
Makefile
Normal file
26
Makefile
Normal file
|
@ -0,0 +1,26 @@
|
|||
CC=mpicc
|
||||
CFLAGS=-Wall -lm -std=c99
|
||||
SRC=src
|
||||
BUILD=build
|
||||
BIN=bin
|
||||
|
||||
all: sequential mpi_line
|
||||
|
||||
sequential: config utils main
|
||||
${CC} ${CFLAGS} ${BUILD}/config.o ${BUILD}/utils.o ${BUILD}/main.o ${SRC}/impl/sequential.c -o ${BIN}/jacobi_sequential
|
||||
|
||||
mpi_line: config utils main
|
||||
${CC} ${CFLAGS} ${BUILD}/config.o ${BUILD}/utils.o ${BUILD}/main.o ${SRC}/impl/mpi_line.c -o ${BIN}/jacobi_mpi_line
|
||||
|
||||
main: ${SRC}/main.c
|
||||
${CC} -c ${CFLAGS} ${SRC}/main.c -o ${BUILD}/main.o
|
||||
|
||||
config: ${SRC}/config.c
|
||||
${CC} -c ${CFLAGS} ${SRC}/config.c -o ${BUILD}/config.o
|
||||
|
||||
utils: ${SRC}/utils.c
|
||||
${CC} -c ${CFLAGS} ${SRC}/utils.c -o ${BUILD}/utils.o
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm build/* bin/*
|
16
jacobi.conf
Normal file
16
jacobi.conf
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Configuration file for the Jacobi project.
|
||||
|
||||
# The size of the matrix (borders excluded).
|
||||
N 5
|
||||
|
||||
# The value at each border.
|
||||
NORTH 0.0
|
||||
EAST 0.0
|
||||
SOUTH 300.0
|
||||
WEST 0.0
|
||||
|
||||
# The initial value to assign at each internal cell.
|
||||
INIT_VALUE 0.0
|
||||
|
||||
# The threshold that determines the convergence.
|
||||
THRESHOLD 1.0
|
58
src/config.c
Normal file
58
src/config.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct configuration {
|
||||
int n;
|
||||
double north;
|
||||
double east;
|
||||
double south;
|
||||
double west;
|
||||
double init_value;
|
||||
double threshold;
|
||||
} configuration;
|
||||
|
||||
int load_config(configuration *config) {
|
||||
char property[100];
|
||||
char *value;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen("jacobi.conf", "r");
|
||||
if (fp == NULL) {
|
||||
perror("Error opening file jacobi.conf");
|
||||
return 1;
|
||||
}
|
||||
while (fgets(property, 100, fp) != NULL) {
|
||||
if (property[0] == '\n' || property[0] == '#') {
|
||||
/* Skip empty lines and comments */
|
||||
continue;
|
||||
}
|
||||
value = strchr(property, ' ');
|
||||
if (value == NULL) {
|
||||
fclose(fp);
|
||||
perror("Error reading file jacobi.conf");
|
||||
return 1;
|
||||
}
|
||||
value[0] = '\0';
|
||||
value += sizeof(char);
|
||||
value[strlen(value) - 1] = '\0';
|
||||
if (strcmp(property, "N") == 0) {
|
||||
sscanf(value, "%d", &(config->n));
|
||||
} else if (strcmp(property, "NORTH") == 0) {
|
||||
sscanf(value, "%lf", &(config->north));
|
||||
} else if (strcmp(property, "EAST") == 0) {
|
||||
sscanf(value, "%lf", &(config->east));
|
||||
} else if (strcmp(property, "SOUTH") == 0) {
|
||||
sscanf(value, "%lf", &(config->south));
|
||||
} else if (strcmp(property, "WEST") == 0) {
|
||||
sscanf(value, "%lf", &(config->west));
|
||||
} else if (strcmp(property, "INIT_VALUE") == 0) {
|
||||
sscanf(value, "%lf", &(config->init_value));
|
||||
} else if (strcmp(property, "THRESHOLD") == 0) {
|
||||
sscanf(value, "%lf", &(config->threshold));
|
||||
} else {
|
||||
printf("Unknown property %s\n", property);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
11
src/config.h
Normal file
11
src/config.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
typedef struct configuration {
|
||||
int n;
|
||||
double north;
|
||||
double east;
|
||||
double south;
|
||||
double west;
|
||||
double init_value;
|
||||
double threshold;
|
||||
} configuration;
|
||||
|
||||
int load_config(configuration *config);
|
116
src/impl/mpi_line.c
Normal file
116
src/impl/mpi_line.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* MPI version with the matrix subdivided by "lines".
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <mpi.h>
|
||||
#include "../config.h"
|
||||
#include "../utils.h"
|
||||
|
||||
#define TAG_BORDER 0
|
||||
#define TAG_MATRIX 1
|
||||
|
||||
double *compute_jacobi(int rank, int numprocs, int n, double init_value, double threshold, borders b, int *iterations) {
|
||||
double *complete_x;
|
||||
double *x;
|
||||
double max_diff, global_max_diff, new_x;
|
||||
int i, j;
|
||||
int nb = n + 2; // n plus the border
|
||||
int rows, rows_to_transmit;
|
||||
int receive_pos;
|
||||
MPI_Status status;
|
||||
|
||||
if (rank == 0) {
|
||||
rows = n - (n / numprocs) * (numprocs - 1);
|
||||
} else {
|
||||
rows = n / numprocs;
|
||||
}
|
||||
LOG(printf("[Process %d/%d] rows: %d\n", rank, numprocs, rows));
|
||||
/* LOG(printf("[Process %d/%d] initializing matrix\n", rank, numprocs)); */
|
||||
/* Initialize the matrix */
|
||||
x = create_sa_matrix(rows + 2, nb);
|
||||
for (i = 0; i < rows + 2; i++) {
|
||||
for (j = 1; j <= n; j++) {
|
||||
x[IDX(nb, i, j)] = init_value;
|
||||
}
|
||||
}
|
||||
/* Initialize boundary regions */
|
||||
for (i = 0; i < rows + 2; i++) {
|
||||
x[IDX(nb, i, 0)] = b.west;
|
||||
x[IDX(nb, i, n + 1)] = b.east;
|
||||
}
|
||||
if (rank == 0) {
|
||||
for (i = 1; i <= n + 1; i++) {
|
||||
x[IDX(nb, 0, i)] = b.north;
|
||||
}
|
||||
}
|
||||
if (rank == numprocs - 1){
|
||||
for (i = 1; i < n + 1; i++) {
|
||||
x[IDX(nb, rows + 1, i)] = b.south;
|
||||
}
|
||||
}
|
||||
/* LOG(printf("[Process %d/%d] matrix initialized\n", rank, numprocs)); */
|
||||
/* Iterative refinement of x until values converge */
|
||||
*iterations = 0;
|
||||
do {
|
||||
max_diff = 0;
|
||||
global_max_diff = 0;
|
||||
for (i = 1; i <= rows; i++) {
|
||||
for (j = 1; j <= n; j++) {
|
||||
new_x = 0.25 * (x[IDX(nb, i - 1, j)] + x[IDX(nb, i, j + 1)] + x[IDX(nb, i + 1, j)] + x[IDX(nb, i, j - 1)]);
|
||||
max_diff = (double) fmax(max_diff, fabs(new_x - x[IDX(nb, i, j)]));
|
||||
x[IDX(nb, i, j)] = new_x;
|
||||
}
|
||||
}
|
||||
if (rank % 2 == 0) {
|
||||
if (rank != numprocs - 1) {
|
||||
// Send and receive south border
|
||||
MPI_Send(&x[IDX(nb, rows, 0)], nb, MPI_DOUBLE, rank + 1, TAG_BORDER, MPI_COMM_WORLD);
|
||||
MPI_Recv(&x[IDX(nb, rows + 1, 0)], nb, MPI_DOUBLE, rank + 1, TAG_BORDER, MPI_COMM_WORLD, &status);
|
||||
}
|
||||
if (rank != 0) {
|
||||
// Send and receive north border
|
||||
MPI_Send(&x[IDX(nb, 1, 0)], nb, MPI_DOUBLE, rank - 1, TAG_BORDER, MPI_COMM_WORLD);
|
||||
MPI_Recv(&x[IDX(nb, 0, 0)], nb, MPI_DOUBLE, rank - 1, TAG_BORDER, MPI_COMM_WORLD, &status);
|
||||
}
|
||||
} else {
|
||||
// Receive and send north border
|
||||
MPI_Recv(&x[IDX(nb, 0, 0)], nb, MPI_DOUBLE, rank - 1, TAG_BORDER, MPI_COMM_WORLD, &status);
|
||||
MPI_Send(&x[IDX(nb, 1, 0)], nb, MPI_DOUBLE, rank - 1, TAG_BORDER, MPI_COMM_WORLD);
|
||||
if (rank != numprocs - 1) {
|
||||
// Receive and send south border
|
||||
MPI_Recv(&x[IDX(nb, rows + 1, 0)], nb, MPI_DOUBLE, rank + 1, TAG_BORDER, MPI_COMM_WORLD, &status);
|
||||
MPI_Send(&x[IDX(nb, rows, 0)], nb, MPI_DOUBLE, rank + 1, TAG_BORDER, MPI_COMM_WORLD);
|
||||
}
|
||||
}
|
||||
/* LOG(printf("[Process %d/%d] max_diff: %f\n", rank, numprocs, max_diff)); */
|
||||
MPI_Allreduce(&max_diff, &global_max_diff, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
|
||||
/* LOG(printf("[Process %d/%d] global_max_diff: %f\n", rank, numprocs, global_max_diff)); */
|
||||
(*iterations)++;
|
||||
} while (global_max_diff > threshold);
|
||||
|
||||
if (rank == 0) {
|
||||
complete_x = create_sa_matrix(nb, nb);
|
||||
memcpy(complete_x, x, (rows + ((rank == numprocs - 1) ? 2 : 1)) * (nb) * sizeof(double));
|
||||
rows_to_transmit = n / numprocs;
|
||||
receive_pos = rows + 1;
|
||||
for (i = 1; i < numprocs; i++) {
|
||||
if (i == numprocs - 1) {
|
||||
rows_to_transmit++;
|
||||
}
|
||||
MPI_Recv(&complete_x[IDX(nb, receive_pos, 0)], rows_to_transmit * (nb), MPI_DOUBLE, i, TAG_MATRIX, MPI_COMM_WORLD, &status);
|
||||
receive_pos += n / numprocs;
|
||||
}
|
||||
} else {
|
||||
complete_x = NULL;
|
||||
rows_to_transmit = rows;
|
||||
if (rank == numprocs - 1) {
|
||||
rows_to_transmit++;
|
||||
}
|
||||
MPI_Send(&x[IDX(nb, 1, 0)], rows_to_transmit * (nb), MPI_DOUBLE, 0, TAG_MATRIX, MPI_COMM_WORLD);
|
||||
}
|
||||
|
||||
return complete_x;
|
||||
}
|
50
src/impl/sequential.c
Normal file
50
src/impl/sequential.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Sequential version.
|
||||
* No paralleliization used.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <mpi.h>
|
||||
#include "../config.h"
|
||||
#include "../utils.h"
|
||||
|
||||
double *compute_jacobi(int rank, int numprocs, int n, double init_value, double threshold, borders b, int *iterations) {
|
||||
double *x;
|
||||
double max_diff, new_x;
|
||||
int i, j;
|
||||
int nb = n + 2; // n plus the border
|
||||
|
||||
if (numprocs != 1) {
|
||||
MPI_Abort(MPI_COMM_WORLD, 1);
|
||||
}
|
||||
|
||||
/* Initialize boundary regions */
|
||||
x = create_sa_matrix(n + 2, n + 2);
|
||||
for (i = 1; i <= n; i++) {
|
||||
x[IDX(nb, 0, i)] = b.north;
|
||||
x[IDX(nb, n + 1, i)] = b.south;
|
||||
x[IDX(nb, i, 0)] = b.west;
|
||||
x[IDX(nb, i, n + 1)] = b.east;
|
||||
}
|
||||
/* Initialize the rest of the matrix */
|
||||
for (i = 1; i <= n; i++) {
|
||||
for (j = 1; j <= n; j++) {
|
||||
x[IDX(nb, i, j)] = init_value;
|
||||
}
|
||||
}
|
||||
/* Iterative refinement of x until values converge */
|
||||
*iterations = 0;
|
||||
do {
|
||||
max_diff = 0;
|
||||
for (i = 1; i <= n; i++) {
|
||||
for (j = 1; j <= n; j++) {
|
||||
new_x = 0.25 * (x[IDX(nb, i - 1, j)] + x[IDX(nb, i, j + 1)] + x[IDX(nb, i + 1, j)] + x[IDX(nb, i, j - 1)]);
|
||||
max_diff = (double) fmax(max_diff, fabs(new_x - x[IDX(nb, i, j)]));
|
||||
x[IDX(nb, i, j)] = new_x;
|
||||
}
|
||||
}
|
||||
(*iterations)++;
|
||||
} while (max_diff > threshold);
|
||||
return x;
|
||||
}
|
1
src/jacobi.h
Normal file
1
src/jacobi.h
Normal file
|
@ -0,0 +1 @@
|
|||
double *compute_jacobi(int rank, int numprocs, int n, double init_value, double threshold, borders b, int *iterations);
|
76
src/main.c
Normal file
76
src/main.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* MPI version with the matrix subdivided by "lines".
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <mpi.h>
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
#include "jacobi.h"
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int rank;
|
||||
int numprocs;
|
||||
int n;
|
||||
double init_value, threshold;
|
||||
double north, south, east, west;
|
||||
borders b;
|
||||
int config_loaded;
|
||||
configuration config;
|
||||
double *x;
|
||||
double startwtime = 0.0, endwtime;
|
||||
int iterations;
|
||||
|
||||
MPI_Init(&argc, &argv);
|
||||
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
|
||||
|
||||
if (rank == 0) {
|
||||
config_loaded = load_config(&config);
|
||||
if (config_loaded != 0) {
|
||||
MPI_Abort(MPI_COMM_WORLD, 1);
|
||||
}
|
||||
n = config.n;
|
||||
threshold = config.threshold;
|
||||
init_value = config.init_value;
|
||||
north = config.north;
|
||||
south = config.south;
|
||||
east = config.east;
|
||||
west = config.west;
|
||||
}
|
||||
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
|
||||
MPI_Bcast(&init_value, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
|
||||
MPI_Bcast(&threshold, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
|
||||
MPI_Bcast(&north, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
|
||||
MPI_Bcast(&south, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
|
||||
MPI_Bcast(&east, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
|
||||
MPI_Bcast(&west, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
|
||||
|
||||
b.north = north;
|
||||
b.south = south;
|
||||
b.east = east;
|
||||
b.west = west;
|
||||
|
||||
if (rank == 0) {
|
||||
startwtime = MPI_Wtime();
|
||||
}
|
||||
|
||||
x = compute_jacobi(rank, numprocs, n, init_value, threshold, b, &iterations);
|
||||
|
||||
if (rank == 0) {
|
||||
endwtime = MPI_Wtime();
|
||||
printf("Wall clock time: %fs\n", endwtime - startwtime);
|
||||
printf("Iterations: %d\n", iterations);
|
||||
print_sa_matrix(x, n + 2, n + 2);
|
||||
}
|
||||
|
||||
destroy_sa_matrix(x);
|
||||
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
56
src/utils.c
Normal file
56
src/utils.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "utils.h"
|
||||
|
||||
double *create_sa_matrix(int rows, int cols) {
|
||||
double *x;
|
||||
|
||||
x = (double *) malloc(rows * cols * sizeof(double));
|
||||
return x;
|
||||
}
|
||||
|
||||
void destroy_sa_matrix(double *x) {
|
||||
free(x);
|
||||
}
|
||||
|
||||
void print_sa_matrix(double *x, int rows, int cols) {
|
||||
int i, j;
|
||||
for (i = 0; i < rows; i++) {
|
||||
for (j = 0; j < cols; j++) {
|
||||
printf("%f\t", x[IDX(cols, i, j)]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
double **create_matrix(int rows, int cols) {
|
||||
int i;
|
||||
double **x;
|
||||
|
||||
x = (double **) malloc(rows * sizeof(double));
|
||||
for (i = 0; i < rows; i++) {
|
||||
x[i] = (double *) malloc(cols * sizeof(double));
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
void destroy_matrix(double **x, int rows) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rows; i++) {
|
||||
free(x[i]);
|
||||
}
|
||||
free(x);
|
||||
}
|
||||
|
||||
void print_matrix(double **x, int rows, int cols) {
|
||||
int i, j;
|
||||
for (i = 0; i < rows; i++) {
|
||||
for (j = 0; j < cols; j++) {
|
||||
printf("%f\t", x[i][j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
46
src/utils.h
Normal file
46
src/utils.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* #define ENABLE_LOG */
|
||||
|
||||
#ifdef ENABLE_LOG
|
||||
# define LOG(x) x
|
||||
#else
|
||||
# define LOG(x) (void) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Macro used with single array matrices to
|
||||
* get the array index given the number of columns,
|
||||
* the row index and the column index.
|
||||
*/
|
||||
#define IDX(cols, r, c) ((r) * (cols) + (c))
|
||||
|
||||
typedef struct borders {
|
||||
double north;
|
||||
double east;
|
||||
double south;
|
||||
double west;
|
||||
} borders;
|
||||
|
||||
|
||||
/*
|
||||
* Create a matrix stored in a single array.
|
||||
*/
|
||||
double *create_sa_matrix(int rows, int cols);
|
||||
|
||||
/*
|
||||
* Destroy a single array matrix.
|
||||
*/
|
||||
void destroy_sa_matrix(double *x);
|
||||
|
||||
int sa_index(int cols, int r, int c);
|
||||
|
||||
/*
|
||||
* Print a single array matrix.
|
||||
*/
|
||||
void print_sa_matrix(double *x, int rows, int cols);
|
||||
|
||||
double **create_matrix(int rows, int cols);
|
||||
void destroy_matrix(double **x, int rows);
|
||||
void print_matrix(double **x, int rows, int cols);
|
Loading…
Reference in New Issue
Block a user