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  | 
