This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project gfxprim.git.
The branch, master has been updated via 2b5429389de2a646451066572a1c143b80b2efd5 (commit) via d8048d925822c4528faf5c31f02dbc04bcf3dd1e (commit) via 84d09f0d259d317aaddf552c9a4d8f2b0b640ef4 (commit) via 7f869a1b5a909e54300e43194f804430c7bd3739 (commit) via b0e6247fbfb2a2741292723eeba71353d11bd322 (commit) from 090ff9d7d97bdde4cb8daac440294a7460319f2d (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- http://repo.or.cz/w/gfxprim.git/commit/2b5429389de2a646451066572a1c143b80b2e...
commit 2b5429389de2a646451066572a1c143b80b2efd5 Author: Cyril Hrubis metan@ucw.cz Date: Tue Jul 3 12:42:31 2012 +0200
filters: Add initial version of multithreaded linear convolution.
diff --git a/libs/filters/GP_LinearThreads.c b/libs/filters/GP_LinearThreads.c new file mode 100644 index 0000000..e309e80 --- /dev/null +++ b/libs/filters/GP_LinearThreads.c @@ -0,0 +1,301 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +#include <unistd.h> +#include <pthread.h> +#include <string.h> + +#include "core/GP_Common.h" +#include "core/GP_Debug.h" + +#include "GP_Linear.h" +#include "GP_LinearThreads.h" + +static int nr_threads(GP_Size w, GP_Size h) +{ + int count = sysconf(_SC_NPROCESSORS_ONLN); + int threads = GP_MIN(count, (int)(w * h / 1024) + 1); + + if (count < -1) + threads = 1; + + GP_DEBUG(1, "Found %u CPUs size %ux%u runnig %u threads", + count, w, h, threads); + +// return threads; + return 4; +} + +/* + * Multithreaded callback wrapper. + */ +struct callback_priv { + float max; + int abort; + unsigned int nr_threads; + pthread_mutex_t mutex; + GP_ProgressCallback *orig_callback; +}; + +static int progress_callback_mp(GP_ProgressCallback *self) +{ + struct callback_priv *priv = self->priv; + + /* If any thread got non-zero return value from a callback, abort all */ + if (priv->abort) + return 1; + + if (pthread_mutex_trylock(&priv->mutex)) { + GP_DEBUG(1, "Mutex locked, skipping calllback."); + return 0; + } + + /* Compute max value for the percentage */ + priv->orig_callback->percentage = GP_MAX(self->percentage, priv->max); + priv->max = priv->orig_callback->percentage; + + /* Call the original callback */ + int ret = priv->orig_callback->callback(priv->orig_callback); + + /* Turn on abort flag if callback returned nonzero */ + if (ret) + priv->abort = 1; + + pthread_mutex_unlock(&priv->mutex); + + return ret; +} + +static void callback_priv_init(struct callback_priv *priv, int nr_threads, + GP_ProgressCallback *orig_callback) +{ + priv->nr_threads = nr_threads; + priv->orig_callback = orig_callback; + priv->max = 0; + priv->abort = 0; + pthread_mutex_init(&priv->mutex, NULL); +} + +static void callback_priv_exit(struct callback_priv *priv) +{ + pthread_mutex_destroy(&priv->mutex); +} + +/* + * This code just packs and unpacks convolution parameters. + */ +struct convolution { + const GP_Context *src; + GP_Coord x_src; + GP_Coord y_src; + GP_Size w_src; + GP_Size h_src; + + GP_Context *dst; + GP_Coord x_dst; + GP_Coord y_dst; + + float *kernel; + unsigned int ks; + float kern_div; + + GP_ProgressCallback *callback; +}; + +static void convolution_init(struct convolution *conv, const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + GP_Context *dst, GP_Coord x_dst, GP_Coord y_dst, + float kernel[], unsigned int ks, float kern_div, + GP_ProgressCallback *callback) +{ + conv->src = src; + conv->x_src = x_src; + conv->y_src = y_src; + conv->w_src = w_src; + conv->h_src = h_src; + conv->dst = dst; + conv->x_dst = x_dst; + conv->y_dst = y_dst; + conv->kernel = kernel; + conv->ks = ks; + conv->kern_div = kern_div; + conv->callback = callback; +} + +static void *h_linear_convolution(void *arg) +{ + struct convolution *conv = arg; + + long ret; + + ret = GP_FilterHLinearConvolution_Raw(conv->src, conv->x_src, conv->y_src, + conv->w_src, conv->h_src, conv->dst, + conv->x_dst, conv->y_dst, conv->kernel, + conv->ks, conv->kern_div, conv->callback); + return (void*)ret; +} + +static void *v_linear_convolution(void *arg) +{ + struct convolution *conv = arg; + + long ret; + + ret = GP_FilterVLinearConvolution_Raw(conv->src, conv->x_src, conv->y_src, + conv->w_src, conv->h_src, conv->dst, + conv->x_dst, conv->y_dst, conv->kernel, + conv->ks, conv->kern_div, conv->callback); + return (void*)ret; +} + + +int GP_FilterHLinearConvolutionMP_Raw(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, + float kernel[], uint32_t kw, float kern_div, + GP_ProgressCallback *callback) +{ + int t = nr_threads(w_src, h_src); + + if (t == 1) { + return GP_FilterHLinearConvolution_Raw(src, x_src, y_src, + w_src, h_src, + dst, x_dst, y_dst, + kernel, kw, kern_div, + callback); + } + + /* Create multithreaded safe callback on the stack */ + struct callback_priv priv; + callback_priv_init(&priv, t, callback); + GP_ProgressCallback callback_mp = {0, progress_callback_mp, &priv}; + + /* Run t threads */ + int i; + pthread_t threads[t]; + struct convolution convs[t]; + GP_Size h = h_src/t; + + for (i = 0; i < t; i++) { + GP_Coord y_src_2 = y_src + i * h; + GP_Coord y_dst_2 = y_dst + i * h; + GP_Size h_src_2 = h; + + if (i == t - 1) + h_src_2 = h_src - i * h; + + /* Pack convolution parameters into the structure */ + convolution_init(&convs[i], src, x_src, y_src_2, w_src, h_src_2, + dst, x_dst, y_dst_2, kernel, kw, kern_div, + callback ? &callback_mp : NULL); + + pthread_create(&threads[i], NULL, h_linear_convolution, &convs[i]); + } + + int ret = 0; + + for (i = 0; i < t; i++) { + long r; + + pthread_join(threads[i], (void*)&r); + + ret |= (int)r; + } + + callback_priv_exit(&priv); + + return ret; +} + + +int GP_FilterVLinearConvolutionMP_Raw(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, + float kernel[], uint32_t kh, float kern_div, + GP_ProgressCallback *callback) +{ + int t = nr_threads(w_src, h_src); + + if (t == 1) { + return GP_FilterVLinearConvolution_Raw(src, x_src, y_src, + w_src, h_src, + dst, x_dst, y_dst, + kernel, kh, kern_div, + callback); + } + + /* Create multithreaded safe callback on the stack */ + struct callback_priv priv; + callback_priv_init(&priv, t, callback); + GP_ProgressCallback callback_mp = {0, progress_callback_mp, &priv}; + + int i; + pthread_t threads[t]; + struct convolution convs[t]; + GP_Size h = h_src/t; + + for (i = 0; i < t; i++) { + GP_Coord y_src_2 = y_src + i * h; + GP_Coord y_dst_2 = y_dst + i * h; + GP_Size h_src_2 = h; + + if (i == t - 1) + h_src_2 = h_src - i * h; + + /* Pack convolution parameters into the structure */ + convolution_init(&convs[i], src, x_src, y_src_2, w_src, h_src_2, + dst, x_dst, y_dst_2, kernel, kh, kern_div, + callback ? &callback_mp : NULL); + + pthread_create(&threads[i], NULL, v_linear_convolution, &convs[i]); + } + + int ret = 0; + + for (i = 0; i < t; i++) { + long r; + pthread_join(threads[i], (void*)&r); + + ret |= (int)r; + } + + callback_priv_exit(&priv); + + return ret; +} + +/* +int GP_FilterLinearConvolutionMP_Raw(const GP_Context *src, + GP_Coord x_src, GP_Coord y_src, + GP_Size w_src, GP_Size h_src, + GP_Context *dst, + GP_Coord x_dst, GP_Coord y_dst, + float kernel[], uint32_t kw, uint32_t kh, + float kern_div, GP_ProgressCallback *callback) +{ +} +*/
http://repo.or.cz/w/gfxprim.git/commit/d8048d925822c4528faf5c31f02dbc04bcf3d...
commit d8048d925822c4528faf5c31f02dbc04bcf3dd1e Author: Cyril Hrubis metan@ucw.cz Date: Tue Jul 3 10:47:21 2012 +0200
filters: Linear Convolution make use of the TempAllocator.
diff --git a/libs/filters/GP_Linear.c b/libs/filters/GP_Linear.c index ca5c38a..f06d0f6 100644 --- a/libs/filters/GP_Linear.c +++ b/libs/filters/GP_Linear.c @@ -22,6 +22,7 @@
#include "core/GP_Context.h" #include "core/GP_GetPutPixel.h" +#include "core/GP_TempAlloc.h" #include "core/GP_Clamp.h"
#include "core/GP_Debug.h" @@ -42,18 +43,25 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src, uint32_t i; int32_t ikernel[kw], ikern_div; uint32_t size = w_src + kw - 1; - + GP_DEBUG(1, "Horizontal linear convolution kernel width %u " - "rectangle %ux%u", kw, w_src, h_src); + "offset %ix%i rectangle %ux%u", + kw, x_src, y_src, w_src, h_src);
for (i = 0; i < kw; i++) ikernel[i] = kernel[i] * MUL + 0.5;
ikern_div = kern_div * MUL + 0.5;
+ /* Create temporary buffers */ + GP_TempAllocCreate(temp, 3 * size * sizeof(int)); + + int *R = GP_TempAllocGet(temp, size * sizeof(int)); + int *G = GP_TempAllocGet(temp, size * sizeof(int)); + int *B = GP_TempAllocGet(temp, size * sizeof(int)); + /* Do horizontal linear convolution */ for (y = 0; y < (GP_Coord)h_src; y++) { - int R[size], G[size], B[size]; int yi = GP_MIN(y_src + y, (int)src->h - 1);
/* Fetch the whole row */ @@ -63,7 +71,7 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src, i = 0;
/* Copy border pixel until the source image starts */ - while (xi <= 0) { + while (xi <= 0 && i < size) { R[i] = GP_Pixel_GET_R_RGB888(pix); G[i] = GP_Pixel_GET_G_RGB888(pix); B[i] = GP_Pixel_GET_B_RGB888(pix); @@ -73,7 +81,7 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src, }
/* Use as much source image pixels as possible */ - while (xi < (int)src->w) { + while (xi < (int)src->w && i < size) { pix = GP_GetPixel_Raw_24BPP(src, xi, yi);
R[i] = GP_Pixel_GET_R_RGB888(pix); @@ -108,10 +116,6 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src, g /= ikern_div; b /= ikern_div; - R[x] = r; - G[x] = g; - B[x] = b; - /* and clamp just to be extra sure */ r = GP_CLAMP(r, 0, 255); g = GP_CLAMP(g, 0, 255); @@ -121,9 +125,13 @@ int GP_FilterHLinearConvolution_Raw(const GP_Context *src, GP_Pixel_CREATE_RGB888(r, g, b)); }
- if (GP_ProgressCallbackReport(callback, y, dst->h, dst->w)) + if (GP_ProgressCallbackReport(callback, y, dst->h, dst->w)) { + GP_TempAllocFree(temp); return 1; + } } + + GP_TempAllocFree(temp);
GP_ProgressCallbackDone(callback); return 0; @@ -146,13 +154,20 @@ int GP_FilterVLinearConvolution_Raw(const GP_Context *src, ikernel[i] = kernel[i] * MUL + 0.5;
GP_DEBUG(1, "Vertical linear convolution kernel width %u " - "rectangle %ux%u", kh, w_src, h_src); + "offset %ix%i rectangle %ux%u", + kh, x_src, y_src, w_src, h_src);
ikern_div = kern_div * MUL + 0.5; + + /* Create temporary buffers */ + GP_TempAllocCreate(temp, 3 * size * sizeof(int)); + + int *R = GP_TempAllocGet(temp, size * sizeof(int)); + int *G = GP_TempAllocGet(temp, size * sizeof(int)); + int *B = GP_TempAllocGet(temp, size * sizeof(int));
/* Do vertical linear convolution */ for (x = 0; x < (GP_Coord)w_src; x++) { - int R[size], G[size], B[size]; int xi = GP_MIN(x_src + x, (int)src->w - 1); /* Fetch the whole row */ @@ -162,7 +177,7 @@ int GP_FilterVLinearConvolution_Raw(const GP_Context *src, i = 0;
/* Copy border pixel until the source image starts */ - while (yi <= 0) { + while (yi <= 0 && i < size) { R[i] = GP_Pixel_GET_R_RGB888(pix); G[i] = GP_Pixel_GET_G_RGB888(pix); B[i] = GP_Pixel_GET_B_RGB888(pix); @@ -172,7 +187,7 @@ int GP_FilterVLinearConvolution_Raw(const GP_Context *src, }
/* Use as much source image pixels as possible */ - while (yi < (int)src->h) { + while (yi < (int)src->h && i < size) { pix = GP_GetPixel_Raw_24BPP(src, xi, yi);
R[i] = GP_Pixel_GET_R_RGB888(pix); @@ -216,10 +231,14 @@ int GP_FilterVLinearConvolution_Raw(const GP_Context *src, GP_Pixel_CREATE_RGB888(r, g, b)); } - if (GP_ProgressCallbackReport(callback, x, dst->w, dst->h)) + if (GP_ProgressCallbackReport(callback, x, dst->w, dst->h)) { + GP_TempAllocFree(temp); return 1; + } }
+ GP_TempAllocFree(temp); + GP_ProgressCallbackDone(callback); return 0; }
http://repo.or.cz/w/gfxprim.git/commit/84d09f0d259d317aaddf552c9a4d8f2b0b640...
commit 84d09f0d259d317aaddf552c9a4d8f2b0b640ef4 Author: Cyril Hrubis metan@ucw.cz Date: Mon Jul 2 14:43:20 2012 +0200
core: Add simple temporary buffer allocator.
diff --git a/include/core/GP_TempAlloc.h b/include/core/GP_TempAlloc.h new file mode 100644 index 0000000..925b112 --- /dev/null +++ b/include/core/GP_TempAlloc.h @@ -0,0 +1,85 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +/* + + Temporary block allocator implementation. + + Creates pool for block allocation (small ones are done on the stack, bigger + using malloc). + + The usage is: + + // Creates new allocation pool + GP_TempAllocCrate(buf, 3 * 1024); + + // Make use of it + int *R = GP_TempAllocGet(buf, 1024); + int *G = GP_TempAllocGet(buf, 1024); + int *B = GP_TempAllocGet(buf, 1024); + + ... + + // Free it + GP_TempAllocDestroy(buf); + + */ + +#ifndef CORE_GP_TEMP_ALLOC_H +#define CORE_GP_TEMP_ALLOC_H + +#include <alloca.h> +#include <stdlib.h> + +#include "core/GP_Common.h" + +#ifndef GP_ALLOCA_THRESHOLD +# define GP_ALLOCA_THRESHOLD 2048 +#endif + +struct GP_TempAlloc { + void *buffer; + size_t pos; + size_t size; +}; + +#define GP_TEMP_ALLOC(size) ({ + ((size) > GP_ALLOCA_THRESHOLD) ? malloc(size) : alloca(size); +}) + +#define GP_TempAllocCreate(name, bsize) + struct GP_TempAlloc name = {.size = (bsize), .pos = 0, + .buffer = GP_TEMP_ALLOC(bsize)}; + +#define GP_TempAllocGet(self, bsize) ({ + GP_ASSERT(self.pos + bsize <= self.size); + size_t _pos = self.pos; + self.pos += bsize; + (void*)(((char*)(self.buffer)) + _pos); +}) + +#define GP_TempAllocFree(self) do { + if (self.size > GP_ALLOCA_THRESHOLD) + free(self.buffer); +} while (0) + +#endif /* CORE_GP_TEMP_ALLOC_H */
http://repo.or.cz/w/gfxprim.git/commit/7f869a1b5a909e54300e43194f804430c7bd3...
commit 7f869a1b5a909e54300e43194f804430c7bd3739 Author: Cyril Hrubis metan@ucw.cz Date: Sun Jul 1 23:32:47 2012 +0200
demos: spiv: Update cpu counter for multithread filters.
diff --git a/demos/spiv/cpu_timer.c b/demos/spiv/cpu_timer.c index 88455eb..6c26d61 100644 --- a/demos/spiv/cpu_timer.c +++ b/demos/spiv/cpu_timer.c @@ -23,26 +23,40 @@ #include <stdio.h> #include "cpu_timer.h"
+static void to_time(int *sec, int *nsec, struct timespec *start, + struct timespec *stop) +{ + if (stop->tv_nsec < start->tv_nsec) { + *sec = stop->tv_sec - start->tv_sec - 1; + *nsec = stop->tv_nsec + 1000000000 - start->tv_nsec; + } else { + *sec = stop->tv_sec - start->tv_sec; + *nsec = stop->tv_nsec - start->tv_nsec; + } +} + void cpu_timer_start(struct cpu_timer *self, const char *name) { self->name = name; - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &self->t_start); + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &self->t_cpu_start); + clock_gettime(CLOCK_MONOTONIC, &self->t_real_start); }
void cpu_timer_stop(struct cpu_timer *self) { - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &self->t_stop); + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &self->t_cpu_stop); + clock_gettime(CLOCK_MONOTONIC, &self->t_real_stop);
- int sec; - int nsec; + int cpu_sec; + int cpu_nsec;
- if (self->t_stop.tv_nsec < self->t_start.tv_nsec) { - sec = self->t_stop.tv_sec - self->t_start.tv_sec - 1; - nsec = self->t_stop.tv_nsec + 1000000000 - self->t_start.tv_nsec; - } else { - sec = self->t_stop.tv_sec - self->t_start.tv_sec; - nsec = self->t_stop.tv_nsec - self->t_start.tv_nsec; - } + int real_sec; + int real_nsec; + + to_time(&cpu_sec, &cpu_nsec, &self->t_cpu_start, &self->t_cpu_stop); + to_time(&real_sec, &real_nsec, &self->t_real_start, &self->t_real_stop);
- printf("TIMER '%s' %i.%09i secn", self->name, sec, nsec); + printf("TIMER '%s' CPU=%i.%09is REAL=%i.%09isn", self->name, + cpu_sec, cpu_nsec, real_sec, real_nsec); } diff --git a/demos/spiv/cpu_timer.h b/demos/spiv/cpu_timer.h index 1b41144..1d8c8e7 100644 --- a/demos/spiv/cpu_timer.h +++ b/demos/spiv/cpu_timer.h @@ -32,8 +32,10 @@ #include <time.h>
struct cpu_timer { - struct timespec t_start; - struct timespec t_stop; + struct timespec t_cpu_start; + struct timespec t_cpu_stop; + struct timespec t_real_start; + struct timespec t_real_stop; const char *name; };
http://repo.or.cz/w/gfxprim.git/commit/b0e6247fbfb2a2741292723eeba71353d11bd...
commit b0e6247fbfb2a2741292723eeba71353d11bd322 Author: Cyril Hrubis metan@ucw.cz Date: Sun Jul 1 23:16:33 2012 +0200
filters: GP_Linear.h remove the forgotten blur functions.
diff --git a/include/filters/GP_Linear.h b/include/filters/GP_Linear.h index e6cf885..ae96e34 100644 --- a/include/filters/GP_Linear.h +++ b/include/filters/GP_Linear.h @@ -32,35 +32,6 @@ #include "GP_Filter.h"
/* - * Gaussian blur - * - * The sigma parameters defines the blur radii in horizontal and vertical - * direction. - * - * Internaly this is implemented as separable linear filter (calls vertical and - * horizontal convolution with generated gaussian kernel). - * - * This variant could work in-place so it's perectly okay to call - * - * GP_FilterGaussianBlur_Raw(context, context, ...); - */ -int GP_FilterGaussianBlur_Raw(const GP_Context *src, GP_Context *dst, - float sigma_x, float sigma_y, - GP_ProgressCallback *callback); -/* - * Gaussian blur. - * - * If dst is NULL, new bitmap is allocated. - * - * This variant could work in-place. - * - * Returns pointer to destination bitmap or NULL if allocation failed. - */ -GP_Context *GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst, - float sigma_x, float sigma_y, - GP_ProgressCallback *callback); - -/* * Linear convolution. * * The kernel is array of kw * kh floats and is indexed as two directional
-----------------------------------------------------------------------
Summary of changes: demos/spiv/cpu_timer.c | 38 ++- demos/spiv/cpu_timer.h | 6 +- .../GP_Backend.c => include/core/GP_TempAlloc.h | 83 ++++-- include/filters/GP_Linear.h | 29 -- libs/filters/GP_Linear.c | 49 +++- libs/filters/GP_LinearThreads.c | 301 ++++++++++++++++++++ 6 files changed, 419 insertions(+), 87 deletions(-) copy libs/backends/GP_Backend.c => include/core/GP_TempAlloc.h (55%) create mode 100644 libs/filters/GP_LinearThreads.c
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos@gmail.com if you want to unsubscribe, or site admin admin@repo.or.cz if you receive no reply.