Demo entry 6311777

C

   

Submitted by anonymous on Oct 25, 2016 at 00:18
Language: C. Code size: 4.8 kB.

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lodepng.h"
#include <math.h>
#define TAG 0

/*
* Method that actually performs rectification. Goes through each pixel and checks if it's
* less than 127 and sets pixel accordingly
*/
void rec(int pixel, int address, unsigned char * new_image)
{
	if (pixel < 127)
	{
		new_image[address] = 127;
	}
	else
	{
		new_image[address] = pixel;
	}
}

/*
* Method that splits up input image into segments and distributes them to
* different processes. Will also join up all the results for the final
* output image.
*/
void process(char* input_filename, char* output_filename)
{
	// Variables needed to load in image file
	unsigned error;
	unsigned char *image, *block; 
	unsigned width, height;

	error = lodepng_decode32_file(&image, &width, &height, input_filename);
	if (error)
		printf("error %u: %s\n", error, lodepng_error_text(error));

	unsigned char value;
	int xyz = 123; // Used for extra expensive computations to see real impact of speedup of multiple processes

	// Start to create processes at this point
	MPI_Init(NULL, NULL);

	int size;

    // Get the number of processesu
    MPI_Comm_size(MPI_COMM_WORLD, &size);

	// Calculate the rows we can assign to each processor
	int set_size = height/size; 

	// If the number of rows is not equal when splitting, make the last process do more work
	int left_over = height%size; 
	int special = 0;
	if (left_over > 0)
	{
		special = left_over;
	}

    // Get the rank of the process
    int rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    
    // Need to keep track of where we are in the actual picture
    int position_in_global = rank * set_size;

    // If the rows cannot be distributed evently to all processors, make the last process do more work
    if (rank == (size-1) && special)
	{
		set_size += left_over;	
	}
	
	// Create rows to send to each processor
	block = malloc(width * set_size * 4 * sizeof(unsigned char));

	// Each process will go through their segments of the original image to rectify
	// then it will send back the rectified segment to process 0 (main process)
	for (int i = 0; i < set_size ; i++)
	{
		for (int j = 0; j < width; j++)
		{
			int offset_in_image = 4 * width * (position_in_global+i) + 4 * j;
			int offset= 4 * width * i + 4 * j;
			int r = image[offset_in_image]; // R
			rec(r, (offset), block);
			int g = image[offset_in_image + 1]; // G

			rec(g, offset + 1, block);
			int b = image[offset_in_image + 2]; // B
			rec(b, offset + 2, block);
			int a = image[offset_in_image + 3]; // A
			block[offset + 3] = a;
			
			// Extra computation just to see that parallelism does improve runtime of the program
			// Has no impact on the output image.
			xyz *= pow(sin(i + xyz), cos(xyz + j));
			xyz *= pow(sin(i + xyz), cos(xyz + j));
			xyz *= pow(sin(i + xyz), cos(xyz + j));
			xyz *= pow(sin(i + xyz), cos(xyz + j));
			xyz *= pow(sin(i + xyz), cos(xyz + j));

		}

	}
	
	// Send & recieve all the results
	 int val = 0;
	 // Main process (process 0) will do all the joining in the end of results from other
	 // So it needs to call MPI_Recv to get incoming results of other processes
	 if (rank == 0) 
	 {
		char *new_image = malloc(width * height * 4 * sizeof(unsigned char));
		int blk_size = (set_size*width * 4 * sizeof(unsigned char));
		// Process 0 also does some work in rectifying image so it needs to put its result in the
		// output image
	    memcpy(new_image,block,blk_size);
		for (int var = 1; var < size; ++var) 
		{
			int start = (blk_size*var);
			if (var == (size-1) && special)
			{
				set_size += left_over;	
				blk_size=(set_size*width*4 * sizeof(unsigned char));
			}
			char* blk = malloc(blk_size);
			// Waiting for result of other processes. Use a blocking receive so we don't need to 
			// re-order the segments of each process that we receive.
			// This is like a barrier.
			MPI_Recv(blk, blk_size, MPI_CHAR, var, TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
			// Add each process' results into the output image
			memcpy(new_image+start,blk,blk_size);
			free(blk);
		}
		lodepng_encode32_file(output_filename, new_image, width, height);
		free(new_image);
    }
	else {
		MPI_Request request;
		int blk_size=(set_size*width*4 * sizeof(unsigned char));
		// Use a blocking send so we don't need to re-order the segments 
		// of each process in the output image
		MPI_Isend(block, blk_size, MPI_CHAR, 0, TAG, MPI_COMM_WORLD, &request);
	}
	
	MPI_Finalize();
	free(image);
}

int main(int argc, char *argv[])
{
	char* input_filename = argv[1];
	char* output_filename = argv[2];

	process(input_filename, output_filename);

	return 0;
}

This snippet took 0.01 seconds to highlight.

Back to the Entry List or Home.

Delete this entry (admin only).