multithreaded mandelbrot fun

master
Anton Lydike 5 years ago
parent f9b559f3a0
commit a29f32a303

3
.gitignore vendored

@ -1,4 +1,5 @@
*.out *.out
*.o *.o
*.bmp *.png
*.bmp

@ -1,32 +1,33 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <limits.h>
#include "images.h" #include "images.h"
// write an int to a byte array // write an int to a byte array
void bmp__write_int(unsigned char* bytes, int num) { void bmp__write_int(FILE *fp, int num) {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
bytes[i] = num >> (i * 8); putc(num >> (i * 8), fp);
} }
} }
void bmp__write_16bit(unsigned char* bytes, int num) { void bmp__write_16bit(FILE *fp, int num) {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
bytes[i] = num >> (i * 8); putc(num >> (i * 8), fp);
} }
} }
int bmp__align_to_four_bytes(int row_length) { unsigned long int bmp__align_to_four_bytes(unsigned long int row_length) {
int os =row_length % 4; unsigned long int os =row_length % 4;
return os == 0 ?row_length : row_length + (4 - os); return os == 0 ?row_length : row_length + (4 - os);
} }
int bmp__image_byte_size(Image image) { unsigned long int bmp__image_byte_size(Image image) {
// calculate size: // calculate size:
// bitmap file header = 14 // bitmap file header = 14
// BITMAPCOREHEADER = 12 bytes // BITMAPCOREHEADER = 12 bytes
int size = 14 + 12; unsigned long int size = 14 + 12;
// width must be padded to align to 4 bytes // width must be padded to align to 4 bytes
int row_bytes = bmp__align_to_four_bytes(image.width * 3); // 3 bytes per pixel unsigned long int row_bytes = bmp__align_to_four_bytes(image.width * 3); // 3 bytes per pixel
// add row_bytes * height to total size // add row_bytes * height to total size
size += row_bytes * image.height; size += row_bytes * image.height;
@ -53,43 +54,46 @@ int bmp__image_byte_size(Image image) {
// bytes[2] => wert an offset 2 (ist char) // bytes[2] => wert an offset 2 (ist char)
int image_save_bmp(Image image, const char* path) { int image_save_bmp(Image image, const char* path) {
int size = bmp__image_byte_size(image); unsigned long int size = bmp__image_byte_size(image);
unsigned char* bytes = calloc(sizeof(char), size); if ((unsigned long int) size > (unsigned long int) UINT_MAX) {
printf("bitmap is too big!\n");
return 0;
} else {
printf("predicted size is %lu out of %u possible", size, UINT_MAX);
}
FILE *fp = fopen(path, "w");
//unsigned char* bytes = calloc(sizeof(char), size);
// magic bytes, signature "BM" // magic bytes, signature "BM"
// bmp header: // bmp header:
bytes[0] = 'B'; fputs("BM", fp); // offset 0
bytes[1] = 'M';
// write size to header // write size to header
bmp__write_int(bytes + 2, size); bmp__write_int(fp, size); // offset 2
// the next 4 byte are zeros bmp__write_int(fp, 0); // offset 6 - the next 4 byte are zeros
// pixel array offset // pixel array offset
bmp__write_int(bytes + 10, 14 + 12); bmp__write_int(fp, 14 + 12); // offset 10
// DIB header: // DIB header:
bmp__write_int(bytes + 14, 12); // header size bmp__write_int(fp, 12); // header size
bmp__write_16bit(bytes + 18, image.width); // width bmp__write_16bit(fp, image.width); // width
bmp__write_16bit(bytes + 20, image.height); // height bmp__write_16bit(fp, image.height); // height
bmp__write_16bit(bytes + 22, 1); // color planes bmp__write_16bit(fp, 1); // color planes
bmp__write_16bit(bytes + 24, 3 * 8); // bits per pixel bmp__write_16bit(fp, 3 * 8); // bits per pixel
int byte_offset = 26; int line, px;
int byte_pos = 0;
int line;
for (line = 0; line < image.height; line++) { for (line = 0; line < image.height; line++) {
byte_pos = 0; for (px = 0; px < image.width * 3; px += 3) {
for (int px = 0; px < image.width * 3; px += 3) { putc(image.bitmap[line][px + 2], fp);
bytes[byte_offset + byte_pos++] = image.bitmap[line][px + 2]; putc(image.bitmap[line][px + 1], fp);
bytes[byte_offset + byte_pos++] = image.bitmap[line][px + 1]; putc(image.bitmap[line][px + 0], fp);
bytes[byte_offset + byte_pos++] = image.bitmap[line][px + 0]; }
int mod = px % 4;
if (mod != 0) {
for (int i = 0; i < 4-mod; i++) {
putc(0, fp);
}
} }
byte_offset += bmp__align_to_four_bytes(byte_pos);
} }
printf("generated %i bytes out of %i calculated ones\n", byte_offset, size); printf("wrote %li bytes...\n", size);
FILE *fp = fopen(path, "w");
int written = fwrite(bytes, sizeof(char), size, fp);
printf("wrote %i bytes...\n", written);
fclose(fp); fclose(fp);
free(bytes);
return 1; return 1;
} }

@ -1,5 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <limits.h>
#include "images.h" #include "images.h"
@ -11,6 +12,12 @@ int image_new(int width, int height, Image* img) {
img->height = height; img->height = height;
img->width = width; img->width = width;
// approximation
if ((unsigned long int) width * height * 3 > (unsigned long int) UINT_MAX) {
printf("Image dimensions to large for a bitmap!\n");
return 0;
}
// initialize bitmap... // initialize bitmap...
img->bitmap = malloc(height * sizeof(char*)); img->bitmap = malloc(height * sizeof(char*));
for (int i = 0; i < height; i++) { for (int i = 0; i < height; i++) {

@ -1,12 +1,22 @@
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include "images/images.h" #include "images/images.h"
#include "complex.c" #include "complex.c"
#define MB_THREADS 7
void draw_mandelbrot(int width, int height, int iterations); void draw_mandelbrot(int width, int height, int iterations);
void draw_mandelbrot_auto(int width, int iterations); void draw_mandelbrot_auto(int width, int iterations);
int test_mandelbrot(Complex c, int iterations); int test_mandelbrot(Complex c, int iterations);
void* create_shared_memory(size_t size);
int image_new_shared(int width, int height, Image* img);
void image_destroy_shared(Image img);
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
int width = 3000; int width = 3000;
@ -22,7 +32,7 @@ int main(int argc, char* argv[]) {
} }
void draw_mandelbrot_auto(int width, int iterations) { void draw_mandelbrot_auto(int width, int iterations) {
draw_mandelbrot(width, 2 * width / 3, iterations); draw_mandelbrot(width, 2.5f * width / 3, iterations);
} }
void draw_mandelbrot(int width, int height, int iterations) { void draw_mandelbrot(int width, int height, int iterations) {
@ -31,24 +41,51 @@ void draw_mandelbrot(int width, int height, int iterations) {
float step = 3.0f / width; float step = 3.0f / width;
Image img; Image img;
image_new(width, height, &img); image_new_shared(width, height, &img);
int thread_id = 0;
for (int i = 0; i < MB_THREADS - 1; i++) {
if (fork() == 0) {
thread_id = i + 1;
break;
}
}
printf("Thread %i reporting for duty\n", thread_id);
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
if (x % MB_THREADS != thread_id) continue;
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
Complex c = complex_new( Complex c = complex_new(
(x - center_x) * step, (x - center_x) * step,
(y - center_y) * step (y - center_y) * step
); );
int ret = test_mandelbrot(c, iterations); int ret = test_mandelbrot(c, iterations);
int r = (ret * 160 / iterations); //int r = (ret * 160 / iterations);
int g = (ret * 9 / iterations); //int g = (ret * 9 / iterations);
int b = (ret * 165 / iterations); //int b = (ret * 165 / iterations);
image_set_px(img, x, y, r,g,b); //image_set_px(img, x, y, r,g,b);
int color = 255 * ret / (float) iterations;
image_set_px(img, x, y, color, color, color);
} }
} }
printf("Thread %i is finished\n", thread_id);
if (thread_id != 0) {
exit(0);
}
int status;
for (int i = 0; i < MB_THREADS - 1; i++) {
printf("Waiting for threads... %d/%d\n", i, MB_THREADS - 1);
while(wait(&status) > 0) {}
}
printf("Got %d/%d threads\n", MB_THREADS - 1, MB_THREADS - 1);
image_save_bmp(img, "mandelbrot.bmp"); image_save_bmp(img, "mandelbrot.bmp");
image_destroy(img); image_destroy_shared(img);
} }
int test_mandelbrot(Complex c, int iterations) { int test_mandelbrot(Complex c, int iterations) {
@ -61,3 +98,45 @@ int test_mandelbrot(Complex c, int iterations) {
return 0; return 0;
} }
int image_new_shared(int width, int height, Image* img) {
if (img == NULL) return 0;
img->height = height;
img->width = width;
if ((unsigned long int) width * height * 3 > (unsigned long int) UINT_MAX) {
printf("Image dimensions to large for a bitmap!\n");
return 0;
}
// initialize bitmap...
img->bitmap = create_shared_memory(height * sizeof(char*));
for (int i = 0; i < height; i++) {
img->bitmap[i] = create_shared_memory(3 * width * sizeof(char));
}
return 1;
}
void image_destroy_shared(Image img) {
for (int i = 0; i < img.height; i++) {
munmap(img.bitmap[i], 3 * img.width * sizeof(char));
}
munmap(img.bitmap, img.height * sizeof(char*));
}
void* create_shared_memory(size_t size) {
// Our memory buffer will be readable and writable:
int protection = PROT_READ | PROT_WRITE;
// The buffer will be shared (meaning other processes can access it), but
// anonymous (meaning third-party processes cannot obtain an address for it),
// so only this process and its children will be able to use it:
int visibility = MAP_SHARED | MAP_ANONYMOUS;
// The remaining parameters to `mmap()` are not important for this use case,
// but the manpage for `mmap` explains their purpose.
return mmap(NULL, size, protection, visibility, -1, 0);
}
Loading…
Cancel
Save