summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2016-02-05 22:47:22 +0100
committerSebastian Berg <sebastian@sipsolutions.net>2016-03-17 13:15:04 +0100
commit19655d1d80f299bd76982d485b74aa8b4b0018d6 (patch)
tree29df4716651895d27f7e5cd57c76af0767bf9021
parent1429c606643d1ad305e710c4a31cb6f398d04c53 (diff)
downloadnumpy-19655d1d80f299bd76982d485b74aa8b4b0018d6.tar.gz
ENH: Unlock the GIL for gufuncs
-rw-r--r--doc/release/1.12.0-notes.rst5
-rw-r--r--numpy/core/src/umath/ufunc_object.c19
2 files changed, 24 insertions, 0 deletions
diff --git a/doc/release/1.12.0-notes.rst b/doc/release/1.12.0-notes.rst
index 38e5e4338..319ea2e6a 100644
--- a/doc/release/1.12.0-notes.rst
+++ b/doc/release/1.12.0-notes.rst
@@ -145,6 +145,11 @@ masked out when the reduce method was used. The new identity is -1, which
should work properly on twos complement machines as all bits will be set to
one.
+Generalized Ufuncs will now unlock the GIL
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Generalized Ufuncs, including most of the linalg module, will now unlock
+the Python global interpreter lock.
+
Changes
=======
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index c4a2b8560..6eb0aae55 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -1951,6 +1951,7 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
npy_intp iter_shape[NPY_MAXARGS];
NpyIter *iter = NULL;
npy_uint32 iter_flags;
+ npy_intp total_problem_size;
/* These parameters come from extobj= or from a TLS global */
int buffersize = 0, errormask = 0;
@@ -2346,6 +2347,16 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
}
}
+ total_problem_size = NpyIter_GetIterSize(iter);
+ if (total_problem_size < 0) {
+ /*
+ * Only used for threading, if negative (this means that it is
+ * larger then ssize_t before axes removal) assume that the actual
+ * problem is large enough to be threaded usefully.
+ */
+ total_problem_size = 1000;
+ }
+
/* Remove all the core output dimensions from the iterator */
for (i = broadcast_ndim; i < iter_ndim; ++i) {
if (NpyIter_RemoveAxis(iter, broadcast_ndim) != NPY_SUCCEED) {
@@ -2387,6 +2398,7 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
NpyIter_IterNextFunc *iternext;
char **dataptr;
npy_intp *count_ptr;
+ NPY_BEGIN_THREADS_DEF;
/* Get the variables needed for the loop */
iternext = NpyIter_GetIterNext(iter, NULL);
@@ -2397,10 +2409,17 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
dataptr = NpyIter_GetDataPtrArray(iter);
count_ptr = NpyIter_GetInnerLoopSizePtr(iter);
+ if (!needs_api && !NpyIter_IterationNeedsAPI(iter)) {
+ NPY_BEGIN_THREADS_THRESHOLDED(total_problem_size);
+ }
do {
inner_dimensions[0] = *count_ptr;
innerloop(dataptr, inner_dimensions, inner_strides, innerloopdata);
} while (iternext(iter));
+
+ if (!needs_api && !NpyIter_IterationNeedsAPI(iter)) {
+ NPY_END_THREADS;
+ }
} else {
/**
* For each output operand, check if it has non-zero size,