multi-threaded multibrot

master
orange 12 years ago
parent 1b4f1b7592
commit 49b477b2de

@ -1,8 +1,11 @@
#include <assert.h>
#include <complex.h> #include <complex.h>
#include <getopt.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <png.h> #include <png.h>
#include <pthread.h>
typedef uint32_t pixel_t; typedef uint32_t pixel_t;
@ -17,8 +20,7 @@ const int max_it = 170;
/* Compute the out-coloring based on the iteration counter. */ /* Compute the out-coloring based on the iteration counter. */
pixel_t outcolor(int it) { pixel_t outcolor(int it) {
/* return 0x00010001 * ((it * 0xff) / max_it); */ return 0x00010001 * ((it * 0xff) / max_it);
return 0x00000001 * ((it * 0xff) / max_it);
} }
/* "Compute" the in-coloring. */ /* "Compute" the in-coloring. */
@ -26,12 +28,10 @@ pixel_t incolor() {
return 0x00000000; /* black */ 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 x = 0; x < mbrot->width; x++) {
for (size_t i = 0; i < mbrot->width * mbrot->height; i++) {
size_t y = i / mbrot->width;
size_t x = i % mbrot->width;
float complex c = ((3.0f * x / mbrot->width) - 2.0f) float complex c = ((3.0f * x / mbrot->width) - 2.0f)
+ I * ((2.0f * y / mbrot->height) - 1.0f); + I * ((2.0f * y / mbrot->height) - 1.0f);
@ -57,14 +57,42 @@ void drawmandelbrot(bitmap_t * mbrot) {
color = incolor(); color = incolor();
} }
size_t i = y * mbrot->width + x;
mbrot->pixels[i] = color; 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 /* Write "bitmap" to a PNG file specified by "path"; returns 0 on
success, non-zero on error. */ success, non-zero on error. */
static int save_png_to_file(bitmap_t * bitmap, const char *path) { static int save_png_to_file(bitmap_t * bitmap, const char *path) {
FILE *fp; 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'. */ * is set to a value which means 'success'. */
int status = -1; 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 pixel_size = 3;
int depth = 8; 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; goto png_create_info_struct_failed;
} }
/*Set up error handling. */ /* Set up error handling. */
if (setjmp(png_jmpbuf(png_ptr))) { if (setjmp(png_jmpbuf(png_ptr))) {
goto png_failure; 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); png_malloc(png_ptr, sizeof(uint8_t) * bitmap->width * pixel_size);
row_pointers[y] = row; row_pointers[y] = row;
for (x = 0; x < bitmap->width; ++x) { for (x = 0; x < bitmap->width; ++x) {
/* FIXME */
pixel_t *pixel = bitmap->pixels + (y*bitmap->width + x); pixel_t *pixel = bitmap->pixels + (y*bitmap->width + x);
*row++ = (*pixel & 0x00ff0000) >> 16; *row++ = (*pixel & 0x00ff0000) >> 16;
*row++ = (*pixel & 0x0000ff00) >> 8; *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_free(png_ptr, row_pointers);
png_failure: png_failure:
/* FIXME info struct destroy? */
png_create_info_struct_failed: png_create_info_struct_failed:
png_destroy_write_struct(&png_ptr, &info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr);
png_create_write_struct_failed: png_create_write_struct_failed:
@ -154,21 +178,54 @@ fopen_failed:
} }
int main(int argc, char *argv[]) { 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 <number_of_threads>\n");
exit(0);
}
/* Set up mandelbrot bitmap. */
bitmap_t mbrot; bitmap_t mbrot;
mbrot.width = 640; mbrot.width = 1600;
mbrot.height = 480; /* FIXME calculate */ mbrot.height = 1200;
mbrot.pixels = calloc(sizeof(pixel_t), mbrot.width * mbrot.height); 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. */ ret = pthread_mutex_init(&next_y_mutex, NULL);
drawmandelbrot(&mbrot); 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 */ /* Save PNG */
char *file = "multibrot.png"; char *file = "multibrot.png";
if (save_png_to_file(&mbrot, file) != 0) { ret = save_png_to_file(&mbrot, file);
fprintf(stderr, "Could not save PNG to %s.\n", file); assert(ret == 0);
exit(1);
}
/* Quit. */ /* Quit. */
pthread_exit(NULL);
free(threads);
free(mbrot.pixels);
ret = pthread_mutex_destroy(&next_y_mutex);
assert(ret == 0);
return 0; return 0;
} }

Loading…
Cancel
Save