Skip to content

Commit 84aab09

Browse files
committed
Issue python#26588: add debug traces
Try to debug random failure on buildbots.
1 parent 24f949e commit 84aab09

3 files changed

Lines changed: 59 additions & 5 deletions

File tree

Lib/test/test_tracemalloc.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,18 @@ def traceback_filename(filename):
8888

8989
class TestTracemallocEnabled(unittest.TestCase):
9090
def setUp(self):
91+
if _testcapi:
92+
_testcapi.tracemalloc_set_debug(True)
93+
9194
if tracemalloc.is_tracing():
9295
self.skipTest("tracemalloc must be stopped before the test")
9396

9497
tracemalloc.start(1)
9598

9699
def tearDown(self):
97100
tracemalloc.stop()
101+
if _testcapi:
102+
_testcapi.tracemalloc_set_debug(False)
98103

99104
def test_get_tracemalloc_memory(self):
100105
data = [allocate_bytes(123) for count in range(1000)]
@@ -877,6 +882,9 @@ class TestCAPI(unittest.TestCase):
877882
maxDiff = 80 * 20
878883

879884
def setUp(self):
885+
if _testcapi:
886+
_testcapi.tracemalloc_set_debug(True)
887+
880888
if tracemalloc.is_tracing():
881889
self.skipTest("tracemalloc must be stopped before the test")
882890

@@ -890,6 +898,8 @@ def setUp(self):
890898

891899
def tearDown(self):
892900
tracemalloc.stop()
901+
if _testcapi:
902+
_testcapi.tracemalloc_set_debug(False)
893903

894904
def get_traceback(self):
895905
frames = _testcapi.tracemalloc_get_traceback(self.domain, self.ptr)

Modules/_testcapimodule.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3747,6 +3747,19 @@ tracemalloc_get_traceback(PyObject *self, PyObject *args)
37473747
return _PyTraceMalloc_GetTraceback(domain, (Py_uintptr_t)ptr);
37483748
}
37493749

3750+
PyObject*
3751+
tracemalloc_set_debug(PyObject *self, PyObject *args)
3752+
{
3753+
int debug;
3754+
extern int tracemalloc_debug;
3755+
3756+
if (!PyArg_ParseTuple(args, "i", &debug))
3757+
return NULL;
3758+
3759+
tracemalloc_debug = debug;
3760+
Py_RETURN_NONE;
3761+
}
3762+
37503763

37513764
static PyMethodDef TestMethods[] = {
37523765
{"raise_exception", raise_exception, METH_VARARGS},
@@ -3936,6 +3949,7 @@ static PyMethodDef TestMethods[] = {
39363949
{"tracemalloc_track", tracemalloc_track, METH_VARARGS},
39373950
{"tracemalloc_untrack", tracemalloc_untrack, METH_VARARGS},
39383951
{"tracemalloc_get_traceback", tracemalloc_get_traceback, METH_VARARGS},
3952+
{"tracemalloc_set_debug", tracemalloc_set_debug, METH_VARARGS},
39393953
{NULL, NULL} /* sentinel */
39403954
};
39413955

Modules/_tracemalloc.c

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ static struct {
4545
int use_domain;
4646
} tracemalloc_config = {TRACEMALLOC_NOT_INITIALIZED, 0, 1, 1};
4747

48+
int tracemalloc_debug = 0;
49+
4850
#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
4951
/* This lock is needed because tracemalloc_free() is called without
5052
the GIL held from PyMem_RawFree(). It cannot acquire the lock because it
@@ -891,18 +893,24 @@ tracemalloc_clear_traces(void)
891893
_Py_hashtable_clear(tracemalloc_filenames);
892894
}
893895

896+
#define DEBUG(MSG) \
897+
if (tracemalloc_debug) { fprintf(stderr, "[pid %li, tid %li] " MSG "\n", (long)getpid(), PyThread_get_thread_ident()); fflush(stderr); }
898+
894899

895900
static int
896901
tracemalloc_init(void)
897902
{
903+
DEBUG("tracemalloc_init()");
898904
if (tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) {
899905
PyErr_SetString(PyExc_RuntimeError,
900906
"the tracemalloc module has been unloaded");
901907
return -1;
902908
}
903909

904-
if (tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED)
910+
if (tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED) {
911+
DEBUG("tracemalloc_init(): exit (already initialized)");
905912
return 0;
913+
}
906914

907915
PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
908916

@@ -969,18 +977,23 @@ tracemalloc_init(void)
969977
/* Disable tracing allocations until hooks are installed. Set
970978
also the reentrant flag to detect bugs: fail with an assertion error
971979
if set_reentrant(1) is called while tracing is disabled. */
980+
DEBUG("tracemalloc_init(): set_reentrant(1)");
972981
set_reentrant(1);
973982

974983
tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED;
984+
DEBUG("tracemalloc_init(): done");
975985
return 0;
976986
}
977987

978988

979989
static void
980990
tracemalloc_deinit(void)
981991
{
982-
if (tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED)
992+
DEBUG("tracemalloc_deinit()");
993+
if (tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED) {
994+
DEBUG("tracemalloc_deinit(): exit (not initialized)");
983995
return;
996+
}
984997
tracemalloc_config.initialized = TRACEMALLOC_FINALIZED;
985998

986999
tracemalloc_stop();
@@ -997,11 +1010,13 @@ tracemalloc_deinit(void)
9971010
}
9981011
#endif
9991012

1013+
DEBUG("tracemalloc_deinit(): delete reentrant key");
10001014
#ifdef REENTRANT_THREADLOCAL
10011015
PyThread_delete_key(tracemalloc_reentrant_key);
10021016
#endif
10031017

10041018
Py_XDECREF(unknown_filename);
1019+
DEBUG("tracemalloc_deinit(): done");
10051020
}
10061021

10071022

@@ -1011,11 +1026,15 @@ tracemalloc_start(int max_nframe)
10111026
PyMemAllocatorEx alloc;
10121027
size_t size;
10131028

1014-
if (tracemalloc_init() < 0)
1029+
DEBUG("tracemalloc_start()");
1030+
if (tracemalloc_init() < 0) {
1031+
DEBUG("tracemalloc_start(): ERROR! init failed!");
10151032
return -1;
1033+
}
10161034

10171035
if (tracemalloc_config.tracing) {
10181036
/* hook already installed: do nothing */
1037+
DEBUG("tracemalloc_start(): exit (already tracing)");
10191038
return 0;
10201039
}
10211040

@@ -1057,23 +1076,30 @@ tracemalloc_start(int max_nframe)
10571076

10581077
/* everything is ready: start tracing Python memory allocations */
10591078
tracemalloc_config.tracing = 1;
1079+
1080+
DEBUG("tracemalloc_start(): set_reentrant(0)");
10601081
set_reentrant(0);
10611082

1083+
DEBUG("tracemalloc_start(): done");
10621084
return 0;
10631085
}
10641086

10651087

10661088
static void
10671089
tracemalloc_stop(void)
10681090
{
1069-
if (!tracemalloc_config.tracing)
1091+
DEBUG("tracemalloc_stop()");
1092+
if (!tracemalloc_config.tracing) {
1093+
DEBUG("tracemalloc_stop(): exit (not tracing)");
10701094
return;
1095+
}
10711096

10721097
/* stop tracing Python memory allocations */
10731098
tracemalloc_config.tracing = 0;
10741099

10751100
/* set the reentrant flag to detect bugs: fail with an assertion error if
10761101
set_reentrant(1) is called while tracing is disabled. */
1102+
DEBUG("tracemalloc_stop(): set_reentrant(1)");
10771103
set_reentrant(1);
10781104

10791105
/* unregister the hook on memory allocators */
@@ -1088,6 +1114,7 @@ tracemalloc_stop(void)
10881114
/* release memory */
10891115
raw_free(tracemalloc_traceback);
10901116
tracemalloc_traceback = NULL;
1117+
DEBUG("tracemalloc_stop(): done");
10911118
}
10921119

10931120
PyDoc_STRVAR(tracemalloc_is_tracing_doc,
@@ -1455,8 +1482,11 @@ py_tracemalloc_start(PyObject *self, PyObject *args)
14551482
}
14561483
nframe_int = Py_SAFE_DOWNCAST(nframe, Py_ssize_t, int);
14571484

1458-
if (tracemalloc_start(nframe_int) < 0)
1485+
if (tracemalloc_start(nframe_int) < 0) {
1486+
DEBUG("start(): ERROR!");
14591487
return NULL;
1488+
}
1489+
DEBUG("start(): done");
14601490

14611491
Py_RETURN_NONE;
14621492
}

0 commit comments

Comments
 (0)