From 123fc4cb5440494e9e324494bda74696c1b48133 Mon Sep 17 00:00:00 2001 From: orange Date: Sun, 16 Jun 2013 16:12:08 +0200 Subject: [PATCH] multi-threaded multibrot --- Makefile | 4 +-- multibrot.c | 99 +++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 80 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 8b48105..5918cef 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ checkcheck: checkcheck.c $(CC) $(CFLAGS) -o $@ $< -lcheck multibrot: multibrot.c - $(CC) $(CFLAGS) -o $@ $< -lm -lpng + $(CC) $(CFLAGS) -o $@ $< -lm -lpng -pthread multibrot.png: multibrot - ./multibrot + ./multibrot -j2 diff --git a/multibrot.c b/multibrot.c index 11d6554..3a955d2 100644 --- a/multibrot.c +++ b/multibrot.c @@ -1,8 +1,11 @@ +#include #include +#include #include #include #include #include +#include typedef uint32_t pixel_t; @@ -17,8 +20,7 @@ const int max_it = 170; /* Compute the out-coloring based on the iteration counter. */ pixel_t outcolor(int it) { - /* return 0x00010001 * ((it * 0xff) / max_it); */ - return 0x00000001 * ((it * 0xff) / max_it); + return 0x00010001 * ((it * 0xff) / max_it); } /* "Compute" the in-coloring. */ @@ -26,12 +28,10 @@ pixel_t incolor() { return 0x00000000; /* black */ } +/* Computes the visual representation of a mandelbrot set for a given line. */ +void compmandelbrot_line(bitmap_t* mbrot, size_t y) { -void drawmandelbrot(bitmap_t * mbrot) { - - for (size_t i = 0; i < mbrot->width * mbrot->height; i++) { - size_t y = i / mbrot->width; - size_t x = i % mbrot->width; + for (size_t x = 0; x < mbrot->width; x++) { float complex c = ((3.0f * x / mbrot->width) - 2.0f) + I * ((2.0f * y / mbrot->height) - 1.0f); @@ -57,14 +57,42 @@ void drawmandelbrot(bitmap_t * mbrot) { color = incolor(); } + size_t i = y * mbrot->width + x; mbrot->pixels[i] = color; } } +/* Next line to compute. */ +size_t next_y = 0; + +/* Mutex for next_y. */ +pthread_mutex_t next_y_mutex; + +/* Thread to compute mandelbrot. */ +void *compmandelbrot(void *arg) { + bitmap_t* mbrot = (bitmap_t*) arg; + + size_t y = 0; + while (y < mbrot->height) { + int ret; + ret = pthread_mutex_lock(&next_y_mutex); + assert(ret == 0); + + y = next_y++; + + ret = pthread_mutex_unlock(&next_y_mutex); + assert(ret == 0); + + if (y < mbrot->height) { + compmandelbrot_line(mbrot, y); + } + } + + pthread_exit(NULL); +} /* Write "bitmap" to a PNG file specified by "path"; returns 0 on success, non-zero on error. */ - static int save_png_to_file(bitmap_t * bitmap, const char *path) { FILE *fp; @@ -78,8 +106,6 @@ static int save_png_to_file(bitmap_t * bitmap, const char *path) { * is set to a value which means 'success'. */ int status = -1; - /* FIXME The following number is set by trial and error only. I cannot see - * where it it is documented in the libpng manual. */ int pixel_size = 3; int depth = 8; @@ -99,7 +125,7 @@ static int save_png_to_file(bitmap_t * bitmap, const char *path) { goto png_create_info_struct_failed; } - /*Set up error handling. */ + /* Set up error handling. */ if (setjmp(png_jmpbuf(png_ptr))) { goto png_failure; } @@ -121,7 +147,6 @@ static int save_png_to_file(bitmap_t * bitmap, const char *path) { png_malloc(png_ptr, sizeof(uint8_t) * bitmap->width * pixel_size); row_pointers[y] = row; for (x = 0; x < bitmap->width; ++x) { - /* FIXME */ pixel_t *pixel = bitmap->pixels + (y*bitmap->width + x); *row++ = (*pixel & 0x00ff0000) >> 16; *row++ = (*pixel & 0x0000ff00) >> 8; @@ -144,7 +169,6 @@ static int save_png_to_file(bitmap_t * bitmap, const char *path) { png_free(png_ptr, row_pointers); png_failure: - /* FIXME info struct destroy? */ png_create_info_struct_failed: png_destroy_write_struct(&png_ptr, &info_ptr); png_create_write_struct_failed: @@ -154,21 +178,54 @@ fopen_failed: } int main(int argc, char *argv[]) { + + /* Get command line options. */ + int num_threads = 1; + char* options = "j:"; + if (getopt(argc, argv, options) == 'j') { + num_threads = (int) strtol(optarg, NULL, 10); + assert(num_threads != 0); + } else { + printf("Usage: multibrot -j \n"); + exit(0); + } + + /* Set up mandelbrot bitmap. */ bitmap_t mbrot; - mbrot.width = 640; - mbrot.height = 480; /* FIXME calculate */ + mbrot.width = 1600; + mbrot.height = 1200; mbrot.pixels = calloc(sizeof(pixel_t), mbrot.width * mbrot.height); + assert(mbrot.pixels != NULL); + + /* Start computing threads. */ + int ret; + pthread_t* threads; + threads = calloc(sizeof(pthread_t), num_threads); - /* Do the mandelbrot. */ - drawmandelbrot(&mbrot); + ret = pthread_mutex_init(&next_y_mutex, NULL); + assert(ret == 0); + + for (int t = 0; t < num_threads; t++) { + ret = pthread_create(&threads[t], NULL, compmandelbrot, (void *) &mbrot); + assert(ret == 0); + } + + /* Wait for the threads to finish. */ + for (int t = 0; t < num_threads; t++) { + ret = pthread_join(threads[t], NULL); + assert(ret == 0); + } /* Save PNG */ char *file = "multibrot.png"; - if (save_png_to_file(&mbrot, file) != 0) { - fprintf(stderr, "Could not save PNG to %s.\n", file); - exit(1); - } + ret = save_png_to_file(&mbrot, file); + assert(ret == 0); /* Quit. */ + pthread_exit(NULL); + free(threads); + free(mbrot.pixels); + ret = pthread_mutex_destroy(&next_y_mutex); + assert(ret == 0); return 0; }