diff options
-rw-r--r-- | algorithms/burning-ship-lattice.c | 11 | ||||
-rw-r--r-- | algorithms/burning-ship.c | 11 | ||||
-rw-r--r-- | algorithms/mandelbrot.c | 11 | ||||
-rw-r--r-- | algorithms/tricorn.c | 11 | ||||
-rw-r--r-- | fractal-gen.c | 106 | ||||
-rw-r--r-- | fractal-gen.h | 18 |
6 files changed, 98 insertions, 70 deletions
diff --git a/algorithms/burning-ship-lattice.c b/algorithms/burning-ship-lattice.c index a219537..7c2d1e9 100644 --- a/algorithms/burning-ship-lattice.c +++ b/algorithms/burning-ship-lattice.c @@ -31,27 +31,26 @@ void *generate_burning_ship_lattice_section(void *section) { data_section *d = (data_section*)section; unsigned int x,y,i; - int idx = 0; double a,b; double complex z,c; double size_units = 0.09f; double top = -0.082f; double left = -1.8f; - for (y = d->core, b = (d->core*(size_units/d->size)+top); y < d->size; b+=((d->cores*size_units)/d->size), y+=d->cores) + for (y = d->core, b = (d->core*(size_units/size)+top); y < size; b+=((cores*size_units)/size), y+=cores) { - for (x = 0, a = left; x < d->size; a+=(size_units/d->size), x++) + for (x = 0, a = left; x < size; a+=(size_units/size), x++) { z = 0; c = a+I*b; - for (i = 0; i < d->iterat; i++) + for (i = 0; i < iterat; i++) { if (cabsf(z) >= 2) break; - z = cpow( cabsf(crealf(z)) + I*cabsf(cimagf(z)) , d->power) + c; + z = cpow( cabsf(crealf(z)) + I*cabsf(cimagf(z)) , power) + c; } - d->data[idx++] = (255*i)/d->iterat; + d->data[d->idx++] = (255*i)/iterat; } } return NULL; diff --git a/algorithms/burning-ship.c b/algorithms/burning-ship.c index 35d1839..8a5d1a1 100644 --- a/algorithms/burning-ship.c +++ b/algorithms/burning-ship.c @@ -31,27 +31,26 @@ void *generate_burning_ship_section(void *section) { data_section *d = (data_section*)section; unsigned int x,y,i; - int idx = 0; double a,b; double complex z,c; double size_units = 3.5f; double top = -2.2f; double left = -2.2f; - for (y = d->core, b = (d->core*(size_units/d->size)+top); y < d->size; b+=((d->cores*size_units)/d->size), y+=d->cores) + for (y = d->core, b = (d->core*(size_units/size)+top); y < size; b+=((cores*size_units)/size), y+=cores) { - for (x = 0, a = left; x < d->size; a+=(size_units/d->size), x++) + for (x = 0, a = left; x < size; a+=(size_units/size), x++) { z = 0; c = a+I*b; - for (i = 0; i < d->iterat; i++) + for (i = 0; i < iterat; i++) { if (cabsf(z) >= 2) break; - z = cpow( cabsf(crealf(z)) + I*cabsf(cimagf(z)) , d->power) + c; + z = cpow( cabsf(crealf(z)) + I*cabsf(cimagf(z)) , power) + c; } - d->data[idx++] = (255*i)/d->iterat; + d->data[d->idx++] = (255*i)/iterat; } } return NULL; diff --git a/algorithms/mandelbrot.c b/algorithms/mandelbrot.c index 1c3f5a2..28bb188 100644 --- a/algorithms/mandelbrot.c +++ b/algorithms/mandelbrot.c @@ -31,27 +31,26 @@ void *generate_mandelbrot_section(void *section) { data_section *d = (data_section*)section; unsigned int x,y,i; - int idx = 0; double a,b; double complex z,c; double size_units = 3.5f; double top = -1.75f; double left = -2.5f; - for (y = d->core, b = (d->core*(size_units/d->size)+top); y < d->size; b+=((d->cores*size_units)/d->size), y+=d->cores) + for (y = d->core, b = (d->core*(size_units/size)+top); y < size; b+=((cores*size_units)/size), y+=cores) { - for (x = d->clust_id, a = (d->clust_id*(size_units/d->size)+left); x < d->size; a+=((d->clust_total*size_units)/d->size), x+=d->clust_total) + for (x = clust_id, a = (clust_id*(size_units/size)+left); x < size; a+=((clust_total*size_units)/size), x+=clust_total) { z = 0; c = a+I*b; - for (i = 0; i < d->iterat; i++) + for (i = 0; i < iterat; i++) { if (cabsf(z) >= 2) break; - z = cpow(z , d->power) + c; + z = cpow(z , power) + c; } - d->data[idx++] = (255*i)/d->iterat; + d->data[d->idx++] = (255*i)/iterat; } } return NULL; diff --git a/algorithms/tricorn.c b/algorithms/tricorn.c index 16c399e..c89420a 100644 --- a/algorithms/tricorn.c +++ b/algorithms/tricorn.c @@ -31,27 +31,26 @@ void *generate_tricorn_section(void *section) { data_section *d = (data_section*)section; unsigned int x,y,i; - int idx = 0; double a,b; double complex z,c; double size_units = 4.f; double top = -2.f; double left = -2.3f; - for (y = d->core, b = (d->core*(size_units/d->size)+top); y < d->size; b+=((d->cores*size_units)/d->size), y+=d->cores) + for (y = d->core, b = (d->core*(size_units/size)+top); y < size; b+=((cores*size_units)/size), y+=cores) { - for (x = 0, a = left; x < d->size; a+=(size_units/d->size), x++) + for (x = 0, a = left; x < size; a+=(size_units/size), x++) { z = 0; c = a+I*b; - for (i = 0; i < d->iterat; i++) + for (i = 0; i < iterat; i++) { if (cabsf(z) >= 2) break; - z = cpow(conj(z) , d->power) + c; + z = cpow(conj(z) , power) + c; } - d->data[idx++] = (255*i)/d->iterat; + d->data[d->idx++] = (255*i)/iterat; } } return NULL; diff --git a/fractal-gen.c b/fractal-gen.c index dc30e8d..3268af2 100644 --- a/fractal-gen.c +++ b/fractal-gen.c @@ -35,9 +35,10 @@ struct section_generator int main(int argc, char **argv) { - unsigned int size, iterat, cores, i, x, y; - unsigned int clust_id, clust_total; - double power; + unsigned long x, y, i; + double thread_mult; + double ram_nice = 0.f; + char* ram_unit = NULL; char* bname; data_section* sections; void *(*generator)(void *); @@ -47,9 +48,9 @@ int main(int argc, char **argv) { "burning-ship-gen" , &generate_burning_ship_section }, { "burning-ship-lattice-gen" , &generate_burning_ship_lattice_section }, { "tricorn-gen" , &generate_tricorn_section } - }; + }; - // Select correct generator for the fractal type + /* Select correct generator for the fractal type */ bname = basename(argv[0]); generator = NULL; for (i = 0; i < sizeof(generators)/sizeof(struct section_generator); i++) @@ -62,10 +63,12 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - if (argc < 4 || argc > 6) + if (argc < 4 || argc > 7) { - fprintf(stderr, "%s size iterat power [threads]\n" - "%s size iterat power cluster-id cluster-total\n", argv[0], argv[0]); + fprintf(stderr, + "%s size iterat power [threads]\n" + "%s size iterat power thread_multiplier cluster-id cluster-total\n", + argv[0], argv[0]); return EXIT_FAILURE; } @@ -78,52 +81,73 @@ int main(int argc, char **argv) * - our ID in cluster * - total members in cluster */ - cores = (argc == 5)? atoi(argv[4]) : sysconf(_SC_NPROCESSORS_ONLN); // Screw maintainability ;) - clust_id = argc == 6? atoi(argv[4]) : 0; - clust_total = argc == 6? atoi(argv[5]) : 1; + cores = (argc == 5)? atoi(argv[4]) : sysconf(_SC_NPROCESSORS_ONLN); + thread_mult = argc == 7? atof(argv[4]) : 1.f; + clust_id = argc == 7? atoi(argv[5]) : 0; + clust_total = argc == 7? atoi(argv[6]) : 1; - // Interlacing is column-based, can't have more workers than columns + /* Extend number of threads to multiplier value */ + cores *= thread_mult; + + /* Interlacing is column-based, can't have more workers than columns */ if (cores > size) { fprintf(stderr, "WARN: Capping number of threads to image width\n"); cores = size; } + if (size % clust_total != 0) + { + fprintf(stderr, "ERROR: size must be an exact multiple of clust_total\n"); + return EXIT_FAILURE; + } + assert(size > 0); assert(iterat > 0); assert(cores > 0); - // Allocate memory for sections + /* Allocate memory for sections */ if ((sections = malloc(sizeof(data_section)*cores)) == NULL) { perror("malloc"); return EXIT_FAILURE; } - // Spawn all the threads! Something something interlacing - fprintf(stderr, "Spawning %d threads:\n", cores); + ram_nice = (size*size)/clust_total; + if (ram_nice < 1024) + ram_unit = "B"; + else if (ram_nice < 1024*1024) + ram_nice /= 1024, ram_unit = "KiB"; + else if (ram_nice < 1024*1024*1024) + ram_nice /= (1024*1024), ram_unit = "MiB"; + else + ram_nice /= (1024*1024*1024), ram_unit = "GiB"; + + fprintf(stderr, + "Forecast resource use:\n" + " Threads: %d\n" + " RAM : ~%.4f %s\n", + cores, + ram_nice, + ram_unit); + /* Spawn all the threads! Something something interlacing */ for (i = 0; i < cores; i++) { - // Has to be a better way - sections[i].core = i; - sections[i].cores = cores; - sections[i].clust_id = clust_id; - sections[i].clust_total = clust_total; - sections[i].size = size; - sections[i].power = power; - sections[i].iterat = iterat; - - // A bit complex, icky, will document later + /* A bit complex, icky, will document later */ if (i < (size%cores)) - x = (size*((int)(size/cores)+1)); + x = (size/cores)+1; else - x = (size*(int)(size/cores)); + x = (size/cores); + + x *= size; + x = ceilf((double)x/clust_total); if ((sections[i].data = malloc(x)) == NULL) { - fprintf(stderr, "\n"); + fprintf(stderr, "\nmalloc of %lu bytes failed\n", x); perror("malloc"); - // Free already allocated chunks of memory + + /* Free already allocated chunks of memory */ i--; while(i-- + 1) free(sections[i].data); @@ -131,31 +155,35 @@ int main(int argc, char **argv) free(sections); return EXIT_FAILURE; } - fprintf(stderr, " -> Thread #%d (%d bytes data area)\r", i+1, x); + sections[i].core = i; + sections[i].datasize = x; + fprintf(stderr, " -> Thread %lu\r", i); pthread_create(§ions[i].thread, NULL, generator, &(sections[i])); } - // Wait for each thread to complete + while((x = sections[0].idx) < sections[0].datasize) + { + fprintf(stderr, "Thread 0: %.4f%%\r", 100.f*(double)x/sections[0].datasize ); + sleep(1); + } + + /* Wait for each thread to complete */ for (i = 0; i < cores; i++) pthread_join(sections[i].thread, NULL); - // Output PGM Header + /* Output PGM Header */ printf("P5\n%d\n%d\n255\n",size/clust_total,size); - // Vomit the data segments back onto the screen, deinterlacing - // TO DO: look at fwrite performance benefits over putchar + /* Vomit the data segments back onto the screen, deinterlacing + * TO DO: look at fwrite performance benefits over putchar */ for (y = 0; y < size; y++) - { for (x = 0; x < size/clust_total; x++) - { putchar(sections[y%cores].data[(y/cores)*(size/clust_total) + x]); - } - } fprintf(stderr, "\nDone\n"); - // Free the memory we allocated for point data + /* Free the memory we allocated for point data */ for (i = 0; i < cores; i++) free(sections[i].data); diff --git a/fractal-gen.h b/fractal-gen.h index 656aeec..a4c0b76 100644 --- a/fractal-gen.h +++ b/fractal-gen.h @@ -40,17 +40,21 @@ typedef struct { - unsigned int core; - unsigned int cores; - unsigned int clust_id; - unsigned int clust_total; - unsigned int size; - double power; - unsigned int iterat; + volatile unsigned long idx; + unsigned long core; + unsigned long datasize; char* data; pthread_t thread; } data_section; +unsigned int cores; +unsigned int clust_id; +unsigned int clust_total; +unsigned int size; +unsigned int iterat; +double power; + + #include "algorithms.h" #endif |