Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions python/ray/_raylet.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ cdef extern from "Python.h":
ctypedef struct CPyThreadState "PyThreadState":
int recursion_limit
int recursion_remaining
int c_recursion_remaining
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This field exists in all Python versions?

Copy link
Contributor Author

@dayshah dayshah Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no it doesn't but having it here doesn't cause any issues even if used with old python versions

recursion_limit and recursion_remaining also don't exist for all python versions

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, interesting


# From Include/ceveal.h#67
int Py_GetRecursionLimit()
Expand Down
64 changes: 49 additions & 15 deletions python/ray/_raylet.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -679,29 +679,63 @@ def compute_task_id(ObjectRef object_ref):


cdef increase_recursion_limit():
"""Double the recusion limit if current depth is close to the limit"""
"""
Ray does some weird things with asio fibers and asyncio to run asyncio actors.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Killing boost fiber is on the @edoakes's wishlist

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ya ik I talked to him about it, he said he's gonna try prioritizing next quarter 👀

This results in the Python interpreter thinking there's a lot of recursion depth,
so we need to increase the limit when we start getting close.

0x30C0000 is Python 3.12
On 3.12, when recursion depth increases, c_recursion_remaining will decrease,
and that's what's actually compared to raise a RecursionError. So increasing
it by 1000 when it drops below 1000 will keep us from raising the RecursionError.
https://github.com/python/cpython/blob/bfb9e2f4a4e690099ec2ec53c08b90f4d64fde36/Python/pystate.c#L1353
0x30B00A4 is Python 3.11
On 3.11, the recursion depth can be calculated with recursion_limit - recursion_remaining.
We can get the current limit with Py_GetRecursionLimit and set it with Py_SetRecursionLimit.
We'll double the limit when there's less than 500 remaining.
On older versions
There's simply a recursion_depth variable and we'll increase the max the same
way we do for 3.11.
"""
cdef:
CPyThreadState * s = <CPyThreadState *> PyThreadState_Get()
int current_limit = Py_GetRecursionLimit()
int new_limit = current_limit * 2
cdef extern from *:
"""
#if PY_VERSION_HEX >= 0x30C0000
#define CURRENT_DEPTH(x) ((x)->py_recursion_limit - (x)->py_recursion_remaining)
bool IncreaseRecursionLimitIfNeeded(PyThreadState *x) {
if (x->c_recursion_remaining < 1000) {
x->c_recursion_remaining += 1000;
return true;
}
return false;
}
#elif PY_VERSION_HEX >= 0x30B00A4
#define CURRENT_DEPTH(x) ((x)->recursion_limit - (x)->recursion_remaining)
bool IncreaseRecursionLimitIfNeeded(PyThreadState *x) {
int current_limit = Py_GetRecursionLimit();
int current_depth = x->recursion_limit - x->recursion_remaining;
if (current_limit - current_depth < 500) {
Py_SetRecursionLimit(current_limit * 2);
return true;
}
return false;
}
#else
#define CURRENT_DEPTH(x) ((x)->recursion_depth)
bool IncreaseRecursionLimitIfNeeded(PyThreadState *x) {
int current_limit = Py_GetRecursionLimit();
if (current_limit - x->recursion_depth < 500) {
Py_SetRecursionLimit(current_limit * 2);
return true;
}
return false;
}
#endif
"""
int CURRENT_DEPTH(CPyThreadState *x)

int current_depth = CURRENT_DEPTH(s)
if current_limit - current_depth < 500:
Py_SetRecursionLimit(new_limit)
logger.debug("Increasing Python recursion limit to {} "
"current recursion depth is {}.".format(
new_limit, current_depth))
c_bool IncreaseRecursionLimitIfNeeded(CPyThreadState *x)

CPyThreadState * s = <CPyThreadState *> PyThreadState_Get()
c_bool increased_recursion_limit = IncreaseRecursionLimitIfNeeded(s)

if increased_recursion_limit:
logger.debug("Increased Python recursion limit")


cdef CObjectLocationPtrToDict(CObjectLocation* c_object_location):
Expand Down