Browse Source

First commit

printconf
Stephen Downward 7 months ago
parent
commit
cd6d6a8b29
9 changed files with 317 additions and 0 deletions
  1. +2
    -0
      Makefile
  2. +57
    -0
      ezpng.c
  3. +2
    -0
      ezpng.h
  4. +25
    -0
      main.c
  5. +91
    -0
      master.c
  6. +1
    -0
      master.h
  7. +119
    -0
      slave.c
  8. +1
    -0
      slave.h
  9. +19
    -0
      types.h

+ 2
- 0
Makefile View File

@@ -0,0 +1,2 @@
build: ezpng.c ezpng.h main.c master.c master.h types.h slave.h slave.c
mpicc ezpng.c main.c master.c slave.c -lpng -lm -o mandelbrot

+ 57
- 0
ezpng.c View File

@@ -0,0 +1,57 @@
#include <stdio.h>
#include <png.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "types.h"

void savePng(char *filename, int h, int w, Pixel *buf)
{
FILE *fp;
fp = fopen(filename, "wb");
if(!fp)
{
printf("ERROR: Could not save image!\r\n");
return;
}

png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(png_ptr);

png_set_IHDR (png_ptr,
info_ptr,
w, //image width
h, //height
8, //bit depth
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);

png_byte **row_pointers = png_malloc (png_ptr, h * sizeof (png_byte *));
for(int y = 0; y < h; y++)
{
png_byte *row = png_malloc (png_ptr, sizeof(uint8_t) * w * 3);
row_pointers[y] = row;
for(int x = 0; x < w; x++)
{
Pixel pixel = buf[x + w*y];
*row++ = pixel.red;
*row++ = pixel.green;
*row++ = pixel.blue;
}
}

png_init_io (png_ptr, fp);
png_set_rows (png_ptr, info_ptr, row_pointers);
png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

fclose(fp);
//Free memory
for(int y = 0; y < h; y++)
{
png_free(png_ptr, row_pointers[y]);
}
png_free(png_ptr, row_pointers);
}

+ 2
- 0
ezpng.h View File

@@ -0,0 +1,2 @@
#include "types.h"
void savePng(char *filename, int h, int w, Pixel *buf);

+ 25
- 0
main.c View File

@@ -0,0 +1,25 @@
#include<mpi.h>
#include<stdlib.h>
#include<stdio.h>
#include "master.h"
#include "slave.h"

int main(char argc, char **argv)
{
MPI_Init(NULL, NULL);

int worldSize, worldRank;
MPI_Comm_size(MPI_COMM_WORLD, &worldSize);
MPI_Comm_rank(MPI_COMM_WORLD, &worldRank);

if(worldSize == 1)
{
printf("ERROR: You need at least 1 slave!");
return 1;
}

worldRank == 0 ? master_main(argc, argv, worldSize) : slave_main(worldSize, worldRank);

MPI_Finalize();
return 0;
}

+ 91
- 0
master.c View File

@@ -0,0 +1,91 @@
#include<mpi.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
#include "types.h"
#include "ezpng.h"

void master_main(char argc, char **argv, int numSlaves)
{
printf("\t\tMPI Mandelbrot Generator\r\n");
printf("\t\t\twww.scd31.com\r\n");

Config conf;
conf.w = 44000;
conf.h = 44000;
conf.batch = 2342;

long curPixel = 0;

Pixel *buffer = malloc(sizeof(Pixel) * conf.w * conf.h);

//Send config to slaves
for(int i = 1; i < numSlaves; i++)
{
MPI_Send(&conf, sizeof(conf), MPI_BYTE, i, 0, MPI_COMM_WORLD);
}

int lastCheckpoint = 0;
int busy[numSlaves]; //Holds id of pixel being worked on
Pixel tmpBufs[numSlaves][conf.batch];
MPI_Request reqs[numSlaves];
memset(busy, 0, sizeof(int) * numSlaves);
bool done = false;
while(!done)
{
done = curPixel >= conf.w * conf.h;
if(lastCheckpoint < curPixel - (conf.w * conf.h / 100.0))
{
//1%
int percent = (double)curPixel / conf.w / conf.h * 100;
printf("%d %\r\n", percent);
lastCheckpoint = curPixel;
}

for(int i = 1; i < numSlaves; i++)
{
if(busy[i]) done = false;
//Find slaves that are not busy, and send them stuff to do
if(!busy[i] && curPixel < conf.w * conf.h)
{
long amtToSend = MIN(conf.batch, ((long)conf.w * conf.h) - curPixel);
MPI_Send(&curPixel, 1, MPI_LONG, i, 1, MPI_COMM_WORLD);
MPI_Send(buffer + curPixel, amtToSend * sizeof(Pixel),
MPI_BYTE, i, 0, MPI_COMM_WORLD);
//Start recv
MPI_Irecv(tmpBufs[i], amtToSend * sizeof(Pixel), MPI_BYTE,
i, 0, MPI_COMM_WORLD, &reqs[i]);
busy[i] = curPixel;
curPixel += conf.batch; //{batch} pixels at a time

}
else if(reqs[i] != 0)
{
//Try to recv data from the slaves
int amtToRecv = MIN(conf.batch, ((long)conf.w * conf.h) - busy[i]);
int flag = 0;
MPI_Test(&reqs[i], &flag, MPI_STATUS_IGNORE);
if(flag != 0)
{
//printf("%d, %d\r\n", amtToRecv, i);
//Buf is valid
memcpy(buffer + busy[i], tmpBufs[i], sizeof(Pixel) * amtToRecv);
busy[i] = 0;
reqs[i] = 0;
}
}
}
}
//Send all of the threads a curPixel of -1
//This tells them to stop
for(int i = 1; i < numSlaves; i++)
{
long curPixel = -1;
MPI_Send(&curPixel, 1, MPI_LONG, i, 1, MPI_COMM_WORLD);
}
savePng("current.png", conf.h, conf.w, buffer);
free(buffer);
printf("Done!\r\n");
}

+ 1
- 0
master.h View File

@@ -0,0 +1 @@
void master_main(char argc, char **argv, int numSlaves);

+ 119
- 0
slave.c View File

@@ -0,0 +1,119 @@
#include<stdio.h>
#include<stdlib.h>
#include<mpi.h>
#include<math.h>
#include "types.h"

double map(double x, double in_min, double in_max, double out_min, double out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

Pixel hsl_to_rgb(int h, double s, double l)
{
if(h == 360) h = 0;
if(s > 1) s = 1;
if(l > 1) l = 1;
double c = (1 - abs(2 * l - 1)) * s;
double x = c * (1 - fabs(fmod(((double)h)/60, 2) - 1));
double m = l - c / 2;
double r, g, b;
int q = h / 60;
switch(q)
{
case(0):
r = c;
g = x;
b = 0;
break;
case(1):
r = x;
g = c;
b = 0;
break;
case(2):
r = 0;
g = c;
b = x;
break;
case(3):
r = 0;
g = x;
b = c;
break;
case(4):
r = x;
g = 0;
b = c;
break;
case(5):
r = c;
g = 0;
b = x;
}
Pixel out;
out.red = 255 * (r + m);
out.green = 255 * (g + m);
out.blue = 255 * (b + m);
return out;
}

Pixel mandelbrot(int pixId, int w, int h)
{
int x = pixId % w;
int y = pixId / w;

double center[] = {-1.48493111, -0.000007277489};
double range = 1.2446E1;
double bounds[] = {center[0] - range, center[1] - range,
center[0] + range, center[1] + range};

double Creal = map(x, 0, w, bounds[0], bounds[2]);
double Cimaginary = map(y, 0, h, bounds[1], bounds[3]);

double real = 0;
double imaginary = 0;
for(int i = 0; i < 20000; i++)
{
double realTmp = real;
real = real*real - imaginary*imaginary + Creal;
imaginary = realTmp * 2 * imaginary + Cimaginary;
if(imaginary * imaginary + real * real > 2 ||
imaginary * imaginary + real * real < -2)
{
return hsl_to_rgb(i, 1, 0.5);
}
}
return (Pixel){.red=0, .green=0, .blue=0};
}

void slave_main(int slaveCount, int id)
{
Config conf;
MPI_Recv(&conf, sizeof(conf), MPI_BYTE, 0, 0,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);

Pixel *buf = malloc(sizeof(Pixel) * conf.batch);
while(1)
{
long curPixel;
MPI_Recv(&curPixel, 1, MPI_LONG, 0, 1,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
if(curPixel == -1) break;
int amtToSend = MIN(conf.batch, ((long)conf.w * conf.h) - curPixel);
MPI_Recv(buf, sizeof(Pixel) * amtToSend, MPI_BYTE, 0, 0,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);

//Processing
for(int i = 0; i < amtToSend; i++)
{
buf[i] = mandelbrot(curPixel + i, conf.w, conf.h);
}

MPI_Send(buf, sizeof(Pixel) * amtToSend, MPI_BYTE, 0, 0,
MPI_COMM_WORLD);
}
free(buf);
}

+ 1
- 0
slave.h View File

@@ -0,0 +1 @@
void slave_main(int slaveCount, int id);

+ 19
- 0
types.h View File

@@ -0,0 +1,19 @@
#ifndef TYPES_H
#define TYPES_H

#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))

typedef struct
{
char red;
char green;
char blue;
} Pixel;

typedef struct
{
int w, h;
int batch;
} Config;

#endif

Loading…
Cancel
Save