multi-threaded multibrot
This commit is contained in:
parent
1b4f1b7592
commit
123fc4cb54
2 changed files with 82 additions and 25 deletions
4
Makefile
4
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
|
||||
|
|
103
multibrot.c
103
multibrot.c
|
@ -1,8 +1,11 @@
|
|||
#include <assert.h>
|
||||
#include <complex.h>
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <png.h>
|
||||
#include <pthread.h>
|
||||
|
||||
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[]) {
|
||||
bitmap_t mbrot;
|
||||
mbrot.width = 640;
|
||||
mbrot.height = 480; /* FIXME calculate */
|
||||
mbrot.pixels = calloc(sizeof(pixel_t), mbrot.width * mbrot.height);
|
||||
|
||||
/* Do the mandelbrot. */
|
||||
drawmandelbrot(&mbrot);
|
||||
/* 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;
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue