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:
|
||||
|
||||
|
|
|
@ -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/*
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
double *compute_jacobi(int rank, int numprocs, int n, double init_value, double threshold, borders b, int *iterations);
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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