[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnuastro-commits] master e65eb48: Arithmetic: multithreaded variable-op
From: |
Mohammad Akhlaghi |
Subject: |
[gnuastro-commits] master e65eb48: Arithmetic: multithreaded variable-operand operators |
Date: |
Tue, 19 Mar 2019 09:25:00 -0400 (EDT) |
branch: master
commit e65eb489065f030f90d557d7e6e1030a9a6c7cb5
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>
Arithmetic: multithreaded variable-operand operators
Arithmetic's variable-operand operators work independently on each pixel,
so as the datasets become larger and more numerous, they can greatly
benefit from multi-threaded analysis. However, until now, they done their
processing on a single thread.
With this commit, the `gal_arithmetic' library function accepts a new
argument for the number of threads to use and the variable-operand
operators will do their work in multi-threaded mode.
---
NEWS | 7 +
bin/arithmetic/arithmetic.c | 5 +-
bin/arithmetic/ui.c | 2 +
bin/convertt/convertt.c | 12 +-
bin/convertt/ui.c | 2 +-
bin/convolve/ui.c | 4 +-
bin/mkcatalog/ui.c | 2 +-
bin/statistics/ui.c | 8 +-
bin/table/table.c | 8 +-
doc/gnuastro.texi | 39 ++++--
lib/arithmetic.c | 326 ++++++++++++++++++++++++++------------------
lib/gnuastro/arithmetic.h | 2 +-
lib/options.c | 6 +-
13 files changed, 252 insertions(+), 171 deletions(-)
diff --git a/NEWS b/NEWS
index acf16eb..ced25a9 100644
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,10 @@ GNU Astronomy Utilities NEWS -*-
outline -*-
`sigclip-median', and `sigclip-std'. These are very useful when
several inputs have strong outliers that affect the median, or the
mean is required.
+ - Multithreaded operation for the following operators that
+ combine/co-add multiple inputs into one output with same size: `min',
+ `max', `number', `sum', `mean', `std', `median', `sigclip-number',
+ `sigclip-median', `sigclip-mean', `sigclip-std'.
--wcsfile and --wcshdu: these two options can be used to specify a
different file for reading the WCS of the output. This is useful when
the default (theh WCS of the first dataset that is read) is not the
@@ -150,6 +154,9 @@ GNU Astronomy Utilities NEWS -*-
outline -*-
version, the `-s' short option was used for it. But with the new
`--sort' option, `-s' may cause confusion.
+ Library
+ gal_arithmetic: new argument: number of threads to use (when relevant).
+
** Bugs fixed
bug #55313: Fits program writing --write values in reverse order
bug #55333: Fits program crash when --write or --update have no value.
diff --git a/bin/arithmetic/arithmetic.c b/bin/arithmetic/arithmetic.c
index bfa33e0..0c60cdb 100644
--- a/bin/arithmetic/arithmetic.c
+++ b/bin/arithmetic/arithmetic.c
@@ -431,7 +431,7 @@ wrapper_for_filter(struct arithmeticparams *p, char *token,
int operator)
"along dimension %zu is a float", ndim-i);
/* Make sure it isn't negative. */
- comp=gal_arithmetic(GAL_ARITHMETIC_OP_GT, 0, tmp, zero);
+ comp=gal_arithmetic(GAL_ARITHMETIC_OP_GT, 1, 0, tmp, zero);
if( *(uint8_t *)(comp->array) == 0 )
error(EXIT_FAILURE, 0, "lengths of filter along dimensions "
"must be positive. The given length in dimension %zu"
@@ -1153,7 +1153,8 @@ reversepolish(struct arithmeticparams *p)
number of arguments it uses depend on the operator. So
when the operator doesn't need three operands, the extra
arguments will be ignored. */
- operands_add(p, NULL, gal_arithmetic(op, flags, d1, d2, d3));
+ operands_add(p, NULL, gal_arithmetic(op, p->cp.numthreads,
+ flags, d1, d2, d3));
}
/* No need to call the arithmetic library, call the proper
diff --git a/bin/arithmetic/ui.c b/bin/arithmetic/ui.c
index f08d5c1..0ef9a24 100644
--- a/bin/arithmetic/ui.c
+++ b/bin/arithmetic/ui.c
@@ -33,6 +33,7 @@ along with Gnuastro. If not, see
<http://www.gnu.org/licenses/>.
#include <gnuastro/fits.h>
#include <gnuastro/table.h>
#include <gnuastro/array.h>
+#include <gnuastro/threads.h>
#include <gnuastro-internal/timing.h>
#include <gnuastro-internal/options.h>
@@ -124,6 +125,7 @@ ui_initialize_options(struct arithmeticparams *p,
cp->program_exec = PROGRAM_EXEC;
cp->program_bibtex = PROGRAM_BIBTEX;
cp->program_authors = PROGRAM_AUTHORS;
+ cp->numthreads = gal_threads_number();
cp->coptions = gal_commonopts_options;
/* Modify the common options. */
diff --git a/bin/convertt/convertt.c b/bin/convertt/convertt.c
index 3ffb66d..128dde6 100644
--- a/bin/convertt/convertt.c
+++ b/bin/convertt/convertt.c
@@ -72,11 +72,11 @@ convertt_change(struct converttparams *p)
{
/* Make a condition array: all pixels with a value equal to
`change->from' will be set as 1 in this array. */
- cond=gal_arithmetic(GAL_ARITHMETIC_OP_EQ, GAL_ARITHMETIC_NUMOK,
+ cond=gal_arithmetic(GAL_ARITHMETIC_OP_EQ, 1, GAL_ARITHMETIC_NUMOK,
channel, change->from);
/* Now, use the condition array to set the proper values. */
- channel=gal_arithmetic(GAL_ARITHMETIC_OP_WHERE, flags, channel,
+ channel=gal_arithmetic(GAL_ARITHMETIC_OP_WHERE, 1, flags, channel,
cond, change->to);
/* Clean up, since we set the free flag, all extra arrays have been
@@ -104,11 +104,11 @@ convertt_trunc_function(int operator, gal_data_t *data,
gal_data_t *value)
/* Make a condition array: all pixels with a value equal to
`change->from' will be set as 1 in this array. */
- cond=gal_arithmetic(operator, GAL_ARITHMETIC_NUMOK, data, value);
+ cond=gal_arithmetic(operator, 1, GAL_ARITHMETIC_NUMOK, data, value);
/* Now, use the condition array to set the proper values. */
- out=gal_arithmetic(GAL_ARITHMETIC_OP_WHERE, flags, data, cond, value);
+ out=gal_arithmetic(GAL_ARITHMETIC_OP_WHERE, 1, flags, data, cond, value);
/* A small sanity check. The process must be in-place so the original
@@ -200,8 +200,8 @@ convertt_scale_to_uchar(struct converttparams *p)
}
/* Calculate the minimum and maximum. */
- mind = gal_arithmetic(GAL_ARITHMETIC_OP_MINVAL, 0, channel);
- maxd = gal_arithmetic(GAL_ARITHMETIC_OP_MAXVAL, 0, channel);
+ mind = gal_arithmetic(GAL_ARITHMETIC_OP_MINVAL, 1, 0, channel);
+ maxd = gal_arithmetic(GAL_ARITHMETIC_OP_MAXVAL, 1, 0, channel);
tmin = *((float *)(mind->array));
tmax = *((float *)(maxd->array));
gal_data_free(mind);
diff --git a/bin/convertt/ui.c b/bin/convertt/ui.c
index 71bcc0d..284801c 100644
--- a/bin/convertt/ui.c
+++ b/bin/convertt/ui.c
@@ -332,7 +332,7 @@ ui_read_check_only_options(struct converttparams *p)
if(p->fluxhighstr && p->fluxlowstr)
{
- cond=gal_arithmetic(GAL_ARITHMETIC_OP_GT, GAL_ARITHMETIC_NUMOK,
+ cond=gal_arithmetic(GAL_ARITHMETIC_OP_GT, 1, GAL_ARITHMETIC_NUMOK,
p->fluxhigh, p->fluxlow);
if( *((unsigned char *)cond->array) == 0 )
diff --git a/bin/convolve/ui.c b/bin/convolve/ui.c
index 1e40688..3698f8d 100644
--- a/bin/convolve/ui.c
+++ b/bin/convolve/ui.c
@@ -559,11 +559,11 @@ ui_preparations(struct convolveparams *p)
meaningful. */
sum=gal_statistics_sum(p->input);
sum=gal_data_copy_to_new_type_free(sum, GAL_TYPE_FLOAT32);
- p->input = gal_arithmetic(GAL_ARITHMETIC_OP_DIVIDE,
+ p->input = gal_arithmetic(GAL_ARITHMETIC_OP_DIVIDE, 1,
GAL_ARITHMETIC_FLAGS_ALL, p->input, sum);
sum=gal_statistics_sum(p->kernel);
sum=gal_data_copy_to_new_type_free(sum, GAL_TYPE_FLOAT32);
- p->kernel = gal_arithmetic(GAL_ARITHMETIC_OP_DIVIDE,
+ p->kernel = gal_arithmetic(GAL_ARITHMETIC_OP_DIVIDE, 1,
GAL_ARITHMETIC_FLAGS_ALL, p->kernel, sum);
}
}
diff --git a/bin/mkcatalog/ui.c b/bin/mkcatalog/ui.c
index 5a9ee5c..cc2daf4 100644
--- a/bin/mkcatalog/ui.c
+++ b/bin/mkcatalog/ui.c
@@ -1042,7 +1042,7 @@ ui_preparations_read_inputs(struct mkcatalogparams *p)
pixels and 0 for zero pixels. */
zero=gal_data_alloc(NULL, GAL_TYPE_UINT8, 1, &one, NULL, 1, -1,
NULL, NULL, NULL);
- p->upmask=gal_arithmetic(GAL_ARITHMETIC_OP_NE,
+ p->upmask=gal_arithmetic(GAL_ARITHMETIC_OP_NE, 1,
( GAL_ARITHMETIC_INPLACE
| GAL_ARITHMETIC_FREE
| GAL_ARITHMETIC_NUMOK ),
diff --git a/bin/statistics/ui.c b/bin/statistics/ui.c
index 4e1c7d4..662c0df 100644
--- a/bin/statistics/ui.c
+++ b/bin/statistics/ui.c
@@ -597,7 +597,7 @@ ui_out_of_range_to_blank(struct statisticsparams *p)
tmp=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 1, &one, NULL, 0, -1,
NULL, NULL, NULL);
*((float *)(tmp->array)) = p->greaterequal;
- cond_g=gal_arithmetic(GAL_ARITHMETIC_OP_LT, flags, ref, tmp);
+ cond_g=gal_arithmetic(GAL_ARITHMETIC_OP_LT, 1, flags, ref, tmp);
gal_data_free(tmp);
}
@@ -608,7 +608,7 @@ ui_out_of_range_to_blank(struct statisticsparams *p)
tmp=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 1, &one, NULL, 0, -1,
NULL, NULL, NULL);
*((float *)(tmp->array)) = p->lessthan;
- cond_l=gal_arithmetic(GAL_ARITHMETIC_OP_GE, flags, ref, tmp);
+ cond_l=gal_arithmetic(GAL_ARITHMETIC_OP_GE, 1, flags, ref, tmp);
gal_data_free(tmp);
}
@@ -622,7 +622,7 @@ ui_out_of_range_to_blank(struct statisticsparams *p)
cond = isnan(p->greaterequal) ? cond_l : cond_g;
break;
case 2:
- cond = gal_arithmetic(GAL_ARITHMETIC_OP_OR, flagsor, cond_l, cond_g);
+ cond = gal_arithmetic(GAL_ARITHMETIC_OP_OR, 1, flagsor, cond_l, cond_g);
break;
}
@@ -637,7 +637,7 @@ ui_out_of_range_to_blank(struct statisticsparams *p)
/* Set all the pixels that satisfy the condition to blank. Note that a
blank value will be used in the proper type of the input in the
`where' operator.*/
- gal_arithmetic(GAL_ARITHMETIC_OP_WHERE, flagsor, p->input, cond, blank);
+ gal_arithmetic(GAL_ARITHMETIC_OP_WHERE, 1, flagsor, p->input, cond, blank);
/* Reset the blank flags so they are checked again if necessary. */
diff --git a/bin/table/table.c b/bin/table/table.c
index 1b5008c..7577064 100644
--- a/bin/table/table.c
+++ b/bin/table/table.c
@@ -109,12 +109,12 @@ table_range(struct tableparams *p)
/* Find all the bad elements (smaller than the minimum and larger than
the maximum) so we can flag them. */
- ltmin=gal_arithmetic(GAL_ARITHMETIC_OP_LT, numok, ref, min);
- gemax=gal_arithmetic(GAL_ARITHMETIC_OP_GE, numok, ref, max);
- ltmin=gal_arithmetic(GAL_ARITHMETIC_OP_OR, inplace, ltmin, gemax);
+ ltmin=gal_arithmetic(GAL_ARITHMETIC_OP_LT, 1, numok, ref, min);
+ gemax=gal_arithmetic(GAL_ARITHMETIC_OP_GE, 1, numok, ref, max);
+ ltmin=gal_arithmetic(GAL_ARITHMETIC_OP_OR, 1, inplace, ltmin, gemax);
/* Add these flags to all previous flags. */
- mask=gal_arithmetic(GAL_ARITHMETIC_OP_OR, inplace, mask, ltmin);
+ mask=gal_arithmetic(GAL_ARITHMETIC_OP_OR, 1, inplace, mask, ltmin);
/* For a check.
{
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 6e94ddb..79664bc 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -12270,13 +12270,17 @@ to @command{minvalue}.
@item min
The first popped operand to this operator must be a positive integer number
which specifies how many further operands should be popped from the
-stack. The given number of operands must have the same type and size. Each
-pixel of the output of this operator will be set to the minimum value of
-the given number of operands (images) in that pixel.
+stack. All the subsequently popped operands must have the same type and
+size. This operator (and all the variable-operand operators similar to it
+that are discussed below) will work in multithreaded mode unless Arithmetic
+is called with the @option{--numthreads=1} option, see @ref{Multi-threaded
+operations}.
-For example the following command will produce an image with the same size
-and type as the inputs but each output pixel is set to the minimum
-respective pixel value of the three input images.
+Each pixel of the output of the @code{min} operator will be given the
+minimum value of the same pixel from all the popped operands/images. For
+example the following command will produce an image with the same size and
+type as the three inputs, but each output pixel value will be the minimum
+of the same pixel's values in all three input images.
@example
$ astarithmetic a.fits b.fits c.fits 3 min
@@ -27144,8 +27148,9 @@ Multi-operand statistical operations. When
@code{gal_arithmetic} is called
with any of these operators, it will expect only a single operand that will
be interpreted as a list of datasets (see @ref{List of gal_data_t}. The
output will be a single dataset with each of its elements replaced by the
-respective statistical operation on the whole list. See the discussion
-under the @code{min} operator in @ref{Arithmetic operators}.
+respective statistical operation on the whole list. These operators can
+work on multiple threads using the @code{numthreads} argument. See the
+discussion under the @code{min} operator in @ref{Arithmetic operators}.
@end deffn
@deffn Macro GAL_ARITHMETIC_OP_SIGCLIP_STD
@@ -27216,11 +27221,15 @@ directly use those functions.
@end deffn
address@hidden {gal_data_t *} gal_arithmetic (int operator, int flags, ...)
address@hidden {gal_data_t *} gal_arithmetic (int @code{operator}, size_t
@code{numthreads}, int @code{flags}, ...)
Do the arithmetic operation of @code{operator} on the given operands (the
-third argument and any further argument). Certain special conditions can
-also be specified with the @code{flag} operator. The acceptable values for
address@hidden are defined in the macros above.
+third argument and any further argument). If the operator can work on
+multiple threads, the number of threads can be specified with
address@hidden When the operator is single-threaded, @code{numthreads}
+will be ignored. Special conditions can also be specified with the
address@hidden operator (a bit-flag with bits described above, for example
address@hidden or @code{GAL_ARITHMETIC_FREE}). The
+acceptable values for @code{operator} are also defined in the macros above.
@code{gal_arithmetic} is a multi-argument function (like C's
@code{printf}). In other words, the number of necessary arguments is not
@@ -27228,9 +27237,9 @@ fixed and depends on the value to @code{operator}. Here
are a few examples
showing this variability:
@example
-out_1=gal_arithmetic(GAL_ARITHMETIC_OP_LOG, 0, in_1);
-out_2=gal_arithmetic(GAL_ARITHMETIC_OP_PLUS, 0, in_1, in_2);
-out_3=gal_arithmetic(GAL_ARITHMETIC_OP_WHERE, 0, in_1, in_2, in_3);
+out_1=gal_arithmetic(GAL_ARITHMETIC_OP_LOG, 1, 0, in_1);
+out_2=gal_arithmetic(GAL_ARITHMETIC_OP_PLUS, 1, 0, in_1, in_2);
+out_3=gal_arithmetic(GAL_ARITHMETIC_OP_WHERE, 1, 0, in_1, in_2, in_3);
@end example
The number of necessary operands for each operator (and thus the number of
diff --git a/lib/arithmetic.c b/lib/arithmetic.c
index aba3df2..dfdfabb 100644
--- a/lib/arithmetic.c
+++ b/lib/arithmetic.c
@@ -32,6 +32,7 @@ along with Gnuastro. If not, see
<http://www.gnu.org/licenses/>.
#include <gnuastro/blank.h>
#include <gnuastro/qsort.h>
#include <gnuastro/pointer.h>
+#include <gnuastro/threads.h>
#include <gnuastro/dimension.h>
#include <gnuastro/statistics.h>
#include <gnuastro/arithmetic.h>
@@ -669,27 +670,45 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
/***********************************************************************/
/*************** Multiple operand operators **************/
/***********************************************************************/
+struct multioperandparams
+{
+ gal_data_t *list; /* List of input datasets. */
+ gal_data_t *out; /* Output dataset. */
+ size_t dnum; /* Number of input dataset. */
+ int operator; /* Operator to use. */
+ uint8_t *hasblank; /* Array of 0s or 1s for each input. */
+ float p1; /* Sigma-cliping parameter 1. */
+ float p2; /* Sigma-cliping parameter 2. */
+};
+
+
+
+
+
#define MULTIOPERAND_MIN(TYPE) { \
- TYPE p, max; \
+ TYPE t, max; \
size_t n, j=0; \
- gal_type_max(list->type, &max); \
- do /* Loop over each pixel */ \
+ gal_type_max(p->list->type, &max); \
+ \
+ /* Go over all the pixels assigned to this thread. */ \
+ for(tind=0; tprm->indexs[tind] != GAL_BLANK_SIZE_T; ++tind) \
{ \
+ /* Initialize, `j' is desired pixel's index. */ \
n=0; \
- p=max; \
- for(i=0;i<dnum;++i) /* Loop over each array. */ \
+ t=max; \
+ j=tprm->indexs[tind]; \
+ \
+ for(i=0;i<p->dnum;++i) /* Loop over each array. */ \
{ /* Only for integer types, b==b. */ \
- if( hasblank[i] && b==b) \
+ if( p->hasblank[i] && b==b) \
{ \
if( a[i][j] != b ) \
- { p = a[i][j] < p ? a[i][j] : p; ++n; } \
+ { t = a[i][j] < t ? a[i][j] : t; ++n; } \
} \
- else { p = a[i][j] < p ? a[i][j] : p; ++n; } \
+ else { t = a[i][j] < t ? a[i][j] : t; ++n; } \
} \
- *o++ = n ? p : b; /* No usable elements: set to blank. */ \
- ++j; \
+ o[j] = n ? t : b; /* No usable elements: set to blank. */ \
} \
- while(o<of); \
}
@@ -697,26 +716,29 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
#define MULTIOPERAND_MAX(TYPE) { \
- TYPE p, min; \
+ TYPE t, min; \
size_t n, j=0; \
- gal_type_min(list->type, &min); \
- do /* Loop over each pixel */ \
+ gal_type_min(p->list->type, &min); \
+ \
+ /* Go over all the pixels assigned to this thread. */ \
+ for(tind=0; tprm->indexs[tind] != GAL_BLANK_SIZE_T; ++tind) \
{ \
+ /* Initialize, `j' is desired pixel's index. */ \
n=0; \
- p=min; \
- for(i=0;i<dnum;++i) /* Loop over each array. */ \
+ t=min; \
+ j=tprm->indexs[tind]; \
+ \
+ for(i=0;i<p->dnum;++i) /* Loop over each array. */ \
{ /* Only for integer types, b==b. */ \
- if( hasblank[i] && b==b) \
+ if( p->hasblank[i] && b==b) \
{ \
if( a[i][j] != b ) \
- { p = a[i][j] > p ? a[i][j] : p; ++n; } \
+ { t = a[i][j] > t ? a[i][j] : t; ++n; } \
} \
- else { p = a[i][j] > p ? a[i][j] : p; ++n; } \
+ else { t = a[i][j] > t ? a[i][j] : t; ++n; } \
} \
- *o++ = n ? p : b; /* No usable elements: set to blank. */ \
- ++j; \
+ o[j] = n ? t : b; /* No usable elements: set to blank. */ \
} \
- while(o<of); \
}
@@ -725,14 +747,19 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
#define MULTIOPERAND_NUM { \
int use; \
- size_t n, j=0; \
- do /* Loop over each pixel */ \
+ size_t n, j; \
+ \
+ /* Go over all the pixels assigned to this thread. */ \
+ for(tind=0; tprm->indexs[tind] != GAL_BLANK_SIZE_T; ++tind) \
{ \
+ /* Initialize, `j' is desired pixel's index. */ \
n=0; \
- for(i=0;i<dnum;++i) /* Loop over each array. */ \
+ j=tprm->indexs[tind]; \
+ \
+ for(i=0;i<p->dnum;++i) /* Loop over each array. */ \
{ \
/* Only integers and non-NaN floats: v==v is 1. */ \
- if(hasblank[i]) \
+ if(p->hasblank[i]) \
use = ( b==b \
? ( a[i][j]!=b ? 1 : 0 ) /* Integer */ \
: ( a[i][j]==a[i][j] ? 1 : 0 ) ); /* Float */ \
@@ -741,10 +768,8 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
/* Increment counter if necessary. */ \
if(use) ++n; \
} \
- *o++ = n; \
- ++j; \
+ o[j] = n; \
} \
- while(o<of); \
}
@@ -754,15 +779,20 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
#define MULTIOPERAND_SUM { \
int use; \
double sum; \
- size_t n, j=0; \
- do /* Loop over each pixel */ \
+ size_t n, j; \
+ \
+ /* Go over all the pixels assigned to this thread. */ \
+ for(tind=0; tprm->indexs[tind] != GAL_BLANK_SIZE_T; ++tind) \
{ \
+ /* Initialize, `j' is desired pixel's index. */ \
n=0; \
sum=0.0f; \
- for(i=0;i<dnum;++i) /* Loop over each array. */ \
+ j=tprm->indexs[tind]; \
+ \
+ for(i=0;i<p->dnum;++i) /* Loop over each array. */ \
{ \
/* Only integers and non-NaN floats: v==v is 1. */ \
- if(hasblank[i]) \
+ if(p->hasblank[i]) \
use = ( b==b \
? ( a[i][j]!=b ? 1 : 0 ) /* Integer */ \
: ( a[i][j]==*a[i] ? 1 : 0 ) ); /* Float */ \
@@ -771,10 +801,8 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
/* Use in sum if necessary. */ \
if(use) { sum += a[i][j]; ++n; } \
} \
- *o++ = n ? sum : b; \
- ++j; \
+ o[j] = n ? sum : b; \
} \
- while(o<of); \
}
@@ -784,15 +812,20 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
#define MULTIOPERAND_MEAN { \
int use; \
double sum; \
- size_t n, j=0; \
- do /* Loop over each pixel */ \
+ size_t n, j; \
+ \
+ /* Go over all the pixels assigned to this thread. */ \
+ for(tind=0; tprm->indexs[tind] != GAL_BLANK_SIZE_T; ++tind) \
{ \
+ /* Initialize, `j' is desired pixel's index. */ \
n=0; \
sum=0.0f; \
- for(i=0;i<dnum;++i) /* Loop over each array. */ \
+ j=tprm->indexs[tind]; \
+ \
+ for(i=0;i<p->dnum;++i) /* Loop over each array. */ \
{ \
/* Only integers and non-NaN floats: v==v is 1. */ \
- if(hasblank[i]) \
+ if(p->hasblank[i]) \
use = ( b==b \
? ( a[i][j]!=b ? 1 : 0 ) /* Integer */ \
: ( a[i][j]==a[i][j] ? 1 : 0 ) ); /* Float */ \
@@ -801,10 +834,8 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
/* Calculate the mean if necessary. */ \
if(use) { sum += a[i][j]; ++n; } \
} \
- *o++ = n ? sum/n : b; \
- ++j; \
+ o[j] = n ? sum/n : b; \
} \
- while(o<of); \
}
@@ -813,16 +844,21 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
#define MULTIOPERAND_STD { \
int use; \
- size_t n, j=0; \
+ size_t n, j; \
double sum, sum2; \
- do /* Loop over each pixel */ \
+ \
+ /* Go over all the pixels assigned to this thread. */ \
+ for(tind=0; tprm->indexs[tind] != GAL_BLANK_SIZE_T; ++tind) \
{ \
+ /* Initialize, `j' is desired pixel's index. */ \
n=0; \
sum=sum2=0.0f; \
- for(i=0;i<dnum;++i) /* Loop over each array. */ \
+ j=tprm->indexs[tind]; \
+ \
+ for(i=0;i<p->dnum;++i) /* Loop over each array. */ \
{ \
/* Only integers and non-NaN floats: v==v is 1. */ \
- if(hasblank[i]) \
+ if(p->hasblank[i]) \
use = ( b==b \
? ( a[i][j]!=b ? 1 : 0 ) /* Integer */ \
: ( a[i][j]==a[i][j] ? 1 : 0 ) ); /* Float */ \
@@ -836,10 +872,8 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
++n; \
} \
} \
- *o++ = n ? sqrt( (sum2-sum*sum/n)/n ) : b; \
- ++j; \
+ o[j] = n ? sqrt( (sum2-sum*sum/n)/n ) : b; \
} \
- while(o<of); \
}
@@ -848,21 +882,22 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
#define MULTIOPERAND_MEDIAN(TYPE, QSORT_F) { \
int use; \
- size_t n, j=0; \
- TYPE *pixs=gal_pointer_allocate(list->type, dnum, 0, __func__, \
- "pixs"); \
+ size_t n, j; \
+ TYPE *pixs=gal_pointer_allocate(p->list->type, p->dnum, 0, \
+ __func__, "pixs"); \
\
- /* Loop over each pixel */ \
- do \
+ /* Go over all the pixels assigned to this thread. */ \
+ for(tind=0; tprm->indexs[tind] != GAL_BLANK_SIZE_T; ++tind) \
{ \
- /* Initialize. */ \
+ /* Initialize, `j' is desired pixel's index. */ \
n=0; \
+ j=tprm->indexs[tind]; \
\
- /* Loop over each array. */ \
- for(i=0;i<dnum;++i) \
+ /* Loop over each array: `i' is input dataset's index. */ \
+ for(i=0;i<p->dnum;++i) \
{ \
/* Only integers and non-NaN floats: v==v is 1. */ \
- if(hasblank[i]) \
+ if(p->hasblank[i]) \
use = ( b==b \
? ( a[i][j]!=b ? 1 : 0 ) /* Integer */ \
: ( a[i][j]==a[i][j] ? 1 : 0 ) ); /* Float */ \
@@ -876,13 +911,11 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
if(n) \
{ \
qsort(pixs, n, sizeof *pixs, QSORT_F); \
- *o++ = n%2 ? pixs[n/2] : (pixs[n/2] + pixs[n/2-1])/2 ; \
+ o[j] = n%2 ? pixs[n/2] : (pixs[n/2] + pixs[n/2-1])/2 ; \
} \
else \
- *o++=b; \
- ++j; \
+ o[j]=b; \
} \
- while(o<of); \
\
/* Clean up. */ \
free(pixs); \
@@ -894,49 +927,48 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
#define MULTIOPERAND_SIGCLIP(TYPE) { \
float *sarr; \
- size_t n, j=0; \
+ size_t n, j; \
gal_data_t *sclip; \
- TYPE *pixs=gal_pointer_allocate(list->type, dnum, 0, __func__, \
- "pixs"); \
- gal_data_t *cont=gal_data_alloc(pixs, list->type, 1, &dnum, NULL, \
- 0, -1, NULL, NULL, NULL); \
+ TYPE *pixs=gal_pointer_allocate(p->list->type, p->dnum, 0, \
+ __func__, "pixs"); \
+ gal_data_t *cont=gal_data_alloc(pixs, p->list->type, 1, &p->dnum, \
+ NULL, 0, -1, NULL, NULL, NULL); \
\
- /* Loop over each pixel */ \
- do \
+ /* Go over all the pixels assigned to this thread. */ \
+ for(tind=0; tprm->indexs[tind] != GAL_BLANK_SIZE_T; ++tind) \
{ \
- /* Initialize. */ \
+ /* Initialize, `j' is desired pixel's index. */ \
n=0; \
+ j=tprm->indexs[tind]; \
\
- /* Loop over each array. */ \
- for(i=0;i<dnum;++i) pixs[n++]=a[i][j]; \
+ /* Read the necessay values from each input. */ \
+ for(i=0;i<p->dnum;++i) pixs[n++]=a[i][j]; \
\
/* If there are any elements, measure the */ \
if(n) \
{ \
- sclip=gal_statistics_sigma_clip(cont, p1, p2, 1, 1); \
+ sclip=gal_statistics_sigma_clip(cont, p->p1, p->p2, 1, 1); \
sarr=sclip->array; \
- switch(operator) \
+ switch(p->operator) \
{ \
- case GAL_ARITHMETIC_OP_SIGCLIP_STD: *o++=sarr[3]; break;\
- case GAL_ARITHMETIC_OP_SIGCLIP_MEAN: *o++=sarr[2]; break;\
- case GAL_ARITHMETIC_OP_SIGCLIP_MEDIAN: *o++=sarr[1]; break;\
- case GAL_ARITHMETIC_OP_SIGCLIP_NUMBER: *o++=sarr[0]; break;\
+ case GAL_ARITHMETIC_OP_SIGCLIP_STD: o[j]=sarr[3]; break;\
+ case GAL_ARITHMETIC_OP_SIGCLIP_MEAN: o[j]=sarr[2]; break;\
+ case GAL_ARITHMETIC_OP_SIGCLIP_MEDIAN: o[j]=sarr[1]; break;\
+ case GAL_ARITHMETIC_OP_SIGCLIP_NUMBER: o[j]=sarr[0]; break;\
default: \
error(EXIT_FAILURE, 0, "%s: a bug! the code %d is not " \
"valid for sigma-clipping results", __func__, \
- operator); \
+ p->operator); \
} \
\
/* Since we are doing sigma-clipping in place, the size, */ \
/* and flags need to be reset. */ \
cont->flag=0; \
- cont->size=cont->dsize[0]=dnum; \
+ cont->size=cont->dsize[0]=p->dnum; \
} \
else \
- *o++=b; \
- ++j; \
+ o[j]=b; \
} \
- while(o<of); \
\
/* Clean up. */ \
gal_data_free(cont); \
@@ -947,25 +979,26 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
#define MULTIOPERAND_TYPE_SET(TYPE, QSORT_F) { \
- TYPE b, **a, *o=out->array, *of=o+out->size; \
- size_t i=0; /* Different from the `i' in the main function. */ \
+ gal_data_t *tmp; \
+ size_t i=0, tind; \
+ TYPE b, **a, *o=p->out->array; \
\
/* Allocate space to keep the pointers to the arrays of each. */ \
/* Input data structure. The operators will increment these */ \
/* pointers while parsing them. */ \
errno=0; \
- a=malloc(dnum*sizeof *a); \
+ a=malloc(p->dnum*sizeof *a); \
if(a==NULL) \
error(EXIT_FAILURE, 0, "%s: %zu bytes for `a'", \
- "MULTIOPERAND_TYPE_SET", dnum*sizeof *a); \
+ "MULTIOPERAND_TYPE_SET", p->dnum*sizeof *a); \
\
/* Fill in the array pointers and the blank value for this type. */ \
- gal_blank_write(&b, list->type); \
- for(tmp=list;tmp!=NULL;tmp=tmp->next) \
+ gal_blank_write(&b, p->list->type); \
+ for(tmp=p->list;tmp!=NULL;tmp=tmp->next) \
a[i++]=tmp->array; \
\
/* Do the operation. */ \
- switch(operator) \
+ switch(p->operator) \
{ \
case GAL_ARITHMETIC_OP_MIN: \
MULTIOPERAND_MIN(TYPE); \
@@ -1004,7 +1037,7 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
\
default: \
error(EXIT_FAILURE, 0, "%s: operator code %d not recognized", \
- "MULTIOPERAND_TYPE_SET", operator); \
+ "MULTIOPERAND_TYPE_SET", p->operator); \
} \
\
/* Clean up. */ \
@@ -1015,16 +1048,72 @@ arithmetic_where(int flags, gal_data_t *out, gal_data_t
*cond,
+/* Worker function on each thread. */
+void *
+multioperand_on_thread(void *in_prm)
+{
+ /* Low-level definitions to be done first. */
+ struct gal_threads_params *tprm=(struct gal_threads_params *)in_prm;
+ struct multioperandparams *p=(struct multioperandparams *)tprm->params;
+
+ /* Do the operation on each thread. */
+ switch(p->list->type)
+ {
+ case GAL_TYPE_UINT8:
+ MULTIOPERAND_TYPE_SET(uint8_t, gal_qsort_uint8_i);
+ break;
+ case GAL_TYPE_INT8:
+ MULTIOPERAND_TYPE_SET(int8_t, gal_qsort_int8_i);
+ break;
+ case GAL_TYPE_UINT16:
+ MULTIOPERAND_TYPE_SET(uint16_t, gal_qsort_uint16_i);
+ break;
+ case GAL_TYPE_INT16:
+ MULTIOPERAND_TYPE_SET(int16_t, gal_qsort_int16_i);
+ break;
+ case GAL_TYPE_UINT32:
+ MULTIOPERAND_TYPE_SET(uint32_t, gal_qsort_uint32_i);
+ break;
+ case GAL_TYPE_INT32:
+ MULTIOPERAND_TYPE_SET(int32_t, gal_qsort_int32_i);
+ break;
+ case GAL_TYPE_UINT64:
+ MULTIOPERAND_TYPE_SET(uint64_t, gal_qsort_uint64_i);
+ break;
+ case GAL_TYPE_INT64:
+ MULTIOPERAND_TYPE_SET(int64_t, gal_qsort_int64_i);
+ break;
+ case GAL_TYPE_FLOAT32:
+ MULTIOPERAND_TYPE_SET(float, gal_qsort_float32_i);
+ break;
+ case GAL_TYPE_FLOAT64:
+ MULTIOPERAND_TYPE_SET(double, gal_qsort_float64_i);
+ break;
+ default:
+ error(EXIT_FAILURE, 0, "%s: type code %d not recognized",
+ __func__, p->list->type);
+ }
+
+ /* Wait for all the other threads to finish, then return. */
+ if(tprm->b) pthread_barrier_wait(tprm->b);
+ return NULL;
+}
+
+
+
+
+
/* The single operator in this function is assumed to be a linked list. The
number of operators is determined from the fact that the last node in
the linked list must have a NULL pointer as its `next' element. */
static gal_data_t *
arithmetic_multioperand(int operator, int flags, gal_data_t *list,
- gal_data_t *params)
+ gal_data_t *params, size_t numthreads)
{
uint8_t *hasblank;
size_t i=0, dnum=1;
float p1=NAN, p2=NAN;
+ struct multioperandparams p;
gal_data_t *out, *tmp, *ttmp;
@@ -1087,43 +1176,16 @@ arithmetic_multioperand(int operator, int flags,
gal_data_t *list,
hasblank[i++]=gal_blank_present(tmp, 0);
- /* Start the operation. */
- switch(list->type)
- {
- case GAL_TYPE_UINT8:
- MULTIOPERAND_TYPE_SET(uint8_t, gal_qsort_uint8_i);
- break;
- case GAL_TYPE_INT8:
- MULTIOPERAND_TYPE_SET(int8_t, gal_qsort_int8_i);
- break;
- case GAL_TYPE_UINT16:
- MULTIOPERAND_TYPE_SET(uint16_t, gal_qsort_uint16_i);
- break;
- case GAL_TYPE_INT16:
- MULTIOPERAND_TYPE_SET(int16_t, gal_qsort_int16_i);
- break;
- case GAL_TYPE_UINT32:
- MULTIOPERAND_TYPE_SET(uint32_t, gal_qsort_uint32_i);
- break;
- case GAL_TYPE_INT32:
- MULTIOPERAND_TYPE_SET(int32_t, gal_qsort_int32_i);
- break;
- case GAL_TYPE_UINT64:
- MULTIOPERAND_TYPE_SET(uint64_t, gal_qsort_uint64_i);
- break;
- case GAL_TYPE_INT64:
- MULTIOPERAND_TYPE_SET(int64_t, gal_qsort_int64_i);
- break;
- case GAL_TYPE_FLOAT32:
- MULTIOPERAND_TYPE_SET(float, gal_qsort_float32_i);
- break;
- case GAL_TYPE_FLOAT64:
- MULTIOPERAND_TYPE_SET(double, gal_qsort_float64_i);
- break;
- default:
- error(EXIT_FAILURE, 0, "%s: type code %d not recognized",
- __func__, list->type);
- }
+ /* Set the parameters necessary for multithreaded operation and spin them
+ off to do apply the operator. */
+ p.p1=p1;
+ p.p2=p2;
+ p.out=out;
+ p.list=list;
+ p.dnum=dnum;
+ p.operator=operator;
+ p.hasblank=hasblank;
+ gal_threads_spin_off(multioperand_on_thread, &p, out->size, numthreads);
/* Clean up and return. Note that the operation might have been done in
@@ -1551,7 +1613,7 @@ gal_arithmetic_operator_string(int operator)
gal_data_t *
-gal_arithmetic(int operator, int flags, ...)
+gal_arithmetic(int operator, size_t numthreads, int flags, ...)
{
va_list va;
gal_data_t *d1, *d2, *d3, *out=NULL;
@@ -1641,7 +1703,7 @@ gal_arithmetic(int operator, int flags, ...)
case GAL_ARITHMETIC_OP_SIGCLIP_NUMBER:
d1 = va_arg(va, gal_data_t *);
d2 = va_arg(va, gal_data_t *);
- out=arithmetic_multioperand(operator, flags, d1, d2);
+ out=arithmetic_multioperand(operator, flags, d1, d2, numthreads);
break;
diff --git a/lib/gnuastro/arithmetic.h b/lib/gnuastro/arithmetic.h
index db65bc8..a1922c8 100644
--- a/lib/gnuastro/arithmetic.h
+++ b/lib/gnuastro/arithmetic.h
@@ -143,7 +143,7 @@ enum gal_arithmetic_operators
gal_data_t *
-gal_arithmetic(int operator, int flags, ...);
+gal_arithmetic(int operator, size_t numthreads, int flags, ...);
diff --git a/lib/options.c b/lib/options.c
index 8b34aea..10ae646 100644
--- a/lib/options.c
+++ b/lib/options.c
@@ -1337,11 +1337,11 @@ options_sanity_check(struct argp_option *option, char
*arg,
`GAL_ARITHMETIC_INPLACE' flags. But we will do this when there are
multiple checks so from the two check data structures, we only have
one remaining. */
- check1=gal_arithmetic(operator1, GAL_ARITHMETIC_NUMOK, value, ref1);
+ check1=gal_arithmetic(operator1, 1, GAL_ARITHMETIC_NUMOK, value, ref1);
if(ref2)
{
- check2=gal_arithmetic(operator2, GAL_ARITHMETIC_NUMOK, value, ref2);
- check1=gal_arithmetic(multicheckop, mcflag, check1, check2);
+ check2=gal_arithmetic(operator2, 1, GAL_ARITHMETIC_NUMOK, value, ref2);
+ check1=gal_arithmetic(multicheckop, 1, mcflag, check1, check2);
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnuastro-commits] master e65eb48: Arithmetic: multithreaded variable-operand operators,
Mohammad Akhlaghi <=