diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2013-12-04 00:29:35 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2013-12-04 00:29:35 (GMT) |
commit | 1511680b79c1d959e1186df4d19a9a93881b128d (patch) | |
tree | 57a4d0d4ca42e0d65bda873491397553873ea79b /Modules/_tracemalloc.c | |
parent | 9a954838aba9385618642342828b9dd7c21851d3 (diff) | |
download | cpython-1511680b79c1d959e1186df4d19a9a93881b128d.zip cpython-1511680b79c1d959e1186df4d19a9a93881b128d.tar.gz cpython-1511680b79c1d959e1186df4d19a9a93881b128d.tar.bz2 |
Close #19757: Cleanup tracemalloc, move
PyGILState_Ensure()/PyGILState_Release() calls to the raw wrappers to simplify
the code.
Rename also tracemalloc_log_alloc/log_free() to
tracemalloc_add_trace/remove_trace().
Diffstat (limited to 'Modules/_tracemalloc.c')
-rw-r--r-- | Modules/_tracemalloc.c | 227 |
1 files changed, 129 insertions, 98 deletions
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index 7b88a74..3aaeee0 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -439,7 +439,7 @@ traceback_new(void) } static int -tracemalloc_log_alloc(void *ptr, size_t size) +tracemalloc_add_trace(void *ptr, size_t size) { traceback_t *traceback; trace_t trace; @@ -470,7 +470,7 @@ tracemalloc_log_alloc(void *ptr, size_t size) } static void -tracemalloc_log_free(void *ptr) +tracemalloc_remove_trace(void *ptr) { trace_t trace; @@ -483,118 +483,57 @@ tracemalloc_log_free(void *ptr) } static void* -tracemalloc_malloc(void *ctx, size_t size, int gil_held) +tracemalloc_malloc(void *ctx, size_t size) { PyMemAllocator *alloc = (PyMemAllocator *)ctx; -#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD) - PyGILState_STATE gil_state; -#endif void *ptr; - if (get_reentrant()) { - return alloc->malloc(alloc->ctx, size); - } - - /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() - for allocations larger than 512 bytes. PyGILState_Ensure() may call - PyMem_RawMalloc() indirectly which would call PyGILState_Ensure() if - reentrant are not disabled. */ - set_reentrant(1); -#ifdef WITH_THREAD -#ifdef TRACE_RAW_MALLOC - if (!gil_held) - gil_state = PyGILState_Ensure(); -#else - assert(gil_held); -#endif -#endif ptr = alloc->malloc(alloc->ctx, size); + if (ptr == NULL) + return NULL; - if (ptr != NULL) { - if (tracemalloc_log_alloc(ptr, size) < 0) { - /* Memory allocation failed */ - alloc->free(alloc->ctx, ptr); - ptr = NULL; - } + if (tracemalloc_add_trace(ptr, size) < 0) { + /* Failed to allocate a trace for the new memory block */ + alloc->free(alloc->ctx, ptr); + return NULL; } - set_reentrant(0); - -#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD) - if (!gil_held) - PyGILState_Release(gil_state); -#endif - return ptr; } static void* -tracemalloc_realloc(void *ctx, void *ptr, size_t new_size, int gil_held) +tracemalloc_realloc(void *ctx, void *ptr, size_t new_size) { PyMemAllocator *alloc = (PyMemAllocator *)ctx; -#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD) - PyGILState_STATE gil_state; -#endif void *ptr2; - if (get_reentrant()) { - /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc(). - Example: PyMem_RawRealloc() is called internally by pymalloc - (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new - arena (new_arena()). */ - ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); - - if (ptr2 != NULL && ptr != NULL) - tracemalloc_log_free(ptr); - - return ptr2; - } - - /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for - allocations larger than 512 bytes. PyGILState_Ensure() may call - PyMem_RawMalloc() indirectly which would call PyGILState_Ensure() if - reentrant are not disabled. */ - set_reentrant(1); -#ifdef WITH_THREAD -#ifdef TRACE_RAW_MALLOC - if (!gil_held) - gil_state = PyGILState_Ensure(); -#else - assert(gil_held); -#endif -#endif ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); + if (ptr2 == NULL) + return NULL; - if (ptr2 != NULL) { - if (ptr != NULL) { - /* resize */ - tracemalloc_log_free(ptr); + if (ptr != NULL) { + /* an existing memory block has been resized */ - if (tracemalloc_log_alloc(ptr2, new_size) < 0) { - /* Memory allocation failed. The error cannot be reported to - the caller, because realloc() may already have shrinked the - memory block and so removed bytes. + tracemalloc_remove_trace(ptr); - This case is very unlikely since we just released an hash - entry, so we have enough free bytes to allocate the new - entry. */ - } - } - else { - /* new allocation */ - if (tracemalloc_log_alloc(ptr2, new_size) < 0) { - /* Memory allocation failed */ - alloc->free(alloc->ctx, ptr2); - ptr2 = NULL; - } + if (tracemalloc_add_trace(ptr2, new_size) < 0) { + /* Memory allocation failed. The error cannot be reported to + the caller, because realloc() may already have shrinked the + memory block and so removed bytes. + + This case is very unlikely since we just released an hash + entry, so we have enough free bytes to allocate the new + entry. */ } } - set_reentrant(0); - -#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD) - if (!gil_held) - PyGILState_Release(gil_state); -#endif + else { + /* new allocation */ + if (tracemalloc_add_trace(ptr2, new_size) < 0) { + /* Failed to allocate a trace for the new memory block */ + alloc->free(alloc->ctx, ptr2); + return NULL; + } + } return ptr2; } @@ -610,34 +549,126 @@ tracemalloc_free(void *ctx, void *ptr) a deadlock in PyThreadState_DeleteCurrent(). */ alloc->free(alloc->ctx, ptr); - tracemalloc_log_free(ptr); + tracemalloc_remove_trace(ptr); } static void* tracemalloc_malloc_gil(void *ctx, size_t size) { - return tracemalloc_malloc(ctx, size, 1); + void *ptr; + + if (get_reentrant()) { + PyMemAllocator *alloc = (PyMemAllocator *)ctx; + return alloc->malloc(alloc->ctx, size); + } + + /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for + allocations larger than 512 bytes, don't trace the same memory + allocation twice. */ + set_reentrant(1); + + ptr = tracemalloc_malloc(ctx, size); + + set_reentrant(0); + return ptr; } static void* tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size) { - return tracemalloc_realloc(ctx, ptr, new_size, 1); + void *ptr2; + + if (get_reentrant()) { + /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc(). + Example: PyMem_RawRealloc() is called internally by pymalloc + (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new + arena (new_arena()). */ + PyMemAllocator *alloc = (PyMemAllocator *)ctx; + + ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); + if (ptr2 != NULL && ptr != NULL) + tracemalloc_remove_trace(ptr); + return ptr2; + } + + /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for + allocations larger than 512 bytes. Don't trace the same memory + allocation twice. */ + set_reentrant(1); + + ptr2 = tracemalloc_realloc(ctx, ptr, new_size); + + set_reentrant(0); + return ptr2; } #ifdef TRACE_RAW_MALLOC static void* tracemalloc_raw_malloc(void *ctx, size_t size) { - return tracemalloc_malloc(ctx, size, 0); +#ifdef WITH_THREAD + PyGILState_STATE gil_state; +#endif + void *ptr; + + if (get_reentrant()) { + PyMemAllocator *alloc = (PyMemAllocator *)ctx; + return alloc->malloc(alloc->ctx, size); + } + + /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() + indirectly which would call PyGILState_Ensure() if reentrant are not + disabled. */ + set_reentrant(1); + +#ifdef WITH_THREAD + gil_state = PyGILState_Ensure(); + ptr = tracemalloc_malloc(ctx, size); + PyGILState_Release(gil_state); +#else + ptr = tracemalloc_malloc(ctx, size); +#endif + + set_reentrant(0); + return ptr; } static void* tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size) { - return tracemalloc_realloc(ctx, ptr, new_size, 0); -} +#ifdef WITH_THREAD + PyGILState_STATE gil_state; #endif + void *ptr2; + + if (get_reentrant()) { + /* Reentrant call to PyMem_RawRealloc(). */ + PyMemAllocator *alloc = (PyMemAllocator *)ctx; + + ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); + if (ptr2 != NULL && ptr != NULL) + tracemalloc_remove_trace(ptr); + + return ptr2; + } + + /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() + indirectly which would call PyGILState_Ensure() if reentrant calls are + not disabled. */ + set_reentrant(1); + +#ifdef WITH_THREAD + gil_state = PyGILState_Ensure(); + ptr2 = tracemalloc_realloc(ctx, ptr, new_size); + PyGILState_Release(gil_state); +#else + ptr2 = tracemalloc_realloc(ctx, ptr, new_size); +#endif + + set_reentrant(0); + return ptr2; +} +#endif /* TRACE_RAW_MALLOC */ static int tracemalloc_clear_filename(_Py_hashtable_entry_t *entry, void *user_data) |