From abb15420c11d9dda9c89f74eac8417240b321109 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Tue, 31 Oct 2023 15:02:31 +0000 Subject: [PATCH] gh-109181: Speed up Traceback object creation by lazily compute the line number (#111548) Signed-off-by: Pablo Galindo --- ...-10-31-14-25-21.gh-issue-109181.11h6Mc.rst | 2 ++ Python/traceback.c | 35 +++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-10-31-14-25-21.gh-issue-109181.11h6Mc.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-31-14-25-21.gh-issue-109181.11h6Mc.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-31-14-25-21.gh-issue-109181.11h6Mc.rst new file mode 100644 index 00000000000..61a15b471cf --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-31-14-25-21.gh-issue-109181.11h6Mc.rst @@ -0,0 +1,2 @@ +Speed up :obj:`Traceback` object creation by lazily compute the line number. +Patch by Pablo Galindo diff --git a/Python/traceback.c b/Python/traceback.c index 05d841e56ad..8aba802ae36 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -109,6 +109,26 @@ tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_)) return Py_NewRef(ret); } +static int +tb_get_lineno(PyTracebackObject* tb) { + _PyInterpreterFrame* frame = tb->tb_frame->f_frame; + assert(frame != NULL); + return PyCode_Addr2Line(_PyFrame_GetCode(frame), tb->tb_lasti); +} + +static PyObject * +tb_lineno_get(PyTracebackObject *self, void *Py_UNUSED(_)) +{ + int lineno = self->tb_lineno; + if (lineno == -1) { + lineno = tb_get_lineno(self); + if (lineno < 0) { + Py_RETURN_NONE; + } + } + return PyLong_FromLong(lineno); +} + static int tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_)) { @@ -152,12 +172,12 @@ static PyMethodDef tb_methods[] = { static PyMemberDef tb_memberlist[] = { {"tb_frame", _Py_T_OBJECT, OFF(tb_frame), Py_READONLY|Py_AUDIT_READ}, {"tb_lasti", Py_T_INT, OFF(tb_lasti), Py_READONLY}, - {"tb_lineno", Py_T_INT, OFF(tb_lineno), Py_READONLY}, {NULL} /* Sentinel */ }; static PyGetSetDef tb_getsetters[] = { {"tb_next", (getter)tb_next_get, (setter)tb_next_set, NULL, NULL}, + {"tb_lineno", (getter)tb_lineno_get, NULL, NULL, NULL}, {NULL} /* Sentinel */ }; @@ -236,8 +256,7 @@ _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame) assert(tb_next == NULL || PyTraceBack_Check(tb_next)); assert(frame != NULL); int addr = _PyInterpreterFrame_LASTI(frame->f_frame) * sizeof(_Py_CODEUNIT); - return tb_create_raw((PyTracebackObject *)tb_next, frame, addr, - PyFrame_GetLineNumber(frame)); + return tb_create_raw((PyTracebackObject *)tb_next, frame, addr, -1); } @@ -681,9 +700,13 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit) } while (tb != NULL) { code = PyFrame_GetCode(tb->tb_frame); + int tb_lineno = tb->tb_lineno; + if (tb_lineno == -1) { + tb_lineno = tb_get_lineno(tb); + } if (last_file == NULL || code->co_filename != last_file || - last_line == -1 || tb->tb_lineno != last_line || + last_line == -1 || tb_lineno != last_line || last_name == NULL || code->co_name != last_name) { if (cnt > TB_RECURSIVE_CUTOFF) { if (tb_print_line_repeated(f, cnt) < 0) { @@ -691,13 +714,13 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit) } } last_file = code->co_filename; - last_line = tb->tb_lineno; + last_line = tb_lineno; last_name = code->co_name; cnt = 0; } cnt++; if (cnt <= TB_RECURSIVE_CUTOFF) { - if (tb_displayline(tb, f, code->co_filename, tb->tb_lineno, + if (tb_displayline(tb, f, code->co_filename, tb_lineno, tb->tb_frame, code->co_name) < 0) { goto error; }