Changed project structure

This commit is contained in:
Fabio Salvini 2016-11-19 14:04:05 +01:00
parent c59f5a4b9b
commit 9256e535ff
11 changed files with 457 additions and 1 deletions

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);