summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorda-woods <dw-git@d-woods.co.uk>2023-03-20 09:38:44 +0000
committerGitHub <noreply@github.com>2023-03-20 10:38:44 +0100
commit7bb7ff04cac4047cb425acbf4e53cc94bc396c0a (patch)
tree8c87d595f1ec8c40114a7c135ae2e5de4661fb4b
parentc8b434c6041de474998fa3a9e779b8340c5b1f71 (diff)
downloadcython-7bb7ff04cac4047cb425acbf4e53cc94bc396c0a.tar.gz
Fix exception handling in memoryview utilitycode (GH-5325)
The new exception-handling semantics meant that the utility code always had to check for exceptions on some void nogil functions (requiring us to re-acquire the GIL). This made performance noticeably worse under some circumstances. Fix this by making the exception specifications noexcept for quite a few cdef functions in the memoryview utility code. Fixes https://github.com/cython/cython/issues/5324
-rw-r--r--Cython/Utility/MemoryView.pyx29
-rw-r--r--tests/compile/fused_redeclare_T3111.pyx12
-rw-r--r--tests/errors/pure_warnings.py6
-rw-r--r--tests/memoryview/memoryview_no_withgil_check.pyx11
4 files changed, 35 insertions, 23 deletions
diff --git a/Cython/Utility/MemoryView.pyx b/Cython/Utility/MemoryView.pyx
index f9ab51663..7ffcbb58e 100644
--- a/Cython/Utility/MemoryView.pyx
+++ b/Cython/Utility/MemoryView.pyx
@@ -318,7 +318,7 @@ cdef indirect_contiguous = Enum("<contiguous and indirect>")
@cname('__pyx_align_pointer')
-cdef void *align_pointer(void *memory, size_t alignment) nogil:
+cdef void *align_pointer(void *memory, size_t alignment) noexcept nogil:
"Align pointer memory on a given boundary"
cdef Py_intptr_t aligned_p = <Py_intptr_t> memory
cdef size_t offset
@@ -679,7 +679,7 @@ cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeIn
return result
@cname('__pyx_memoryview_check')
-cdef inline bint memoryview_check(object o):
+cdef inline bint memoryview_check(object o) noexcept:
return isinstance(o, memoryview)
cdef tuple _unellipsify(object index, int ndim):
@@ -711,10 +711,11 @@ cdef tuple _unellipsify(object index, int ndim):
nslices = ndim - idx
return have_slices or nslices, tuple(result)
-cdef assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim):
+cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1:
for suboffset in suboffsets[:ndim]:
if suboffset >= 0:
raise ValueError, "Indirect dimensions not supported"
+ return 0 # return type just used as an error flag
#
### Slicing a memoryview
@@ -1073,7 +1074,7 @@ cdef {{memviewslice_name}} *get_slice_from_memview(memoryview memview,
return mslice
@cname('__pyx_memoryview_slice_copy')
-cdef void slice_copy(memoryview memview, {{memviewslice_name}} *dst):
+cdef void slice_copy(memoryview memview, {{memviewslice_name}} *dst) noexcept:
cdef int dim
cdef (Py_ssize_t*) shape, strides, suboffsets
@@ -1119,11 +1120,11 @@ cdef memoryview_copy_from_slice(memoryview memview, {{memviewslice_name}} *memvi
#
### Copy the contents of a memoryview slices
#
-cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) nogil:
+cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) noexcept nogil:
return -arg if arg < 0 else arg
@cname('__pyx_get_best_slice_order')
-cdef char get_best_order({{memviewslice_name}} *mslice, int ndim) nogil:
+cdef char get_best_order({{memviewslice_name}} *mslice, int ndim) noexcept nogil:
"""
Figure out the best memory access order for a given slice.
"""
@@ -1150,7 +1151,7 @@ cdef char get_best_order({{memviewslice_name}} *mslice, int ndim) nogil:
cdef void _copy_strided_to_strided(char *src_data, Py_ssize_t *src_strides,
char *dst_data, Py_ssize_t *dst_strides,
Py_ssize_t *src_shape, Py_ssize_t *dst_shape,
- int ndim, size_t itemsize) nogil:
+ int ndim, size_t itemsize) noexcept nogil:
# Note: src_extent is 1 if we're broadcasting
# dst_extent always >= src_extent as we don't do reductions
cdef Py_ssize_t i
@@ -1179,7 +1180,7 @@ cdef void _copy_strided_to_strided(char *src_data, Py_ssize_t *src_strides,
cdef void copy_strided_to_strided({{memviewslice_name}} *src,
{{memviewslice_name}} *dst,
- int ndim, size_t itemsize) nogil:
+ int ndim, size_t itemsize) noexcept nogil:
_copy_strided_to_strided(src.data, src.strides, dst.data, dst.strides,
src.shape, dst.shape, ndim, itemsize)
@@ -1196,7 +1197,7 @@ cdef Py_ssize_t slice_get_size({{memviewslice_name}} *src, int ndim) noexcept no
@cname('__pyx_fill_contig_strides_array')
cdef Py_ssize_t fill_contig_strides_array(
Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t stride,
- int ndim, char order) nogil:
+ int ndim, char order) noexcept nogil:
"""
Fill the strides array for a slice with C or F contiguous strides.
This is like PyBuffer_FillContiguousStrides, but compatible with py < 2.6
@@ -1349,7 +1350,7 @@ cdef int memoryview_copy_contents({{memviewslice_name}} src,
@cname('__pyx_memoryview_broadcast_leading')
cdef void broadcast_leading({{memviewslice_name}} *mslice,
int ndim,
- int ndim_other) nogil:
+ int ndim_other) noexcept nogil:
cdef int i
cdef int offset = ndim_other - ndim
@@ -1369,7 +1370,7 @@ cdef void broadcast_leading({{memviewslice_name}} *mslice,
#
@cname('__pyx_memoryview_refcount_copying')
-cdef void refcount_copying({{memviewslice_name}} *dst, bint dtype_is_object, int ndim, bint inc) nogil:
+cdef void refcount_copying({{memviewslice_name}} *dst, bint dtype_is_object, int ndim, bint inc) noexcept nogil:
# incref or decref the objects in the destination slice if the dtype is object
if dtype_is_object:
refcount_objects_in_slice_with_gil(dst.data, dst.shape, dst.strides, ndim, inc)
@@ -1377,7 +1378,7 @@ cdef void refcount_copying({{memviewslice_name}} *dst, bint dtype_is_object, int
@cname('__pyx_memoryview_refcount_objects_in_slice_with_gil')
cdef void refcount_objects_in_slice_with_gil(char *data, Py_ssize_t *shape,
Py_ssize_t *strides, int ndim,
- bint inc) with gil:
+ bint inc) noexcept with gil:
refcount_objects_in_slice(data, shape, strides, ndim, inc)
@cname('__pyx_memoryview_refcount_objects_in_slice')
@@ -1403,7 +1404,7 @@ cdef void refcount_objects_in_slice(char *data, Py_ssize_t *shape,
@cname('__pyx_memoryview_slice_assign_scalar')
cdef void slice_assign_scalar({{memviewslice_name}} *dst, int ndim,
size_t itemsize, void *item,
- bint dtype_is_object) nogil:
+ bint dtype_is_object) noexcept nogil:
refcount_copying(dst, dtype_is_object, ndim, inc=False)
_slice_assign_scalar(dst.data, dst.shape, dst.strides, ndim, itemsize, item)
refcount_copying(dst, dtype_is_object, ndim, inc=True)
@@ -1412,7 +1413,7 @@ cdef void slice_assign_scalar({{memviewslice_name}} *dst, int ndim,
@cname('__pyx_memoryview__slice_assign_scalar')
cdef void _slice_assign_scalar(char *data, Py_ssize_t *shape,
Py_ssize_t *strides, int ndim,
- size_t itemsize, void *item) nogil:
+ size_t itemsize, void *item) noexcept nogil:
cdef Py_ssize_t i
cdef Py_ssize_t stride = strides[0]
cdef Py_ssize_t extent = shape[0]
diff --git a/tests/compile/fused_redeclare_T3111.pyx b/tests/compile/fused_redeclare_T3111.pyx
index 5d1672198..53f087717 100644
--- a/tests/compile/fused_redeclare_T3111.pyx
+++ b/tests/compile/fused_redeclare_T3111.pyx
@@ -27,10 +27,10 @@ _WARNINGS = """
36:10: 'cpdef_cname_method' redeclared
# from MemoryView.pyx
-979:29: Ambiguous exception value, same as default return value: 0
-979:29: Ambiguous exception value, same as default return value: 0
-1020:46: Ambiguous exception value, same as default return value: 0
-1020:46: Ambiguous exception value, same as default return value: 0
-1110:29: Ambiguous exception value, same as default return value: 0
-1110:29: Ambiguous exception value, same as default return value: 0
+980:29: Ambiguous exception value, same as default return value: 0
+980:29: Ambiguous exception value, same as default return value: 0
+1021:46: Ambiguous exception value, same as default return value: 0
+1021:46: Ambiguous exception value, same as default return value: 0
+1111:29: Ambiguous exception value, same as default return value: 0
+1111:29: Ambiguous exception value, same as default return value: 0
"""
diff --git a/tests/errors/pure_warnings.py b/tests/errors/pure_warnings.py
index 40104bc48..3109439cb 100644
--- a/tests/errors/pure_warnings.py
+++ b/tests/errors/pure_warnings.py
@@ -49,9 +49,9 @@ _WARNINGS = """
# Spurious warnings from utility code - not part of the core test
25:10: 'cpdef_method' redeclared
36:10: 'cpdef_cname_method' redeclared
-979:29: Ambiguous exception value, same as default return value: 0
-1020:46: Ambiguous exception value, same as default return value: 0
-1110:29: Ambiguous exception value, same as default return value: 0
+980:29: Ambiguous exception value, same as default return value: 0
+1021:46: Ambiguous exception value, same as default return value: 0
+1111:29: Ambiguous exception value, same as default return value: 0
"""
_ERRORS = """
diff --git a/tests/memoryview/memoryview_no_withgil_check.pyx b/tests/memoryview/memoryview_no_withgil_check.pyx
new file mode 100644
index 000000000..4753bab12
--- /dev/null
+++ b/tests/memoryview/memoryview_no_withgil_check.pyx
@@ -0,0 +1,11 @@
+# mode: compile
+
+# cython: test_fail_if_c_code_has = __Pyx_ErrOccurredWithGIL
+
+# cython-generated memoryview code shouldn't resort to
+# __Pyx_ErrOccurredWithGIL for error checking (because it's inefficient
+# inside a nogil block)
+
+def assign(double[:] a, double[:] b):
+ with nogil:
+ a[:] = b[:]