-
-
Notifications
You must be signed in to change notification settings - Fork 11.1k
ENH: Configurable allocator #17582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: Configurable allocator #17582
Changes from 1 commit
55f2f6c
23da73e
94b9f25
81b45fd
fc32c2f
de22327
38274a4
59b520a
5264019
7c396d7
de9001c
9e7c3ed
953cc88
ad9329b
6d10fdb
18bea05
4368023
d243313
c9b6854
a8fd378
a17565b
2ec5912
227c4b8
fb8135d
7291484
c7a9c22
99f8250
b43c1fe
a7a5435
e3723df
144acc6
8539f5f
6ab00d0
e7e8754
5f08532
7266029
5d547ff
4617c50
8f739c4
90205b6
5c0d3f9
3b385d9
e6e12a3
048552d
ad6f8ad
50f8b93
c7438f5
f823ba4
ad13161
0a08acd
1f0301d
3d56aa0
8ea68
8000
18
fb2af4d
f05a1c6
660e0a4
a4f8d71
d7b1a1d
ab1a0eb
b92e36c
76cda3a
3eadf2f
dbe9d73
1bfb870
0511820
23c4bc0
ed8649b
9aacefa
79712fa
a2ae4c0
09b9c0d
efb3c77
2945c64
3a97d9a
1df805c
ef607bd
8bdc9a1
a3256e5
4d6ea65
5941d7c
522c368
442b0e1
8ca8b54
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -386,7 +386,7 @@ PyDataMem_Handler default_handler = { | |
} | ||
}; | ||
|
||
PyDataMem_Handler *current_handler = &default_handler; | ||
PyObject *current_handler; | ||
|
||
int uo_index=0; /* user_override index */ | ||
|
||
|
@@ -470,50 +470,77 @@ PyDataMem_UserRENEW(void *ptr, size_t size, const PyDataMemAllocator *allocator) | |
} | ||
|
||
/*NUMPY_API | ||
* Sets a new allocation policy. If the input value is NULL, will reset | ||
* the policy to the default. Returns the previous policy. We wrap | ||
* the user-provided functions so they will still call the python | ||
* and numpy memory management callback hooks. | ||
* Set a new allocation policy. If the input value is NULL, will reset | ||
* the policy to the default. Return the previous policy, or set an exception | ||
* and return NULL if an error has occurred. We wrap the user-provided | ||
* functions so they will still call the python and numpy | ||
* memory management callback hooks. | ||
*/ | ||
NPY_NO_EXPORT const PyDataMem_Handler * | ||
PyDataMem_SetHandler(PyDataMem_Handler *handler) | ||
{ | ||
const PyDataMem_Handler *old = current_handler; | ||
PyObject *capsule; | ||
PyObject *old_capsule; | ||
PyDataMem_Handler *old_handler; | ||
PyObject *token; | ||
if (PyContextVar_Get(current_handler, NULL, &old_capsule)) { | ||
return NULL; | ||
} | ||
old_handler = (PyDataMem_Handler *) PyCapsule_GetPointer(old_capsule, NULL); | ||
if (old_handler == NULL) { | ||
return NULL; | ||
} | ||
if (handler) { | ||
current_handler = handler; | ||
capsule = PyCapsule_New(handler, NULL, NULL); | ||
if (capsule == NULL) { | ||
return NULL; | ||
} | ||
} | ||
else { | ||
current_handler = &default_handler; | ||
capsule = PyCapsule_New(&default_handler, NULL, NULL); | ||
if (capsule == NULL) { | ||
return NULL; | ||
} | ||
} | ||
return old; | ||
token = PyContextVar_Set(current_handler, capsule); | ||
if (token == NULL) { | ||
Py_DECREF(capsule); | ||
return NULL; | ||
} | ||
Py_DECREF(old_capsule); | ||
Py_DECREF(token); | ||
return old_handler; | ||
} | ||
|
||
/*NUMPY_API | ||
* Return the const char name of the PyDataMem_Handler used by the | ||
* PyArrayObject or its base. If neither the PyArrayObject owns its own data | ||
* nor its base is a PyArrayObject which owns its own data return an empty string. | ||
* If NULL, return the name of the current global policy that | ||
* will be used to allocate data for the next PyArrayObject. | ||
* Return the PyDataMem_Handler used by the PyArrayObject. If NULL, return | ||
* the current global policy that ill be used to allocate data | ||
* for the next PyArrayObject. On failure, set an exception and return NULL. | ||
*/ | ||
NPY_NO_EXPORT const char * | ||
PyDataMem_GetHandlerName(PyArrayObject *obj) | ||
NPY_NO_EXPORT PyDataMem_Handler * | ||
PyDataMem_GetHandler(PyArrayObject *obj) | ||
{ | ||
PyObject *base; | ||
PyObject *capsule; | ||
PyDataMem_Handler *handler; | ||
if (obj == NULL) { | ||
return current_handler->name; | ||
if (PyContextVar_Get(current_handler, NULL, &capsule)) { | ||
return NULL; | ||
} | ||
return (PyDataMem_Handler *) PyCapsule_GetPointer(capsule, NULL); | ||
} | ||
PyDataMem_Handler *handler; | ||
/* If there's a handler, the array owns its own datay */ | ||
handler = PyArray_HANDLER(obj); | ||
if (handler != NULL) { | ||
return handler->name; | ||
} | ||
PyObject *base = PyArray_BASE(obj); | ||
if (base != NULL && PyArray_Check(base)) { | ||
handler = PyArray_HANDLER((PyArrayObject *) base); | ||
if (handler != NULL) { | ||
return handler->name; | ||
if (handler == NULL) { | ||
/* | ||
* If the base is an array which owns its own data, return its allocator. | ||
*/ | ||
base = PyArray_BASE(obj); | ||
if (base != NULL && PyArray_Check(base) && PyArray_CHKFLAGS(base, NPY_ARRAY_OWNDATA)) { | ||
return PyArray_HANDLER(base); | ||
} | ||
} | ||
return ""; | ||
return handler; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we then just export There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there is still this scenario that justifies having an
Now I want to know, for debugging purposes, whether handler There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently:
Based on these two facts, why can't we make To summarize the API would look like this:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Of course, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. got it. Adopted |
||
|
||
NPY_NO_EXPORT PyObject * | ||
|
@@ -527,12 +554,9 @@ get_handler_name(PyObject *NPY_UNUSED(self), PyObject *args) | |
PyErr_SetString(PyExc_ValueError, "if supplied, argument must be an ndarray"); | ||
return NULL; | ||
} | ||
const char * name = PyDataMem_GetHandlerName((PyArrayObject *)arr); | ||
if (name == NULL) { | ||
const PyDataMem_Handler * mem_handler = PyDataMem_GetHandler((PyArrayObject *)arr); | ||
if (mem_handler == NULL) { | ||
return NULL; | ||
} | ||
else if (strlen(name) == 0) { | ||
Py_RETURN_NONE; | ||
} | ||
return PyUnicode_FromString(name); | ||
return PyUnicode_FromString(mem_handler->name); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3082,6 +3082,7 @@ UNICODE_compare(npy_ucs4 *ip1, npy_ucs4 *ip2, | |
static int | ||
VOID_compare(char *ip1, char *ip2, PyArrayObject *ap) | ||
{ | ||
PyDataMem_Handler *mem_handler; | ||
PyArray_Descr *descr; | ||
PyObject *names, *key; | ||
PyObject *tup; | ||
|
@@ -3093,6 +3094,12 @@ VOID_compare(char *ip1, char *ip2, PyArrayObject *ap) | |
if (!PyArray_HASFIELDS(ap)) { | ||
return STRING_compare(ip1, ip2, ap); | ||
} | ||
mem_handler = PyDataMem_GetHandler(NULL); | ||
if (mem_handler == NULL) { | ||
/* Better fallback to default than goto finish. */ | ||
PyErr_Clear(); | ||
mem_handler = &default_handler; | ||
} | ||
descr = PyArray_DESCR(ap); | ||
/* | ||
* Compare on the first-field. If equal, then | ||
|
@@ -3119,7 +3126,7 @@ VOID_compare(char *ip1, char *ip2, PyArrayObject *ap) | |
* create temporary buffer and copy, | ||
* always use the current handler for internal allocations | ||
*/ | ||
nip1 = PyDataMem_UserNEW(new->elsize, ¤t_handler->allocator); | ||
nip1 = PyDataMem_UserNEW(new->elsize, &mem_handler->allocator); | ||
if (nip1 == NULL) { | ||
goto finish; | ||
} | ||
|
@@ -3132,12 +3139,12 @@ VOID_compare(char *ip1, char *ip2, PyArrayObject *ap) | |
* create temporary buffer and copy, | ||
* always use the current handler for internal allocations | ||
*/ | ||
nip2 = PyDataMem_UserNEW(new->elsize, ¤t_handler->allocator); | ||
nip2 = PyDataMem_UserNEW(new->elsize, &mem_handler->allocator); | ||
if (nip2 == NULL) { | ||
if (nip1 != ip1 + offset) { | ||
/* destroy temporary buffer */ | ||
PyDataMem_UserFREE(nip1, new->elsize, | ||
¤t_handler->allocator); | ||
&mem_handler->allocator); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting, I have been using the python allocators sometimes for this type of buffers (i.e. in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't want to do this dance:
Do you think it is worthwhile? This pattern occurs in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know. I started using the Python allocators for temporary allocations (since ABI doesn't matter), but with this work there may also be some use in honoring the current allocator (i.e. it will end up on the same memory region?). In any case, I don't think we have to worry about it right now. |
||
} | ||
goto finish; | ||
} | ||
|
@@ -3150,11 +3157,11 @@ VOID_compare(char *ip1, char *ip2, PyArrayObject *ap) | |
if (swap || new->alignment > 1) { | ||
if (nip1 != ip1 + offset) { | ||
/* destroy temporary buffer */ | ||
PyDataMem_UserFREE(nip1, new->elsize, ¤t_handler->allocator); | ||
PyDataMem_UserFREE(nip1, new->elsize, &mem_handler->allocator); | ||
} | ||
if (nip2 != ip2 + offset) { | ||
/* destroy temporary buffer */ | ||
PyDataMem_UserFREE(nip2, new->elsize, ¤t_handler->allocator); | ||
PyDataMem_UserFREE(nip2, new->elsize, &mem_handler->allocator); | ||
} | ||
} | ||
if (res != 0) { | ||
|
Uh oh!
There was an error while loading. Please reload this page.