diff options
author | Julien Danjou <julien@danjou.info> | 2019-10-15 12:00:16 (GMT) |
---|---|---|
committer | Victor Stinner <vstinner@python.org> | 2019-10-15 12:00:16 (GMT) |
commit | 8d59eb1b66c51b2b918da9881c57d07d08df43b7 (patch) | |
tree | 7833df22bb4e8cd3779dfa4a7d5ee2a206ec0b90 /Modules/_tracemalloc.c | |
parent | f3ef06a7cb347ab7bd3cc2b0b3dcebe4f9ff36f9 (diff) | |
download | cpython-8d59eb1b66c51b2b918da9881c57d07d08df43b7.zip cpython-8d59eb1b66c51b2b918da9881c57d07d08df43b7.tar.gz cpython-8d59eb1b66c51b2b918da9881c57d07d08df43b7.tar.bz2 |
bpo-37961, tracemalloc: add Traceback.total_nframe (GH-15545)
Add a total_nframe field to the traces collected by the tracemalloc module.
This field indicates the original number of frames before it was truncated.
Diffstat (limited to 'Modules/_tracemalloc.c')
-rw-r--r-- | Modules/_tracemalloc.c | 45 |
1 files changed, 32 insertions, 13 deletions
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index 26d7600..211c6fb 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -78,15 +78,20 @@ __attribute__((packed)) typedef struct { Py_uhash_t hash; - int nframe; + /* Number of frames stored */ + uint16_t nframe; + /* Total number of frames the traceback had */ + uint16_t total_nframe; frame_t frames[1]; } traceback_t; #define TRACEBACK_SIZE(NFRAME) \ (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1)) -#define MAX_NFRAME \ - ((INT_MAX - (int)sizeof(traceback_t)) / (int)sizeof(frame_t) + 1) +/* The maximum number of frames is either: + - The maximum number of frames we can store in `traceback_t.nframe` + - The maximum memory size_t we can allocate */ +static const unsigned long MAX_NFRAME = Py_MIN(UINT16_MAX, ((SIZE_MAX - sizeof(traceback_t)) / sizeof(frame_t) + 1)); static PyObject *unknown_filename = NULL; @@ -308,6 +313,9 @@ hashtable_compare_traceback(_Py_hashtable_t *ht, const void *pkey, if (traceback1->nframe != traceback2->nframe) return 0; + if (traceback1->total_nframe != traceback2->total_nframe) + return 0; + for (i=0; i < traceback1->nframe; i++) { frame1 = &traceback1->frames[i]; frame2 = &traceback2->frames[i]; @@ -416,6 +424,7 @@ traceback_hash(traceback_t *traceback) /* the cast might truncate len; that doesn't change hash stability */ mult += (Py_uhash_t)(82520UL + len + len); } + x ^= traceback->total_nframe; x += 97531UL; return x; } @@ -436,11 +445,13 @@ traceback_get_frames(traceback_t *traceback) } for (pyframe = tstate->frame; pyframe != NULL; pyframe = pyframe->f_back) { - tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]); - assert(traceback->frames[traceback->nframe].filename != NULL); - traceback->nframe++; - if (traceback->nframe == _Py_tracemalloc_config.max_nframe) - break; + if (traceback->nframe < _Py_tracemalloc_config.max_nframe) { + tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]); + assert(traceback->frames[traceback->nframe].filename != NULL); + traceback->nframe++; + } + if (traceback->total_nframe < UINT16_MAX) + traceback->total_nframe++; } } @@ -456,6 +467,7 @@ traceback_new(void) /* get frames */ traceback = tracemalloc_traceback; traceback->nframe = 0; + traceback->total_nframe = 0; traceback_get_frames(traceback); if (traceback->nframe == 0) return &tracemalloc_empty_traceback; @@ -1001,6 +1013,7 @@ tracemalloc_init(void) PyUnicode_InternInPlace(&unknown_filename); tracemalloc_empty_traceback.nframe = 1; + tracemalloc_empty_traceback.total_nframe = 1; /* borrowed reference */ tracemalloc_empty_traceback.frames[0].filename = unknown_filename; tracemalloc_empty_traceback.frames[0].lineno = 0; @@ -1046,10 +1059,10 @@ tracemalloc_start(int max_nframe) PyMemAllocatorEx alloc; size_t size; - if (max_nframe < 1 || max_nframe > MAX_NFRAME) { + if (max_nframe < 1 || (unsigned long) max_nframe > MAX_NFRAME) { PyErr_Format(PyExc_ValueError, - "the number of frames must be in range [1; %i]", - (int)MAX_NFRAME); + "the number of frames must be in range [1; %lu]", + MAX_NFRAME); return -1; } @@ -1062,7 +1075,6 @@ tracemalloc_start(int max_nframe) return 0; } - assert(1 <= max_nframe && max_nframe <= MAX_NFRAME); _Py_tracemalloc_config.max_nframe = max_nframe; /* allocate a buffer to store a new traceback */ @@ -1234,7 +1246,7 @@ trace_to_pyobject(unsigned int domain, trace_t *trace, PyObject *trace_obj = NULL; PyObject *obj; - trace_obj = PyTuple_New(3); + trace_obj = PyTuple_New(4); if (trace_obj == NULL) return NULL; @@ -1259,6 +1271,13 @@ trace_to_pyobject(unsigned int domain, trace_t *trace, } PyTuple_SET_ITEM(trace_obj, 2, obj); + obj = PyLong_FromUnsignedLong(trace->traceback->total_nframe); + if (obj == NULL) { + Py_DECREF(trace_obj); + return NULL; + } + PyTuple_SET_ITEM(trace_obj, 3, obj); + return trace_obj; } |