Skip to content

Commit

Permalink
Add assignment 10
Browse files Browse the repository at this point in the history
  • Loading branch information
Philipp Gschwandtner committed May 20, 2024
1 parent 176a787 commit 8b4841b
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 0 deletions.
45 changes: 45 additions & 0 deletions 10/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Assignment 10

The goal of this task is to practice using OpenMP tasks and take a first look at the heat stencil application.

## Exercise 1 (1 Point)

### Description

This exercise consists of implementing a program that calculates Delannoy numbers with OpenMP tasks.

A Delannoy number specifies the number of paths from the south-west corner of a 2D grid to the north-east corner, using only the per-step directions north, north-east, and east. See https://en.wikipedia.org/wiki/Delannoy_number for more information and a visualization.

### Tasks

- Implement a sequential program that computes the Delannoy number for a square 2D grid of size NxN where N is an input parameter for your program. If in doubt, base your implementation on the formula given in the Wikipedia article under "basic recurrence relation". Make sure your program is semantically correct by comparing the result against the Delannoy numbers given in the article.
- Parallelize your program using OpenMP tasks and benchmark both the sequential and parallel implementation for several N between 3 and ~15. What can you observe?
- What is the main bottleneck of your parallel implementation and how can it be improved without changing the underlying algorithm?
- Enter the wall clock time of the sequential version and the parallel version for 1 and 12 threads for N=12 on LCC3 to the comparison spreadsheet linked on Discord.

## Exercise 2 (2 Points)

### Description

This exercise consists of implementing a 2-dimensional heat stencil application.

A large class of scientific applications are so-called stencil or structured grid applications. These simulate time-dependent physical processes such as the propagation of heat or pressure in a given medium. The core of the simulation operates on a grid and updates each cell with information from its neighbor cells.

<img alt="heat_stencil" src="https://upload.wikimedia.org/wikipedia/commons/e/ec/2D_von_Neumann_Stencil.svg" width="40%">

### Tasks

- Given the code in [heat_stencil_2D.c](heat_stencil_2D.c), finish the implementation:
- implement the heat propagation by updating each cell with information from its neighbors. If in doubt, you can start with the formula given in https://en.wikipedia.org/wiki/Finite_difference_method#Example:_The_Laplace_operator
- make sure the heat source stays the same through all iterations
- if computing the value at the boundary, use temperature at the center position as the next value (e.g if you want to calculate A[0,1], use A[0,1] as the left neighbor cell instead of the non-existent A[-1,1])
- The simple verification at the end should pass
- Parallelize the implementation using OpenMP. Investigate the use of the `collapse` clause and explain its purpose and effects.
- Measure the time, speedup and efficiency of the stencil codes for varying problem sizes and numbers of threads.
- Enter the wall clock time of the sequential version and the parallel version for 1 and 12 threads for 500x500 on LCC3 to the comparison spreadsheet linked on Discord.

## General Notes

All the material required by the tasks above (e.g., code, figures, text, etc...) must be part of the solution that is handed in. Your experiments should be reproducible and comparable to your measurements using the solution materials that you hand in.

**Every** member of your group must be able to explain the given problem, your solution, and possible findings. You may also need to answer detailed questions about any of these aspects.
158 changes: 158 additions & 0 deletions 10/heat_stencil_2D.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <omp.h>
#include <string.h>

#define RESOLUTION_WIDTH 50
#define RESOLUTION_HEIGHT 50

#define PERROR fprintf(stderr, "%s:%d: error: %s\n", __FILE__, __LINE__, strerror(errno))
#define PERROR_GOTO(label) \
do { \
PERROR; \
goto label; \
} while (0)


// -- vector utilities --

#define IND(y, x) ((y) * (N) + (x))

void printTemperature(double *m, int N, int M);

// -- simulation code ---

int main(int argc, char **argv) {
// 'parsing' optional input parameter = problem size
int N = 200;
if (argc > 1) {
N = atoi(argv[1]);
}
int T = N * 10;
printf("Computing heat-distribution for room size %dX%d for T=%d timesteps\n", N, N, T);

// ---------- setup ----------

// create a buffer for storing temperature fields
double *A = malloc(sizeof(double) * N * N);

if(!A) PERROR_GOTO(error_a);

// set up initial conditions in A
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
A[IND(i,j)] = 273; // temperature is 0° C everywhere (273 K)
}
}

// and there is a heat source
int source_x = N / 4;
int source_y = N / 4;
A[IND(source_x,source_y)] = 273 + 60;

printf("Initial:");
printTemperature(A, N, N);
printf("\n");

// ---------- compute ----------

// create a second buffer for the computation
double *B = malloc(sizeof(double) * N * N);
if(!B) PERROR_GOTO(error_b);
// for each time step ..
for (int t = 0; t < T; t++) {
// todo implement heat propagation
// todo make sure the heat source stays the same

// every 1000 steps show intermediate step
if (!(t % 1000)) {
printf("Step t=%d\n", t);
printTemperature(A, N, N);
printf("\n");
}
}


// ---------- check ----------

printf("Final:");
printTemperature(A, N, N);
printf("\n");

// simple verification if nowhere the heat is more then the heat source
int success = 1;
for (long long i = 0; i < N; i++) {
for (long long j = 0; j < N; j++) {
double temp = A[IND(i,j)];
if (273 <= temp && temp <= 273 + 60)
continue;
success = 0;
break;
}
}

printf("Verification: %s\n", (success) ? "OK" : "FAILED");

// todo ---------- cleanup ----------
error_b:
free(B);
error_a:
free(A);
return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
}

void printTemperature(double *m, int N, int M) {
const char *colors = " .-:=+*^X#%@";
const int numColors = 12;

// boundaries for temperature (for simplicity hard-coded)
const double max = 273 + 30;
const double min = 273 + 0;

// set the 'render' resolution
int W = RESOLUTION_WIDTH;
int H = RESOLUTION_HEIGHT;

// step size in each dimension
int sW = N / W;
int sH = M / H;

// upper wall
printf("\t");
for (int u = 0; u < W + 2; u++) {
printf("X");
}
printf("\n");
// room
for (int i = 0; i < H; i++) {
// left wall
printf("\tX");
// actual room
for (int j = 0; j < W; j++) {
// get max temperature in this tile
double max_t = 0;
for (int x = sH * i; x < sH * i + sH; x++) {
for (int y = sW * j; y < sW * j + sW; y++) {
max_t = (max_t < m[IND(x,y)]) ? m[IND(x,y)] : max_t;
}
}
double temp = max_t;

// pick the 'color'
int c = ((temp - min) / (max - min)) * numColors;
c = (c >= numColors) ? numColors - 1 : ((c < 0) ? 0 : c);

// print the average temperature
printf("%c", colors[c]);
}
// right wall
printf("X\n");
}
// lower wall
printf("\t");
for (int l = 0; l < W + 2; l++) {
printf("X");
}
printf("\n");
}
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ for that assignment have to be handed in via OLAT by 17:00 on the previous day
| 2024-05-07 | [7](07) | OpenMP correctness, auto-vectorization, dependence analysis |
| 2024-05-14 | [8](08) | OpenMP affinity and loop scheduling |
| 2024-05-21 | [9](09) | Vectorization |
| 2024-05-28 | [10](10) | OpenMP task parallelism, heat stencil |

## General Information

Expand Down

0 comments on commit 8b4841b

Please sign in to comment.