Created
May 15, 2013 23:36
-
-
Save OliverUv/5588300 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| File: blurfilter_pthread.c | |
| Implementation of blurfilter function using pthreads. | |
| */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <pthread.h> | |
| #include "blurfilter.h" | |
| #include "ppmio.h" | |
| /* Global variables shared by threads. */ | |
| static pthread_t *threads; | |
| static pthread_attr_t t_attr; | |
| static pthread_barrier_t barrier; | |
| static const double *weights_g; | |
| static pixel *tmp_g; | |
| static pixel *src_g; | |
| static int radius_g; | |
| static int xsize_g, ysize_g; | |
| struct blur_args { | |
| int starting_row; | |
| int num_rows; | |
| }; | |
| pixel* pix(pixel* image, const int xx, const int yy, const int xsize) | |
| { | |
| register int off = xsize*yy + xx; | |
| #ifdef DBG | |
| if(off >= MAX_PIXELS) { | |
| fprintf(stderr, "\n Terribly wrong: %d %d %d\n",xx,yy,xsize); | |
| } | |
| #endif | |
| return (image + off); | |
| } | |
| static void *do_blur(void *arguments) | |
| { | |
| struct blur_args* arg = (struct blur_args*) arguments; | |
| int wi, x, y, x2, y2; | |
| int r, g, b, n, wc; | |
| int start = arg->starting_row; | |
| int end = arg->num_rows + arg->starting_row; | |
| for (y = start; y < end; y++) { | |
| for (x=0; x<xsize_g; x++) { | |
| r = weights_g[0] * pix(src_g, x, y, xsize_g)->r; | |
| g = weights_g[0] * pix(src_g, x, y, xsize_g)->g; | |
| b = weights_g[0] * pix(src_g, x, y, xsize_g)->b; | |
| n = weights_g[0]; | |
| for ( wi=1; wi <= radius_g; wi++) { | |
| wc = weights_g[wi]; | |
| x2 = x - wi; | |
| if(x2 >= 0) { | |
| r += wc * pix(src_g, x2, y, xsize_g)->r; | |
| g += wc * pix(src_g, x2, y, xsize_g)->g; | |
| b += wc * pix(src_g, x2, y, xsize_g)->b; | |
| n += wc; | |
| } | |
| x2 = x + wi; | |
| if(x2 < xsize_g) { | |
| r += wc * pix(src_g, x2, y, xsize_g)->r; | |
| g += wc * pix(src_g, x2, y, xsize_g)->g; | |
| b += wc * pix(src_g, x2, y, xsize_g)->b; | |
| n += wc; | |
| } | |
| } | |
| pix(tmp_g,x,y, xsize_g)->r = r/n; | |
| pix(tmp_g,x,y, xsize_g)->g = g/n; | |
| pix(tmp_g,x,y, xsize_g)->b = b/n; | |
| } | |
| } | |
| // Wait for other threads to finish horizontal bluring. | |
| pthread_barrier_wait(&barrier); | |
| for (y = start; y < end; y++) { | |
| for (x=0; x<xsize_g; x++) { | |
| r = weights_g[0] * pix(tmp_g, x, y, xsize_g)->r; | |
| g = weights_g[0] * pix(tmp_g, x, y, xsize_g)->g; | |
| b = weights_g[0] * pix(tmp_g, x, y, xsize_g)->b; | |
| n = weights_g[0]; | |
| for (wi=1; wi <= radius_g; wi++) { | |
| wc = weights_g[wi]; | |
| y2 = y - wi; | |
| if(y2 >= 0) { | |
| r += wc * pix(tmp_g, x, y2, xsize_g)->r; | |
| g += wc * pix(tmp_g, x, y2, xsize_g)->g; | |
| b += wc * pix(tmp_g, x, y2, xsize_g)->b; | |
| n += wc; | |
| } | |
| y2 = y + wi; | |
| if(y2 < end) { | |
| r += wc * pix(tmp_g, x, y2, xsize_g)->r; | |
| g += wc * pix(tmp_g, x, y2, xsize_g)->g; | |
| b += wc * pix(tmp_g, x, y2, xsize_g)->b; | |
| n += wc; | |
| } | |
| } | |
| pix(src_g,x,y, xsize_g)->r = r/n; | |
| pix(src_g,x,y, xsize_g)->g = g/n; | |
| pix(src_g,x,y, xsize_g)->b = b/n; | |
| } | |
| } | |
| pthread_exit(NULL); | |
| } | |
| void define_workloads(int ysize, int xsize, int num_threads, struct blur_args* args) | |
| { | |
| // Calculate number of pixels per thread | |
| int i; | |
| int rows_to_modify_per_thread = ysize / num_threads; | |
| for (i = 0; i < num_threads; ++i) { | |
| args[i].num_rows = rows_to_modify_per_thread; | |
| } | |
| int rest = ysize % num_threads; | |
| args[num_threads - 1].num_rows += rest; | |
| // Calculate displacement per thread | |
| int sum_rows = 0; | |
| for (i = 0; i < num_threads; ++i) | |
| { | |
| args[i].starting_row = sum_rows; | |
| sum_rows += args[i].num_rows; | |
| } | |
| } | |
| void blurfilter(const int xsize, const int ysize, pixel* src, | |
| const int radius, const double *w) | |
| { | |
| int num_threads, i; | |
| weights_g = w; | |
| radius_g = radius; | |
| xsize_g = xsize; | |
| ysize_g = ysize; | |
| src_g = src; | |
| tmp_g = malloc(xsize * ysize * sizeof(*tmp_g)); | |
| char *num_threads_env = getenv("NUM_THREADS"); | |
| if (num_threads_env) | |
| num_threads = atoi(num_threads_env); | |
| else | |
| num_threads = 16; | |
| threads = malloc(num_threads * sizeof(*threads)); | |
| pthread_attr_init(&t_attr); | |
| pthread_barrier_init(&barrier, NULL, num_threads); | |
| pthread_attr_setdetachstate(&t_attr, PTHREAD_CREATE_JOINABLE); | |
| struct blur_args args[num_threads]; | |
| define_workloads(ysize, xsize, num_threads, args); | |
| // Launch first pass | |
| for (i = 0; i < num_threads; ++i) | |
| { | |
| pthread_create(&threads[i], &t_attr, do_blur, (void *) &args[i]); | |
| // TODO check for errors when return value != 0 | |
| } | |
| // Ensure all threads have reached this point before progressing. | |
| void *status; | |
| for (i = 0; i < num_threads; ++i) | |
| { | |
| pthread_join(threads[i], &status); | |
| // TODO check for errors when return value != 0 | |
| } | |
| pthread_attr_destroy(&t_attr); | |
| pthread_barrier_destroy(&barrier); | |
| free(tmp_g); | |
| free(threads); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment