The following is a scrambled message:
Zpv!uijol!zpvs!qbjo!boe!zpvs!ifbsucsfbl!bsf!voqsfdfefoufe!jo!uif!ijtupsz!pg!uif!xpsme-!cvu!uifo!zpv!sfbe/
This code was used for encryption:
#include <cstdio> // Import the printf function
#include "omp.h" // Import the OpenMP library functions
// Start of program
int main()
{
// This is a "character array", consisting of 105 letters in byte form.
char mymessage[] = "This is a placeholder of the original message";
// The message is encoded by shifting all letters by one, i.e.
// A becomes B, c becomes d and so forth. This shift is easy to implement
// in byte form as all you need to do is to add 1 to a character.
// To printf a single character, use e.g.
// printf("%c\n", mymessage[0]);
// To printf the whole array do e.g. (subtle difference between %c and %s)
// printf("%s\n", mymessage);
/* MISSING CODE: for loop over the 105 characters and adding the value 1 to each entry; */
printf("%s\n", mymessage); // This prints a character array to screen
return 0; // Exit program
}
Hint:
Use suitable pragmas and run the decryption thread-parallel.
Insert a statement in the for-loop that prints the current thread number and decryption result.
Run the code repeatedly and vary the number of threads (OMP_NUM_THREADS). What do you observe?
In the blackboard folder “OpenMP training material” you will find two encrypted images (PGM type) as well as the file “CImg.h”. You need to download those to the machine you are working on. See below for a brief explanation of CImg and PGM.
PGM Images in Portable Gray Map (PGM) format store a single grayscale value between 0 and 255 in each pixel.
CImg CImg is a lightweight, header-only, image library for C/C++. Among other things it allows to read, manipulate and write images. Once loaded, the individual pixels of an image can be accessed using the pixel coordinates \(0\leq x\lt w\) and \(0\leq y\lt h\), where \(w\) and \(h\) are image width and height, respectively. CImg is available here: https://cimg.eu/
The following code has been used for encryption:
#define cimg_display 0 // This gets around the need to link to X11
#include "CImg.h" // import the image library
#include <cstdio> // import printf
using namespace cimg_library; // this just saves a lot of typing, e.g.
// it allows to just state CImg instead of
// cimg_library::CImg
int main(int argc, char * argv[]) // The main function this time knows about
{ // command line arguments
// Load image.
CImg<float> img = CImg<float>(argv[1]); // the first argument on the command
// line is the image, e.g.
// ./a.out image.pgm
const int w = img.width(); // the width of the image in number of pixels
const int h = img.height(); // the height of the image in number of pixels
// To access the colour value of a single pixel of the image, you can
// do:
// float data = img(x,y);
//
// x can be any integer with 0 <= x < w
// y can be any integer with 0 <= y <h
// Encode
for (int r=0;r<300;r++) // The encoding is done 300 times
{
for (int y=0;y<h;y++) // this loop iterates along the y-direction
{
for (int x=0;x<w;x++) // this loops iterates along the x-direction
{
// We swap the colour values of two pixels:
// 1. store the value at coordinates [(x+r+y)%w , y ] in a temporary variable 'buf'
float buf = img( (x+r+y)%w, y); // (x+r+y)%w ensures that the first coordinate is < w
// 2. replace the colour values at [(x+r+y)%w , y] with that of [x,y]
img( (x+r+y)%w, y) = img(x, y);
// 3. replace the colour value at [x,y] with that of the original value at [(x+r+y)%w]
img(x , y) = buf;
}
}
}
// Write encoded image
img.save("encoded.pgm");
return 0;
}
Hints:
You need these commands on hamilton to compile with g++:
module load gcc/9.3.0
g++ decoder.cxx -I . -lpthread -fopenmp -o decoder
./decoder encoded.pgm
Hint:
Hint:
You can use omp_get_wtime() that comes with OpenMP for measurements.
Use OMP_NUM_THREADS to set the number of threads
Suggestion: put all commands into a slurm submission script, e.g.
#SBATCH ...
...
OMP_NUM_THREADS=1 ./decoder image.pgm
OMP_NUM_THREADS=2 ./decoder image.pgm
OMP_NUM_THREADS=4 ./decoder image.pgm
...
The task is to sum all numbers between 1 and \(10^9\) in parallel. We can cross-check our result using the relation \(\sum\limits_{i=1}^N = \frac{N\cdot(N+1)}{2}\)
#include <cstdio>
#include "omp.h"
int main()
{
unsigned long N = 1000000000;
unsigned long SUMS[4] = {0,0,0,0};
#pragma omp parallel for
for (unsigned long i=1;i<N+1;i++)
{
SUMS[omp_get_thread_num()]+=i;
}
unsigned long result = SUMS[0] + SUMS[1] + SUMS[2] + SUMS[3];
printf("Result: %lu\n", result);
return 0;
}