Skip to content

Commit

Permalink
REF: Use more conditional nogil & const memoryviews (#60955)
Browse files Browse the repository at this point in the history
* Use memoryview for count_level_2d

* Use more const memoryviews

* add more conditional nogil
  • Loading branch information
mroeschke authored Feb 18, 2025
1 parent 63249f2 commit 5b2cddb
Show file tree
Hide file tree
Showing 6 changed files with 18 additions and 76 deletions.
28 changes: 1 addition & 27 deletions pandas/_libs/algos.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -818,33 +818,7 @@ def is_monotonic(const numeric_object_t[:] arr, bint timelike):
if timelike and <int64_t>arr[0] == NPY_NAT:
return False, False, False

if numeric_object_t is not object:
with nogil:
prev = arr[0]
for i in range(1, n):
cur = arr[i]
if timelike and <int64_t>cur == NPY_NAT:
is_monotonic_inc = 0
is_monotonic_dec = 0
break
if cur < prev:
is_monotonic_inc = 0
elif cur > prev:
is_monotonic_dec = 0
elif cur == prev:
is_unique = 0
else:
# cur or prev is NaN
is_monotonic_inc = 0
is_monotonic_dec = 0
break
if not is_monotonic_inc and not is_monotonic_dec:
is_monotonic_inc = 0
is_monotonic_dec = 0
break
prev = cur
else:
# object-dtype, identical to above except we cannot use `with nogil`
with nogil(numeric_object_t is not object):
prev = arr[0]
for i in range(1, n):
cur = arr[i]
Expand Down
15 changes: 1 addition & 14 deletions pandas/_libs/hashtable_func_helper.pxi.in
Original file line number Diff line number Diff line change
Expand Up @@ -415,20 +415,7 @@ def mode(ndarray[htfunc_t] values, bint dropna, const uint8_t[:] mask=None):

modes = np.empty(nkeys, dtype=values.dtype)

if htfunc_t is not object:
with nogil:
for k in range(nkeys):
count = counts[k]
if count == max_count:
j += 1
elif count > max_count:
max_count = count
j = 0
else:
continue

modes[j] = keys[k]
else:
with nogil(htfunc_t is not object):
for k in range(nkeys):
count = counts[k]
if count == max_count:
Expand Down
6 changes: 3 additions & 3 deletions pandas/_libs/internals.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ def get_concat_blkno_indexers(list blknos_list not None):
@cython.boundscheck(False)
@cython.wraparound(False)
def get_blkno_indexers(
int64_t[:] blknos, bint group=True
const int64_t[:] blknos, bint group=True
) -> list[tuple[int, slice | np.ndarray]]:
"""
Enumerate contiguous runs of integers in ndarray.
Expand Down Expand Up @@ -596,8 +596,8 @@ def get_blkno_placements(blknos, group: bool = True):
@cython.boundscheck(False)
@cython.wraparound(False)
cpdef update_blklocs_and_blknos(
ndarray[intp_t, ndim=1] blklocs,
ndarray[intp_t, ndim=1] blknos,
const intp_t[:] blklocs,
const intp_t[:] blknos,
Py_ssize_t loc,
intp_t nblocks,
):
Expand Down
17 changes: 10 additions & 7 deletions pandas/_libs/join.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,10 @@ def full_outer_join(const intp_t[:] left, const intp_t[:] right,

@cython.wraparound(False)
@cython.boundscheck(False)
cdef void _get_result_indexer(intp_t[::1] sorter, intp_t[::1] indexer) noexcept nogil:
cdef void _get_result_indexer(
const intp_t[::1] sorter,
intp_t[::1] indexer,
) noexcept nogil:
"""NOTE: overwrites indexer with the result to avoid allocating another array"""
cdef:
Py_ssize_t i, n, idx
Expand Down Expand Up @@ -681,8 +684,8 @@ def outer_join_indexer(ndarray[numeric_object_t] left, ndarray[numeric_object_t]
from pandas._libs.hashtable cimport Int64HashTable


def asof_join_backward_on_X_by_Y(ndarray[numeric_t] left_values,
ndarray[numeric_t] right_values,
def asof_join_backward_on_X_by_Y(const numeric_t[:] left_values,
const numeric_t[:] right_values,
const int64_t[:] left_by_values,
const int64_t[:] right_by_values,
bint allow_exact_matches=True,
Expand Down Expand Up @@ -752,8 +755,8 @@ def asof_join_backward_on_X_by_Y(ndarray[numeric_t] left_values,
return left_indexer, right_indexer


def asof_join_forward_on_X_by_Y(ndarray[numeric_t] left_values,
ndarray[numeric_t] right_values,
def asof_join_forward_on_X_by_Y(const numeric_t[:] left_values,
const numeric_t[:] right_values,
const int64_t[:] left_by_values,
const int64_t[:] right_by_values,
bint allow_exact_matches=1,
Expand Down Expand Up @@ -824,8 +827,8 @@ def asof_join_forward_on_X_by_Y(ndarray[numeric_t] left_values,
return left_indexer, right_indexer


def asof_join_nearest_on_X_by_Y(ndarray[numeric_t] left_values,
ndarray[numeric_t] right_values,
def asof_join_nearest_on_X_by_Y(const numeric_t[:] left_values,
const numeric_t[:] right_values,
const int64_t[:] left_by_values,
const int64_t[:] right_by_values,
bint allow_exact_matches=True,
Expand Down
6 changes: 2 additions & 4 deletions pandas/_libs/lib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -981,16 +981,14 @@ def get_level_sorter(

@cython.boundscheck(False)
@cython.wraparound(False)
def count_level_2d(ndarray[uint8_t, ndim=2, cast=True] mask,
def count_level_2d(const uint8_t[:, :] mask,
const intp_t[:] labels,
Py_ssize_t max_bin,
):
cdef:
Py_ssize_t i, j, k, n
Py_ssize_t i, j, k = mask.shape[1], n = mask.shape[0]
ndarray[int64_t, ndim=2] counts

n, k = (<object>mask).shape

counts = np.zeros((n, max_bin), dtype="i8")
with nogil:
for i in range(n):
Expand Down
22 changes: 1 addition & 21 deletions pandas/_libs/reshape.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -40,27 +40,7 @@ def unstack(const numeric_object_t[:, :] values, const uint8_t[:] mask,
cdef:
Py_ssize_t i, j, w, nulls, s, offset

if numeric_object_t is not object:
# evaluated at compile-time
with nogil:
for i in range(stride):

nulls = 0
for j in range(length):

for w in range(width):

offset = j * width + w

if mask[offset]:
s = i * width + w
new_values[j, s] = values[offset - nulls, i]
new_mask[j, s] = 1
else:
nulls += 1

else:
# object-dtype, identical to above but we cannot use nogil
with nogil(numeric_object_t is not object):
for i in range(stride):

nulls = 0
Expand Down

0 comments on commit 5b2cddb

Please sign in to comment.