From 299f63f37f397c149a3067f4069903941529e376 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 31 Oct 2024 14:04:57 +0300 Subject: [PATCH 1/9] gh-126220: Fix crash on calls to `_lsprof.Profiler` methods with 0 args --- Lib/test/test_cprofile.py | 16 + ...-10-31-14-06-28.gh-issue-126220.uJAJCU.rst | 2 + Modules/_lsprof.c | 230 ++++++----- Modules/clinic/_lsprof.c.h | 357 +++++++++++++++++- 4 files changed, 506 insertions(+), 99 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py index b2595eccc82f70..2d592a68b04ba8 100644 --- a/Lib/test/test_cprofile.py +++ b/Lib/test/test_cprofile.py @@ -30,6 +30,22 @@ def test_bad_counter_during_dealloc(self): self.assertEqual(cm.unraisable.exc_type, TypeError) + def test_crash_on_no_args(self): + # gh-126220 + import _lsprof + + for profile in [_lsprof.Profiler(), cProfile.Profile()]: + for method in [ + "_pystart_callback", + "_pyreturn_callback", + "_ccall_callback", + "_creturn_callback", + ]: + with self.subTest(profile=profile, method=method): + method_obj = getattr(profile, method) + with self.assertRaises(TypeError): + method_obj() # should not crash + def test_evil_external_timer(self): # gh-120289 # Disabling profiler in external timer should not crash diff --git a/Misc/NEWS.d/next/Library/2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst b/Misc/NEWS.d/next/Library/2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst new file mode 100644 index 00000000000000..f1f4a7083843b0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst @@ -0,0 +1,2 @@ +Fix crash of :class:`cProfile.Profile` and ``_lsprof.Profiler`` when their +callbacks were directly called with 0 arguments. diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 8b6906234bdc25..2c2b322fe46583 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -606,17 +606,41 @@ setBuiltins(ProfilerObject *pObj, int nvalue) return 0; } -PyObject* pystart_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) +/*[clinic input] +_lsprof.Profiler._pystart_callback + + code: object + obj: object + / + +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler__pystart_callback_impl(ProfilerObject *self, PyObject *code, + PyObject *obj) +/*[clinic end generated code: output=f6b04ac9658deb04 input=2a8a6a7b163e253d]*/ { - PyObject* code = args[0]; - ptrace_enter_call((PyObject*)self, (void *)code, (PyObject *)code); + ptrace_enter_call((PyObject*)self, (void *)code, code); Py_RETURN_NONE; } -PyObject* pyreturn_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) +/*[clinic input] +_lsprof.Profiler._pyreturn_callback + + code: object + obj: object + retval: object + / + +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler__pyreturn_callback_impl(ProfilerObject *self, + PyObject *code, PyObject *obj, + PyObject *retval) +/*[clinic end generated code: output=dc0488deec84f7fc input=203c2cf434ae6ceb]*/ { - PyObject* code = args[0]; ptrace_leave_call((PyObject*)self, (void *)code); Py_RETURN_NONE; @@ -649,12 +673,24 @@ PyObject* get_cfunc_from_callable(PyObject* callable, PyObject* self_arg, PyObje return NULL; } -PyObject* ccall_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) +/*[clinic input] +_lsprof.Profiler._ccall_callback + + code: object + obj: object + callable: object + self_arg: object + / + +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler__ccall_callback_impl(ProfilerObject *self, PyObject *code, + PyObject *obj, PyObject *callable, + PyObject *self_arg) +/*[clinic end generated code: output=8d50bf59970d2a7e input=9b1560dce1c1a3c8]*/ { if (self->flags & POF_BUILTINS) { - PyObject* callable = args[2]; - PyObject* self_arg = args[3]; - PyObject* cfunc = get_cfunc_from_callable(callable, self_arg, self->missing); if (cfunc) { @@ -667,12 +703,24 @@ PyObject* ccall_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t Py_RETURN_NONE; } -PyObject* creturn_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) +/*[clinic input] +_lsprof.Profiler._creturn_callback + + code: object + obj: object + callable: object + self_arg: object + / + +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler__creturn_callback_impl(ProfilerObject *self, PyObject *code, + PyObject *obj, PyObject *callable, + PyObject *self_arg) +/*[clinic end generated code: output=4c1f245bd3804b9a input=83e727bf01749202]*/ { if (self->flags & POF_BUILTINS) { - PyObject* callable = args[2]; - PyObject* self_arg = args[3]; - PyObject* cfunc = get_cfunc_from_callable(callable, self_arg, self->missing); if (cfunc) { @@ -700,31 +748,27 @@ static const struct { {0, NULL} }; -PyDoc_STRVAR(enable_doc, "\ -enable(subcalls=True, builtins=True)\n\ -\n\ -Start collecting profiling information.\n\ -If 'subcalls' is True, also records for each function\n\ -statistics separated according to its current caller.\n\ -If 'builtins' is True, records the time spent in\n\ -built-in functions separately from their caller.\n\ -"); - -static PyObject* -profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds) +/*[clinic input] +_lsprof.Profiler.enable + + subcalls: bool = True + builtins: bool = True + +Start collecting profiling information. + +If 'subcalls' is True, also records for each function +statistics separated according to its current caller. +If 'builtins' is True, records the time spent in +built-in functions separately from their caller. +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler_enable_impl(ProfilerObject *self, int subcalls, + int builtins) +/*[clinic end generated code: output=1e747f9dc1edd571 input=0b6049b4e398781f]*/ { - int subcalls = -1; - int builtins = -1; - static char *kwlist[] = {"subcalls", "builtins", 0}; int all_events = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|pp:enable", - kwlist, &subcalls, &builtins)) - return NULL; - if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) { - return NULL; - } - PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); if (!monitoring) { return NULL; @@ -776,14 +820,15 @@ flush_unmatched(ProfilerObject *pObj) } -PyDoc_STRVAR(disable_doc, "\ -disable()\n\ -\n\ -Stop collecting profiling information.\n\ -"); +/*[clinic input] +_lsprof.Profiler.disable + +Stop collecting profiling information. +[clinic start generated code]*/ -static PyObject* -profiler_disable(ProfilerObject *self, PyObject* noarg) +static PyObject * +_lsprof_Profiler_disable_impl(ProfilerObject *self) +/*[clinic end generated code: output=838cffef7f651870 input=05700b3fc68d1f50]*/ { if (self->flags & POF_EXT_TIMER) { PyErr_SetString(PyExc_RuntimeError, @@ -834,21 +879,22 @@ profiler_disable(ProfilerObject *self, PyObject* noarg) Py_RETURN_NONE; } -PyDoc_STRVAR(clear_doc, "\ -clear()\n\ -\n\ -Clear all profiling information collected so far.\n\ -"); +/*[clinic input] +_lsprof.Profiler.clear + +Clear all profiling information collected so far. +[clinic start generated code]*/ -static PyObject* -profiler_clear(ProfilerObject *pObj, PyObject* noarg) +static PyObject * +_lsprof_Profiler_clear_impl(ProfilerObject *self) +/*[clinic end generated code: output=dd1c668fb84b1335 input=fbe1f88c28be4f98]*/ { - if (pObj->flags & POF_EXT_TIMER) { + if (self->flags & POF_EXT_TIMER) { PyErr_SetString(PyExc_RuntimeError, "cannot clear profiler in external timer"); return NULL; } - clearEntries(pObj); + clearEntries(self); Py_RETURN_NONE; } @@ -879,74 +925,62 @@ profiler_dealloc(ProfilerObject *op) Py_DECREF(tp); } +/*[clinic input] +_lsprof.Profiler.__init__ + + timer: object(c_default='NULL') = None + timeunit: double = 0.0 + subcalls: bool = True + builtins: bool = True + +Builds a profiler object using the specified timer function. + +The default timer is a fast built-in one based on real time. +For custom timer functions returning integers, timeunit can +be a float specifying a scale (i.e. how long each integer unit +is, in seconds). +[clinic start generated code]*/ + static int -profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw) +_lsprof_Profiler___init___impl(ProfilerObject *self, PyObject *timer, + double timeunit, int subcalls, int builtins) +/*[clinic end generated code: output=ab5498359fd34283 input=40225117dd22d4d7]*/ { - PyObject *timer = NULL; - double timeunit = 0.0; - int subcalls = 1; - int builtins = 1; - static char *kwlist[] = {"timer", "timeunit", - "subcalls", "builtins", 0}; - - if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odpp:Profiler", kwlist, - &timer, &timeunit, - &subcalls, &builtins)) - return -1; - - if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0) + if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) return -1; - pObj->externalTimerUnit = timeunit; - Py_XSETREF(pObj->externalTimer, Py_XNewRef(timer)); - pObj->tool_id = PY_MONITORING_PROFILER_ID; + self->externalTimerUnit = timeunit; + Py_XSETREF(self->externalTimer, Py_XNewRef(timer)); + self->tool_id = PY_MONITORING_PROFILER_ID; PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); if (!monitoring) { return -1; } - pObj->missing = PyObject_GetAttrString(monitoring, "MISSING"); - if (!pObj->missing) { - Py_DECREF(monitoring); + self->missing = PyObject_GetAttrString(monitoring, "MISSING"); + Py_DECREF(monitoring); + if (!self->missing) { return -1; } - Py_DECREF(monitoring); return 0; } static PyMethodDef profiler_methods[] = { _LSPROF_PROFILER_GETSTATS_METHODDEF - {"enable", _PyCFunction_CAST(profiler_enable), - METH_VARARGS | METH_KEYWORDS, enable_doc}, - {"disable", (PyCFunction)profiler_disable, - METH_NOARGS, disable_doc}, - {"clear", (PyCFunction)profiler_clear, - METH_NOARGS, clear_doc}, - {"_pystart_callback", _PyCFunction_CAST(pystart_callback), - METH_FASTCALL, NULL}, - {"_pyreturn_callback", _PyCFunction_CAST(pyreturn_callback), - METH_FASTCALL, NULL}, - {"_ccall_callback", _PyCFunction_CAST(ccall_callback), - METH_FASTCALL, NULL}, - {"_creturn_callback", _PyCFunction_CAST(creturn_callback), - METH_FASTCALL, NULL}, + _LSPROF_PROFILER_ENABLE_METHODDEF + _LSPROF_PROFILER_DISABLE_METHODDEF + _LSPROF_PROFILER_CLEAR_METHODDEF + _LSPROF_PROFILER__PYSTART_CALLBACK_METHODDEF + _LSPROF_PROFILER__PYRETURN_CALLBACK_METHODDEF + _LSPROF_PROFILER__CCALL_CALLBACK_METHODDEF + _LSPROF_PROFILER__CRETURN_CALLBACK_METHODDEF {NULL, NULL} }; -PyDoc_STRVAR(profiler_doc, "\ -Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\ -\n\ - Builds a profiler object using the specified timer function.\n\ - The default timer is a fast built-in one based on real time.\n\ - For custom timer functions returning integers, timeunit can\n\ - be a float specifying a scale (i.e. how long each integer unit\n\ - is, in seconds).\n\ -"); - static PyType_Slot _lsprof_profiler_type_spec_slots[] = { - {Py_tp_doc, (void *)profiler_doc}, + {Py_tp_doc, (void *)_lsprof_Profiler___init____doc__}, {Py_tp_methods, profiler_methods}, {Py_tp_dealloc, profiler_dealloc}, - {Py_tp_init, profiler_init}, + {Py_tp_init, _lsprof_Profiler___init__}, {Py_tp_traverse, profiler_traverse}, {0, 0} }; diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h index b3b7fda5660bfd..7d9b6496db356d 100644 --- a/Modules/clinic/_lsprof.c.h +++ b/Modules/clinic/_lsprof.c.h @@ -2,6 +2,12 @@ preserve [clinic start generated code]*/ +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif +#include "pycore_modsupport.h" // _PyArg_CheckPositional() + PyDoc_STRVAR(_lsprof_Profiler_getstats__doc__, "getstats($self, /)\n" "--\n" @@ -45,4 +51,353 @@ _lsprof_Profiler_getstats(ProfilerObject *self, PyTypeObject *cls, PyObject *con } return _lsprof_Profiler_getstats_impl(self, cls); } -/*[clinic end generated code: output=5c9d87d89863dc83 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_lsprof_Profiler__pystart_callback__doc__, +"_pystart_callback($self, code, obj, /)\n" +"--\n" +"\n"); + +#define _LSPROF_PROFILER__PYSTART_CALLBACK_METHODDEF \ + {"_pystart_callback", _PyCFunction_CAST(_lsprof_Profiler__pystart_callback), METH_FASTCALL, _lsprof_Profiler__pystart_callback__doc__}, + +static PyObject * +_lsprof_Profiler__pystart_callback_impl(ProfilerObject *self, PyObject *code, + PyObject *obj); + +static PyObject * +_lsprof_Profiler__pystart_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *code; + PyObject *obj; + + if (!_PyArg_CheckPositional("_pystart_callback", nargs, 2, 2)) { + goto exit; + } + code = args[0]; + obj = args[1]; + return_value = _lsprof_Profiler__pystart_callback_impl(self, code, obj); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lsprof_Profiler__pyreturn_callback__doc__, +"_pyreturn_callback($self, code, obj, retval, /)\n" +"--\n" +"\n"); + +#define _LSPROF_PROFILER__PYRETURN_CALLBACK_METHODDEF \ + {"_pyreturn_callback", _PyCFunction_CAST(_lsprof_Profiler__pyreturn_callback), METH_FASTCALL, _lsprof_Profiler__pyreturn_callback__doc__}, + +static PyObject * +_lsprof_Profiler__pyreturn_callback_impl(ProfilerObject *self, + PyObject *code, PyObject *obj, + PyObject *retval); + +static PyObject * +_lsprof_Profiler__pyreturn_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *code; + PyObject *obj; + PyObject *retval; + + if (!_PyArg_CheckPositional("_pyreturn_callback", nargs, 3, 3)) { + goto exit; + } + code = args[0]; + obj = args[1]; + retval = args[2]; + return_value = _lsprof_Profiler__pyreturn_callback_impl(self, code, obj, retval); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lsprof_Profiler__ccall_callback__doc__, +"_ccall_callback($self, code, obj, callable, self_arg, /)\n" +"--\n" +"\n"); + +#define _LSPROF_PROFILER__CCALL_CALLBACK_METHODDEF \ + {"_ccall_callback", _PyCFunction_CAST(_lsprof_Profiler__ccall_callback), METH_FASTCALL, _lsprof_Profiler__ccall_callback__doc__}, + +static PyObject * +_lsprof_Profiler__ccall_callback_impl(ProfilerObject *self, PyObject *code, + PyObject *obj, PyObject *callable, + PyObject *self_arg); + +static PyObject * +_lsprof_Profiler__ccall_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *code; + PyObject *obj; + PyObject *callable; + PyObject *self_arg; + + if (!_PyArg_CheckPositional("_ccall_callback", nargs, 4, 4)) { + goto exit; + } + code = args[0]; + obj = args[1]; + callable = args[2]; + self_arg = args[3]; + return_value = _lsprof_Profiler__ccall_callback_impl(self, code, obj, callable, self_arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lsprof_Profiler__creturn_callback__doc__, +"_creturn_callback($self, code, obj, callable, self_arg, /)\n" +"--\n" +"\n"); + +#define _LSPROF_PROFILER__CRETURN_CALLBACK_METHODDEF \ + {"_creturn_callback", _PyCFunction_CAST(_lsprof_Profiler__creturn_callback), METH_FASTCALL, _lsprof_Profiler__creturn_callback__doc__}, + +static PyObject * +_lsprof_Profiler__creturn_callback_impl(ProfilerObject *self, PyObject *code, + PyObject *obj, PyObject *callable, + PyObject *self_arg); + +static PyObject * +_lsprof_Profiler__creturn_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *code; + PyObject *obj; + PyObject *callable; + PyObject *self_arg; + + if (!_PyArg_CheckPositional("_creturn_callback", nargs, 4, 4)) { + goto exit; + } + code = args[0]; + obj = args[1]; + callable = args[2]; + self_arg = args[3]; + return_value = _lsprof_Profiler__creturn_callback_impl(self, code, obj, callable, self_arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lsprof_Profiler_enable__doc__, +"enable($self, /, subcalls=True, builtins=True)\n" +"--\n" +"\n" +"Start collecting profiling information.\n" +"\n" +"If \'subcalls\' is True, also records for each function\n" +"statistics separated according to its current caller.\n" +"If \'builtins\' is True, records the time spent in\n" +"built-in functions separately from their caller."); + +#define _LSPROF_PROFILER_ENABLE_METHODDEF \ + {"enable", _PyCFunction_CAST(_lsprof_Profiler_enable), METH_FASTCALL|METH_KEYWORDS, _lsprof_Profiler_enable__doc__}, + +static PyObject * +_lsprof_Profiler_enable_impl(ProfilerObject *self, int subcalls, + int builtins); + +static PyObject * +_lsprof_Profiler_enable(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(subcalls), &_Py_ID(builtins), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"subcalls", "builtins", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "enable", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + int subcalls = 1; + int builtins = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 2, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + subcalls = PyObject_IsTrue(args[0]); + if (subcalls < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + builtins = PyObject_IsTrue(args[1]); + if (builtins < 0) { + goto exit; + } +skip_optional_pos: + return_value = _lsprof_Profiler_enable_impl(self, subcalls, builtins); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lsprof_Profiler_disable__doc__, +"disable($self, /)\n" +"--\n" +"\n" +"Stop collecting profiling information."); + +#define _LSPROF_PROFILER_DISABLE_METHODDEF \ + {"disable", (PyCFunction)_lsprof_Profiler_disable, METH_NOARGS, _lsprof_Profiler_disable__doc__}, + +static PyObject * +_lsprof_Profiler_disable_impl(ProfilerObject *self); + +static PyObject * +_lsprof_Profiler_disable(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _lsprof_Profiler_disable_impl(self); +} + +PyDoc_STRVAR(_lsprof_Profiler_clear__doc__, +"clear($self, /)\n" +"--\n" +"\n" +"Clear all profiling information collected so far."); + +#define _LSPROF_PROFILER_CLEAR_METHODDEF \ + {"clear", (PyCFunction)_lsprof_Profiler_clear, METH_NOARGS, _lsprof_Profiler_clear__doc__}, + +static PyObject * +_lsprof_Profiler_clear_impl(ProfilerObject *self); + +static PyObject * +_lsprof_Profiler_clear(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _lsprof_Profiler_clear_impl(self); +} + +PyDoc_STRVAR(_lsprof_Profiler___init____doc__, +"Profiler(timer=None, timeunit=0.0, subcalls=True, builtins=True)\n" +"--\n" +"\n" +"Builds a profiler object using the specified timer function.\n" +"\n" +"The default timer is a fast built-in one based on real time.\n" +"For custom timer functions returning integers, timeunit can\n" +"be a float specifying a scale (i.e. how long each integer unit\n" +"is, in seconds)."); + +static int +_lsprof_Profiler___init___impl(ProfilerObject *self, PyObject *timer, + double timeunit, int subcalls, int builtins); + +static int +_lsprof_Profiler___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 4 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(timer), &_Py_ID(timeunit), &_Py_ID(subcalls), &_Py_ID(builtins), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"timer", "timeunit", "subcalls", "builtins", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "Profiler", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[4]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; + PyObject *timer = NULL; + double timeunit = 0.0; + int subcalls = 1; + int builtins = 1; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 0, 4, 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[0]) { + timer = fastargs[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[1]) { + if (PyFloat_CheckExact(fastargs[1])) { + timeunit = PyFloat_AS_DOUBLE(fastargs[1]); + } + else + { + timeunit = PyFloat_AsDouble(fastargs[1]); + if (timeunit == -1.0 && PyErr_Occurred()) { + goto exit; + } + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[2]) { + subcalls = PyObject_IsTrue(fastargs[2]); + if (subcalls < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + builtins = PyObject_IsTrue(fastargs[3]); + if (builtins < 0) { + goto exit; + } +skip_optional_pos: + return_value = _lsprof_Profiler___init___impl((ProfilerObject *)self, timer, timeunit, subcalls, builtins); + +exit: + return return_value; +} +/*[clinic end generated code: output=787298ede73ff273 input=a9049054013a1b77]*/ From af78745c8ae8132387b48a2689e04caa75d34bb6 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 31 Oct 2024 14:22:10 +0300 Subject: [PATCH 2/9] Fix CI --- .../internal/pycore_global_objects_fini_generated.h | 3 +++ Include/internal/pycore_global_strings.h | 3 +++ Include/internal/pycore_runtime_init_generated.h | 3 +++ Include/internal/pycore_unicodeobject_generated.h | 12 ++++++++++++ .../2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst | 2 +- 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 2fd7d5d13a98b2..e4f0138e17edfa 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1231,6 +1231,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(strict_mode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(string)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sub_key)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(subcalls)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(symmetric_difference_update)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tabsize)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tag)); @@ -1248,8 +1249,10 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(threading)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(throw)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timeout)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timer)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(times)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timetuple)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timeunit)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(top)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(trace_callback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(traceback)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index fc3871570cc49d..e70f11e2a26cd5 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -720,6 +720,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(strict_mode) STRUCT_FOR_ID(string) STRUCT_FOR_ID(sub_key) + STRUCT_FOR_ID(subcalls) STRUCT_FOR_ID(symmetric_difference_update) STRUCT_FOR_ID(tabsize) STRUCT_FOR_ID(tag) @@ -737,8 +738,10 @@ struct _Py_global_strings { STRUCT_FOR_ID(threading) STRUCT_FOR_ID(throw) STRUCT_FOR_ID(timeout) + STRUCT_FOR_ID(timer) STRUCT_FOR_ID(times) STRUCT_FOR_ID(timetuple) + STRUCT_FOR_ID(timeunit) STRUCT_FOR_ID(top) STRUCT_FOR_ID(trace_callback) STRUCT_FOR_ID(traceback) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 3b80e265b0ca50..5d404c8fd91ca6 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1229,6 +1229,7 @@ extern "C" { INIT_ID(strict_mode), \ INIT_ID(string), \ INIT_ID(sub_key), \ + INIT_ID(subcalls), \ INIT_ID(symmetric_difference_update), \ INIT_ID(tabsize), \ INIT_ID(tag), \ @@ -1246,8 +1247,10 @@ extern "C" { INIT_ID(threading), \ INIT_ID(throw), \ INIT_ID(timeout), \ + INIT_ID(timer), \ INIT_ID(times), \ INIT_ID(timetuple), \ + INIT_ID(timeunit), \ INIT_ID(top), \ INIT_ID(trace_callback), \ INIT_ID(traceback), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index eb2eca06ec4d4f..d0bc8d7186c053 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -2676,6 +2676,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(subcalls); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(symmetric_difference_update); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2744,6 +2748,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(timer); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(times); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2752,6 +2760,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(timeunit); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(top); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Misc/NEWS.d/next/Library/2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst b/Misc/NEWS.d/next/Library/2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst index f1f4a7083843b0..005ae603d058a8 100644 --- a/Misc/NEWS.d/next/Library/2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst +++ b/Misc/NEWS.d/next/Library/2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst @@ -1,2 +1,2 @@ -Fix crash of :class:`cProfile.Profile` and ``_lsprof.Profiler`` when their +Fix crash of ``cProfile.Profile`` and ``_lsprof.Profiler`` when their callbacks were directly called with 0 arguments. From 3fddc30482af22a061cba9e2c61767c893b0bd1c Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 31 Oct 2024 22:06:34 +0300 Subject: [PATCH 3/9] Only fix 4 crashers --- .../pycore_global_objects_fini_generated.h | 3 - Include/internal/pycore_global_strings.h | 3 - .../internal/pycore_runtime_init_generated.h | 3 - .../internal/pycore_unicodeobject_generated.h | 12 - Modules/_lsprof.c | 144 ++++++------ Modules/clinic/_lsprof.c.h | 222 +----------------- 6 files changed, 78 insertions(+), 309 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index e4f0138e17edfa..2fd7d5d13a98b2 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1231,7 +1231,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(strict_mode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(string)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sub_key)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(subcalls)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(symmetric_difference_update)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tabsize)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tag)); @@ -1249,10 +1248,8 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(threading)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(throw)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timeout)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timer)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(times)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timetuple)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timeunit)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(top)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(trace_callback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(traceback)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index e70f11e2a26cd5..fc3871570cc49d 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -720,7 +720,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(strict_mode) STRUCT_FOR_ID(string) STRUCT_FOR_ID(sub_key) - STRUCT_FOR_ID(subcalls) STRUCT_FOR_ID(symmetric_difference_update) STRUCT_FOR_ID(tabsize) STRUCT_FOR_ID(tag) @@ -738,10 +737,8 @@ struct _Py_global_strings { STRUCT_FOR_ID(threading) STRUCT_FOR_ID(throw) STRUCT_FOR_ID(timeout) - STRUCT_FOR_ID(timer) STRUCT_FOR_ID(times) STRUCT_FOR_ID(timetuple) - STRUCT_FOR_ID(timeunit) STRUCT_FOR_ID(top) STRUCT_FOR_ID(trace_callback) STRUCT_FOR_ID(traceback) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 5d404c8fd91ca6..3b80e265b0ca50 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1229,7 +1229,6 @@ extern "C" { INIT_ID(strict_mode), \ INIT_ID(string), \ INIT_ID(sub_key), \ - INIT_ID(subcalls), \ INIT_ID(symmetric_difference_update), \ INIT_ID(tabsize), \ INIT_ID(tag), \ @@ -1247,10 +1246,8 @@ extern "C" { INIT_ID(threading), \ INIT_ID(throw), \ INIT_ID(timeout), \ - INIT_ID(timer), \ INIT_ID(times), \ INIT_ID(timetuple), \ - INIT_ID(timeunit), \ INIT_ID(top), \ INIT_ID(trace_callback), \ INIT_ID(traceback), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index d0bc8d7186c053..eb2eca06ec4d4f 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -2676,10 +2676,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(subcalls); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(symmetric_difference_update); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2748,10 +2744,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(timer); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(times); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2760,10 +2752,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(timeunit); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(top); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 2c2b322fe46583..73c955744f9ef9 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -748,27 +748,31 @@ static const struct { {0, NULL} }; -/*[clinic input] -_lsprof.Profiler.enable - - subcalls: bool = True - builtins: bool = True - -Start collecting profiling information. - -If 'subcalls' is True, also records for each function -statistics separated according to its current caller. -If 'builtins' is True, records the time spent in -built-in functions separately from their caller. -[clinic start generated code]*/ - -static PyObject * -_lsprof_Profiler_enable_impl(ProfilerObject *self, int subcalls, - int builtins) -/*[clinic end generated code: output=1e747f9dc1edd571 input=0b6049b4e398781f]*/ +PyDoc_STRVAR(enable_doc, "\ +enable(subcalls=True, builtins=True)\n\ +\n\ +Start collecting profiling information.\n\ +If 'subcalls' is True, also records for each function\n\ +statistics separated according to its current caller.\n\ +If 'builtins' is True, records the time spent in\n\ +built-in functions separately from their caller.\n\ +"); + +static PyObject* +profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds) { + int subcalls = -1; + int builtins = -1; + static char *kwlist[] = {"subcalls", "builtins", 0}; int all_events = 0; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|pp:enable", + kwlist, &subcalls, &builtins)) + return NULL; + if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) { + return NULL; + } + PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); if (!monitoring) { return NULL; @@ -820,15 +824,14 @@ flush_unmatched(ProfilerObject *pObj) } -/*[clinic input] -_lsprof.Profiler.disable - -Stop collecting profiling information. -[clinic start generated code]*/ +PyDoc_STRVAR(disable_doc, "\ +disable()\n\ +\n\ +Stop collecting profiling information.\n\ +"); -static PyObject * -_lsprof_Profiler_disable_impl(ProfilerObject *self) -/*[clinic end generated code: output=838cffef7f651870 input=05700b3fc68d1f50]*/ +static PyObject* +profiler_disable(ProfilerObject *self, PyObject* Py_UNUSED(unused)) { if (self->flags & POF_EXT_TIMER) { PyErr_SetString(PyExc_RuntimeError, @@ -879,22 +882,21 @@ _lsprof_Profiler_disable_impl(ProfilerObject *self) Py_RETURN_NONE; } -/*[clinic input] -_lsprof.Profiler.clear - -Clear all profiling information collected so far. -[clinic start generated code]*/ +PyDoc_STRVAR(clear_doc, "\ +clear()\n\ +\n\ +Clear all profiling information collected so far.\n\ +"); -static PyObject * -_lsprof_Profiler_clear_impl(ProfilerObject *self) -/*[clinic end generated code: output=dd1c668fb84b1335 input=fbe1f88c28be4f98]*/ +static PyObject* +profiler_clear(ProfilerObject *pObj, PyObject* noarg) { - if (self->flags & POF_EXT_TIMER) { + if (pObj->flags & POF_EXT_TIMER) { PyErr_SetString(PyExc_RuntimeError, "cannot clear profiler in external timer"); return NULL; } - clearEntries(self); + clearEntries(pObj); Py_RETURN_NONE; } @@ -925,50 +927,48 @@ profiler_dealloc(ProfilerObject *op) Py_DECREF(tp); } -/*[clinic input] -_lsprof.Profiler.__init__ - - timer: object(c_default='NULL') = None - timeunit: double = 0.0 - subcalls: bool = True - builtins: bool = True - -Builds a profiler object using the specified timer function. - -The default timer is a fast built-in one based on real time. -For custom timer functions returning integers, timeunit can -be a float specifying a scale (i.e. how long each integer unit -is, in seconds). -[clinic start generated code]*/ - static int -_lsprof_Profiler___init___impl(ProfilerObject *self, PyObject *timer, - double timeunit, int subcalls, int builtins) -/*[clinic end generated code: output=ab5498359fd34283 input=40225117dd22d4d7]*/ +profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw) { - if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) + PyObject *timer = NULL; + double timeunit = 0.0; + int subcalls = 1; + int builtins = 1; + static char *kwlist[] = {"timer", "timeunit", + "subcalls", "builtins", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odpp:Profiler", kwlist, + &timer, &timeunit, + &subcalls, &builtins)) + return -1; + + if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0) return -1; - self->externalTimerUnit = timeunit; - Py_XSETREF(self->externalTimer, Py_XNewRef(timer)); - self->tool_id = PY_MONITORING_PROFILER_ID; + pObj->externalTimerUnit = timeunit; + Py_XSETREF(pObj->externalTimer, Py_XNewRef(timer)); + pObj->tool_id = PY_MONITORING_PROFILER_ID; PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); if (!monitoring) { return -1; } - self->missing = PyObject_GetAttrString(monitoring, "MISSING"); - Py_DECREF(monitoring); - if (!self->missing) { + pObj->missing = PyObject_GetAttrString(monitoring, "MISSING"); + if (!pObj->missing) { + Py_DECREF(monitoring); return -1; } + Py_DECREF(monitoring); return 0; } static PyMethodDef profiler_methods[] = { _LSPROF_PROFILER_GETSTATS_METHODDEF - _LSPROF_PROFILER_ENABLE_METHODDEF - _LSPROF_PROFILER_DISABLE_METHODDEF - _LSPROF_PROFILER_CLEAR_METHODDEF + {"enable", _PyCFunction_CAST(profiler_enable), + METH_VARARGS | METH_KEYWORDS, enable_doc}, + {"disable", (PyCFunction)profiler_disable, + METH_NOARGS, disable_doc}, + {"clear", (PyCFunction)profiler_clear, + METH_NOARGS, clear_doc}, _LSPROF_PROFILER__PYSTART_CALLBACK_METHODDEF _LSPROF_PROFILER__PYRETURN_CALLBACK_METHODDEF _LSPROF_PROFILER__CCALL_CALLBACK_METHODDEF @@ -976,11 +976,21 @@ static PyMethodDef profiler_methods[] = { {NULL, NULL} }; +PyDoc_STRVAR(profiler_doc, "\ +Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\ +\n\ + Builds a profiler object using the specified timer function.\n\ + The default timer is a fast built-in one based on real time.\n\ + For custom timer functions returning integers, timeunit can\n\ + be a float specifying a scale (i.e. how long each integer unit\n\ + is, in seconds).\n\ +"); + static PyType_Slot _lsprof_profiler_type_spec_slots[] = { - {Py_tp_doc, (void *)_lsprof_Profiler___init____doc__}, + {Py_tp_doc, (void *)profiler_doc}, {Py_tp_methods, profiler_methods}, {Py_tp_dealloc, profiler_dealloc}, - {Py_tp_init, _lsprof_Profiler___init__}, + {Py_tp_init, profiler_init}, {Py_tp_traverse, profiler_traverse}, {0, 0} }; diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h index 7d9b6496db356d..dfba178265994f 100644 --- a/Modules/clinic/_lsprof.c.h +++ b/Modules/clinic/_lsprof.c.h @@ -2,10 +2,6 @@ preserve [clinic start generated code]*/ -#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -# include "pycore_gc.h" // PyGC_Head -# include "pycore_runtime.h" // _Py_ID() -#endif #include "pycore_modsupport.h" // _PyArg_CheckPositional() PyDoc_STRVAR(_lsprof_Profiler_getstats__doc__, @@ -184,220 +180,4 @@ _lsprof_Profiler__creturn_callback(ProfilerObject *self, PyObject *const *args, exit: return return_value; } - -PyDoc_STRVAR(_lsprof_Profiler_enable__doc__, -"enable($self, /, subcalls=True, builtins=True)\n" -"--\n" -"\n" -"Start collecting profiling information.\n" -"\n" -"If \'subcalls\' is True, also records for each function\n" -"statistics separated according to its current caller.\n" -"If \'builtins\' is True, records the time spent in\n" -"built-in functions separately from their caller."); - -#define _LSPROF_PROFILER_ENABLE_METHODDEF \ - {"enable", _PyCFunction_CAST(_lsprof_Profiler_enable), METH_FASTCALL|METH_KEYWORDS, _lsprof_Profiler_enable__doc__}, - -static PyObject * -_lsprof_Profiler_enable_impl(ProfilerObject *self, int subcalls, - int builtins); - -static PyObject * -_lsprof_Profiler_enable(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(subcalls), &_Py_ID(builtins), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"subcalls", "builtins", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "enable", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; - int subcalls = 1; - int builtins = 1; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 2, 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - if (args[0]) { - subcalls = PyObject_IsTrue(args[0]); - if (subcalls < 0) { - goto exit; - } - if (!--noptargs) { - goto skip_optional_pos; - } - } - builtins = PyObject_IsTrue(args[1]); - if (builtins < 0) { - goto exit; - } -skip_optional_pos: - return_value = _lsprof_Profiler_enable_impl(self, subcalls, builtins); - -exit: - return return_value; -} - -PyDoc_STRVAR(_lsprof_Profiler_disable__doc__, -"disable($self, /)\n" -"--\n" -"\n" -"Stop collecting profiling information."); - -#define _LSPROF_PROFILER_DISABLE_METHODDEF \ - {"disable", (PyCFunction)_lsprof_Profiler_disable, METH_NOARGS, _lsprof_Profiler_disable__doc__}, - -static PyObject * -_lsprof_Profiler_disable_impl(ProfilerObject *self); - -static PyObject * -_lsprof_Profiler_disable(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _lsprof_Profiler_disable_impl(self); -} - -PyDoc_STRVAR(_lsprof_Profiler_clear__doc__, -"clear($self, /)\n" -"--\n" -"\n" -"Clear all profiling information collected so far."); - -#define _LSPROF_PROFILER_CLEAR_METHODDEF \ - {"clear", (PyCFunction)_lsprof_Profiler_clear, METH_NOARGS, _lsprof_Profiler_clear__doc__}, - -static PyObject * -_lsprof_Profiler_clear_impl(ProfilerObject *self); - -static PyObject * -_lsprof_Profiler_clear(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _lsprof_Profiler_clear_impl(self); -} - -PyDoc_STRVAR(_lsprof_Profiler___init____doc__, -"Profiler(timer=None, timeunit=0.0, subcalls=True, builtins=True)\n" -"--\n" -"\n" -"Builds a profiler object using the specified timer function.\n" -"\n" -"The default timer is a fast built-in one based on real time.\n" -"For custom timer functions returning integers, timeunit can\n" -"be a float specifying a scale (i.e. how long each integer unit\n" -"is, in seconds)."); - -static int -_lsprof_Profiler___init___impl(ProfilerObject *self, PyObject *timer, - double timeunit, int subcalls, int builtins); - -static int -_lsprof_Profiler___init__(PyObject *self, PyObject *args, PyObject *kwargs) -{ - int return_value = -1; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 4 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(timer), &_Py_ID(timeunit), &_Py_ID(subcalls), &_Py_ID(builtins), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"timer", "timeunit", "subcalls", "builtins", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "Profiler", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[4]; - PyObject * const *fastargs; - Py_ssize_t nargs = PyTuple_GET_SIZE(args); - Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; - PyObject *timer = NULL; - double timeunit = 0.0; - int subcalls = 1; - int builtins = 1; - - fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 0, 4, 0, argsbuf); - if (!fastargs) { - goto exit; - } - if (!noptargs) { - goto skip_optional_pos; - } - if (fastargs[0]) { - timer = fastargs[0]; - if (!--noptargs) { - goto skip_optional_pos; - } - } - if (fastargs[1]) { - if (PyFloat_CheckExact(fastargs[1])) { - timeunit = PyFloat_AS_DOUBLE(fastargs[1]); - } - else - { - timeunit = PyFloat_AsDouble(fastargs[1]); - if (timeunit == -1.0 && PyErr_Occurred()) { - goto exit; - } - } - if (!--noptargs) { - goto skip_optional_pos; - } - } - if (fastargs[2]) { - subcalls = PyObject_IsTrue(fastargs[2]); - if (subcalls < 0) { - goto exit; - } - if (!--noptargs) { - goto skip_optional_pos; - } - } - builtins = PyObject_IsTrue(fastargs[3]); - if (builtins < 0) { - goto exit; - } -skip_optional_pos: - return_value = _lsprof_Profiler___init___impl((ProfilerObject *)self, timer, timeunit, subcalls, builtins); - -exit: - return return_value; -} -/*[clinic end generated code: output=787298ede73ff273 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=79b2515a0d296f7d input=a9049054013a1b77]*/ From 4ffecddb286d69133cfcef4e9ed2d4e22bd0b212 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 31 Oct 2024 22:08:30 +0300 Subject: [PATCH 4/9] Use `instruction_offset` arg name --- Modules/_lsprof.c | 28 ++++++++++++----------- Modules/clinic/_lsprof.c.h | 47 ++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 73c955744f9ef9..fa26d2b4f77a58 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -610,15 +610,15 @@ setBuiltins(ProfilerObject *pObj, int nvalue) _lsprof.Profiler._pystart_callback code: object - obj: object + instruction_offset: object / [clinic start generated code]*/ static PyObject * _lsprof_Profiler__pystart_callback_impl(ProfilerObject *self, PyObject *code, - PyObject *obj) -/*[clinic end generated code: output=f6b04ac9658deb04 input=2a8a6a7b163e253d]*/ + PyObject *instruction_offset) +/*[clinic end generated code: output=5fec8b7ad5ed25e8 input=b166e6953c579cda]*/ { ptrace_enter_call((PyObject*)self, (void *)code, code); @@ -629,7 +629,7 @@ _lsprof_Profiler__pystart_callback_impl(ProfilerObject *self, PyObject *code, _lsprof.Profiler._pyreturn_callback code: object - obj: object + instruction_offset: object retval: object / @@ -637,9 +637,10 @@ _lsprof.Profiler._pyreturn_callback static PyObject * _lsprof_Profiler__pyreturn_callback_impl(ProfilerObject *self, - PyObject *code, PyObject *obj, + PyObject *code, + PyObject *instruction_offset, PyObject *retval) -/*[clinic end generated code: output=dc0488deec84f7fc input=203c2cf434ae6ceb]*/ +/*[clinic end generated code: output=9e2f6fc1b882c51e input=667ffaeb2fa6fd1f]*/ { ptrace_leave_call((PyObject*)self, (void *)code); @@ -677,7 +678,7 @@ PyObject* get_cfunc_from_callable(PyObject* callable, PyObject* self_arg, PyObje _lsprof.Profiler._ccall_callback code: object - obj: object + instruction_offset: object callable: object self_arg: object / @@ -686,9 +687,9 @@ _lsprof.Profiler._ccall_callback static PyObject * _lsprof_Profiler__ccall_callback_impl(ProfilerObject *self, PyObject *code, - PyObject *obj, PyObject *callable, - PyObject *self_arg) -/*[clinic end generated code: output=8d50bf59970d2a7e input=9b1560dce1c1a3c8]*/ + PyObject *instruction_offset, + PyObject *callable, PyObject *self_arg) +/*[clinic end generated code: output=152db83cabd18cad input=0e66687cfb95c001]*/ { if (self->flags & POF_BUILTINS) { PyObject* cfunc = get_cfunc_from_callable(callable, self_arg, self->missing); @@ -707,7 +708,7 @@ _lsprof_Profiler__ccall_callback_impl(ProfilerObject *self, PyObject *code, _lsprof.Profiler._creturn_callback code: object - obj: object + instruction_offset: object callable: object self_arg: object / @@ -716,9 +717,10 @@ _lsprof.Profiler._creturn_callback static PyObject * _lsprof_Profiler__creturn_callback_impl(ProfilerObject *self, PyObject *code, - PyObject *obj, PyObject *callable, + PyObject *instruction_offset, + PyObject *callable, PyObject *self_arg) -/*[clinic end generated code: output=4c1f245bd3804b9a input=83e727bf01749202]*/ +/*[clinic end generated code: output=1e886dde8fed8fb0 input=b18afe023746923a]*/ { if (self->flags & POF_BUILTINS) { PyObject* cfunc = get_cfunc_from_callable(callable, self_arg, self->missing); diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h index dfba178265994f..b35c5e12bdeb44 100644 --- a/Modules/clinic/_lsprof.c.h +++ b/Modules/clinic/_lsprof.c.h @@ -49,7 +49,7 @@ _lsprof_Profiler_getstats(ProfilerObject *self, PyTypeObject *cls, PyObject *con } PyDoc_STRVAR(_lsprof_Profiler__pystart_callback__doc__, -"_pystart_callback($self, code, obj, /)\n" +"_pystart_callback($self, code, instruction_offset, /)\n" "--\n" "\n"); @@ -58,28 +58,28 @@ PyDoc_STRVAR(_lsprof_Profiler__pystart_callback__doc__, static PyObject * _lsprof_Profiler__pystart_callback_impl(ProfilerObject *self, PyObject *code, - PyObject *obj); + PyObject *instruction_offset); static PyObject * _lsprof_Profiler__pystart_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *code; - PyObject *obj; + PyObject *instruction_offset; if (!_PyArg_CheckPositional("_pystart_callback", nargs, 2, 2)) { goto exit; } code = args[0]; - obj = args[1]; - return_value = _lsprof_Profiler__pystart_callback_impl(self, code, obj); + instruction_offset = args[1]; + return_value = _lsprof_Profiler__pystart_callback_impl(self, code, instruction_offset); exit: return return_value; } PyDoc_STRVAR(_lsprof_Profiler__pyreturn_callback__doc__, -"_pyreturn_callback($self, code, obj, retval, /)\n" +"_pyreturn_callback($self, code, instruction_offset, retval, /)\n" "--\n" "\n"); @@ -88,7 +88,8 @@ PyDoc_STRVAR(_lsprof_Profiler__pyreturn_callback__doc__, static PyObject * _lsprof_Profiler__pyreturn_callback_impl(ProfilerObject *self, - PyObject *code, PyObject *obj, + PyObject *code, + PyObject *instruction_offset, PyObject *retval); static PyObject * @@ -96,23 +97,23 @@ _lsprof_Profiler__pyreturn_callback(ProfilerObject *self, PyObject *const *args, { PyObject *return_value = NULL; PyObject *code; - PyObject *obj; + PyObject *instruction_offset; PyObject *retval; if (!_PyArg_CheckPositional("_pyreturn_callback", nargs, 3, 3)) { goto exit; } code = args[0]; - obj = args[1]; + instruction_offset = args[1]; retval = args[2]; - return_value = _lsprof_Profiler__pyreturn_callback_impl(self, code, obj, retval); + return_value = _lsprof_Profiler__pyreturn_callback_impl(self, code, instruction_offset, retval); exit: return return_value; } PyDoc_STRVAR(_lsprof_Profiler__ccall_callback__doc__, -"_ccall_callback($self, code, obj, callable, self_arg, /)\n" +"_ccall_callback($self, code, instruction_offset, callable, self_arg, /)\n" "--\n" "\n"); @@ -121,15 +122,15 @@ PyDoc_STRVAR(_lsprof_Profiler__ccall_callback__doc__, static PyObject * _lsprof_Profiler__ccall_callback_impl(ProfilerObject *self, PyObject *code, - PyObject *obj, PyObject *callable, - PyObject *self_arg); + PyObject *instruction_offset, + PyObject *callable, PyObject *self_arg); static PyObject * _lsprof_Profiler__ccall_callback(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *code; - PyObject *obj; + PyObject *instruction_offset; PyObject *callable; PyObject *self_arg; @@ -137,17 +138,18 @@ _lsprof_Profiler__ccall_callback(ProfilerObject *self, PyObject *const *args, Py goto exit; } code = args[0]; - obj = args[1]; + instruction_offset = args[1]; callable = args[2]; self_arg = args[3]; - return_value = _lsprof_Profiler__ccall_callback_impl(self, code, obj, callable, self_arg); + return_value = _lsprof_Profiler__ccall_callback_impl(self, code, instruction_offset, callable, self_arg); exit: return return_value; } PyDoc_STRVAR(_lsprof_Profiler__creturn_callback__doc__, -"_creturn_callback($self, code, obj, callable, self_arg, /)\n" +"_creturn_callback($self, code, instruction_offset, callable, self_arg,\n" +" /)\n" "--\n" "\n"); @@ -156,7 +158,8 @@ PyDoc_STRVAR(_lsprof_Profiler__creturn_callback__doc__, static PyObject * _lsprof_Profiler__creturn_callback_impl(ProfilerObject *self, PyObject *code, - PyObject *obj, PyObject *callable, + PyObject *instruction_offset, + PyObject *callable, PyObject *self_arg); static PyObject * @@ -164,7 +167,7 @@ _lsprof_Profiler__creturn_callback(ProfilerObject *self, PyObject *const *args, { PyObject *return_value = NULL; PyObject *code; - PyObject *obj; + PyObject *instruction_offset; PyObject *callable; PyObject *self_arg; @@ -172,12 +175,12 @@ _lsprof_Profiler__creturn_callback(ProfilerObject *self, PyObject *const *args, goto exit; } code = args[0]; - obj = args[1]; + instruction_offset = args[1]; callable = args[2]; self_arg = args[3]; - return_value = _lsprof_Profiler__creturn_callback_impl(self, code, obj, callable, self_arg); + return_value = _lsprof_Profiler__creturn_callback_impl(self, code, instruction_offset, callable, self_arg); exit: return return_value; } -/*[clinic end generated code: output=79b2515a0d296f7d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ee788c83b5c85fb1 input=a9049054013a1b77]*/ From e3160e3d08e82e8a414660169b88f29501362d07 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 2 Nov 2024 01:08:39 +0300 Subject: [PATCH 5/9] Convert all methods --- .../pycore_global_objects_fini_generated.h | 3 + Include/internal/pycore_global_strings.h | 3 + .../internal/pycore_runtime_init_generated.h | 3 + .../internal/pycore_unicodeobject_generated.h | 12 + Modules/_lsprof.c | 140 ++++++----- Modules/clinic/_lsprof.c.h | 222 +++++++++++++++++- 6 files changed, 310 insertions(+), 73 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 2fd7d5d13a98b2..e4f0138e17edfa 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1231,6 +1231,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(strict_mode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(string)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sub_key)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(subcalls)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(symmetric_difference_update)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tabsize)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tag)); @@ -1248,8 +1249,10 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(threading)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(throw)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timeout)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timer)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(times)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timetuple)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timeunit)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(top)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(trace_callback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(traceback)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index fc3871570cc49d..e70f11e2a26cd5 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -720,6 +720,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(strict_mode) STRUCT_FOR_ID(string) STRUCT_FOR_ID(sub_key) + STRUCT_FOR_ID(subcalls) STRUCT_FOR_ID(symmetric_difference_update) STRUCT_FOR_ID(tabsize) STRUCT_FOR_ID(tag) @@ -737,8 +738,10 @@ struct _Py_global_strings { STRUCT_FOR_ID(threading) STRUCT_FOR_ID(throw) STRUCT_FOR_ID(timeout) + STRUCT_FOR_ID(timer) STRUCT_FOR_ID(times) STRUCT_FOR_ID(timetuple) + STRUCT_FOR_ID(timeunit) STRUCT_FOR_ID(top) STRUCT_FOR_ID(trace_callback) STRUCT_FOR_ID(traceback) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 3b80e265b0ca50..5d404c8fd91ca6 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1229,6 +1229,7 @@ extern "C" { INIT_ID(strict_mode), \ INIT_ID(string), \ INIT_ID(sub_key), \ + INIT_ID(subcalls), \ INIT_ID(symmetric_difference_update), \ INIT_ID(tabsize), \ INIT_ID(tag), \ @@ -1246,8 +1247,10 @@ extern "C" { INIT_ID(threading), \ INIT_ID(throw), \ INIT_ID(timeout), \ + INIT_ID(timer), \ INIT_ID(times), \ INIT_ID(timetuple), \ + INIT_ID(timeunit), \ INIT_ID(top), \ INIT_ID(trace_callback), \ INIT_ID(traceback), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index eb2eca06ec4d4f..d0bc8d7186c053 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -2676,6 +2676,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(subcalls); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(symmetric_difference_update); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2744,6 +2748,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(timer); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(times); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2752,6 +2760,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(timeunit); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(top); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index fa26d2b4f77a58..614a49b4619b49 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -750,27 +750,27 @@ static const struct { {0, NULL} }; -PyDoc_STRVAR(enable_doc, "\ -enable(subcalls=True, builtins=True)\n\ -\n\ -Start collecting profiling information.\n\ -If 'subcalls' is True, also records for each function\n\ -statistics separated according to its current caller.\n\ -If 'builtins' is True, records the time spent in\n\ -built-in functions separately from their caller.\n\ -"); - -static PyObject* -profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds) + +/*[clinic input] +_lsprof.Profiler.enable + + subcalls: bool = True + builtins: bool = True + +Start collecting profiling information. + +If 'subcalls' is True, also records for each function +statistics separated according to its current caller. +If 'builtins' is True, records the time spent in +built-in functions separately from their caller. +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler_enable_impl(ProfilerObject *self, int subcalls, + int builtins) +/*[clinic end generated code: output=1e747f9dc1edd571 input=0b6049b4e398781f]*/ { - int subcalls = -1; - int builtins = -1; - static char *kwlist[] = {"subcalls", "builtins", 0}; int all_events = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|pp:enable", - kwlist, &subcalls, &builtins)) - return NULL; if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) { return NULL; } @@ -826,14 +826,16 @@ flush_unmatched(ProfilerObject *pObj) } -PyDoc_STRVAR(disable_doc, "\ -disable()\n\ -\n\ -Stop collecting profiling information.\n\ -"); -static PyObject* -profiler_disable(ProfilerObject *self, PyObject* Py_UNUSED(unused)) +/*[clinic input] +_lsprof.Profiler.disable + +Stop collecting profiling information. +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler_disable_impl(ProfilerObject *self) +/*[clinic end generated code: output=838cffef7f651870 input=05700b3fc68d1f50]*/ { if (self->flags & POF_EXT_TIMER) { PyErr_SetString(PyExc_RuntimeError, @@ -884,21 +886,22 @@ profiler_disable(ProfilerObject *self, PyObject* Py_UNUSED(unused)) Py_RETURN_NONE; } -PyDoc_STRVAR(clear_doc, "\ -clear()\n\ -\n\ -Clear all profiling information collected so far.\n\ -"); +/*[clinic input] +_lsprof.Profiler.clear + +Clear all profiling information collected so far. +[clinic start generated code]*/ -static PyObject* -profiler_clear(ProfilerObject *pObj, PyObject* noarg) +static PyObject * +_lsprof_Profiler_clear_impl(ProfilerObject *self) +/*[clinic end generated code: output=dd1c668fb84b1335 input=fbe1f88c28be4f98]*/ { - if (pObj->flags & POF_EXT_TIMER) { + if (self->flags & POF_EXT_TIMER) { PyErr_SetString(PyExc_RuntimeError, "cannot clear profiler in external timer"); return NULL; } - clearEntries(pObj); + clearEntries(self); Py_RETURN_NONE; } @@ -929,33 +932,39 @@ profiler_dealloc(ProfilerObject *op) Py_DECREF(tp); } +/*[clinic input] +_lsprof.Profiler.__init__ + + timer: object(c_default='NULL') = None + timeunit: double = 0.0 + subcalls: bool = True + builtins: bool = True + +Builds a profiler object using the specified timer function. + +The default timer is a fast built-in one based on real time. +For custom timer functions returning integers, timeunit can +be a float specifying a scale (i.e. how long each integer unit +is, in seconds). +[clinic start generated code]*/ + static int -profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw) +_lsprof_Profiler___init___impl(ProfilerObject *self, PyObject *timer, + double timeunit, int subcalls, int builtins) +/*[clinic end generated code: output=ab5498359fd34283 input=40225117dd22d4d7]*/ { - PyObject *timer = NULL; - double timeunit = 0.0; - int subcalls = 1; - int builtins = 1; - static char *kwlist[] = {"timer", "timeunit", - "subcalls", "builtins", 0}; - - if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odpp:Profiler", kwlist, - &timer, &timeunit, - &subcalls, &builtins)) + if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) return -1; - - if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0) - return -1; - pObj->externalTimerUnit = timeunit; - Py_XSETREF(pObj->externalTimer, Py_XNewRef(timer)); - pObj->tool_id = PY_MONITORING_PROFILER_ID; + self->externalTimerUnit = timeunit; + Py_XSETREF(self->externalTimer, Py_XNewRef(timer)); + self->tool_id = PY_MONITORING_PROFILER_ID; PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); if (!monitoring) { return -1; } - pObj->missing = PyObject_GetAttrString(monitoring, "MISSING"); - if (!pObj->missing) { + self->missing = PyObject_GetAttrString(monitoring, "MISSING"); + if (!self->missing) { Py_DECREF(monitoring); return -1; } @@ -965,12 +974,9 @@ profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw) static PyMethodDef profiler_methods[] = { _LSPROF_PROFILER_GETSTATS_METHODDEF - {"enable", _PyCFunction_CAST(profiler_enable), - METH_VARARGS | METH_KEYWORDS, enable_doc}, - {"disable", (PyCFunction)profiler_disable, - METH_NOARGS, disable_doc}, - {"clear", (PyCFunction)profiler_clear, - METH_NOARGS, clear_doc}, + _LSPROF_PROFILER_ENABLE_METHODDEF + _LSPROF_PROFILER_DISABLE_METHODDEF + _LSPROF_PROFILER_CLEAR_METHODDEF _LSPROF_PROFILER__PYSTART_CALLBACK_METHODDEF _LSPROF_PROFILER__PYRETURN_CALLBACK_METHODDEF _LSPROF_PROFILER__CCALL_CALLBACK_METHODDEF @@ -978,21 +984,11 @@ static PyMethodDef profiler_methods[] = { {NULL, NULL} }; -PyDoc_STRVAR(profiler_doc, "\ -Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\ -\n\ - Builds a profiler object using the specified timer function.\n\ - The default timer is a fast built-in one based on real time.\n\ - For custom timer functions returning integers, timeunit can\n\ - be a float specifying a scale (i.e. how long each integer unit\n\ - is, in seconds).\n\ -"); - static PyType_Slot _lsprof_profiler_type_spec_slots[] = { - {Py_tp_doc, (void *)profiler_doc}, + {Py_tp_doc, (void *)_lsprof_Profiler___init____doc__}, {Py_tp_methods, profiler_methods}, {Py_tp_dealloc, profiler_dealloc}, - {Py_tp_init, profiler_init}, + {Py_tp_init, _lsprof_Profiler___init__}, {Py_tp_traverse, profiler_traverse}, {0, 0} }; diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h index b35c5e12bdeb44..b6f829441fd3d6 100644 --- a/Modules/clinic/_lsprof.c.h +++ b/Modules/clinic/_lsprof.c.h @@ -2,6 +2,10 @@ preserve [clinic start generated code]*/ +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif #include "pycore_modsupport.h" // _PyArg_CheckPositional() PyDoc_STRVAR(_lsprof_Profiler_getstats__doc__, @@ -183,4 +187,220 @@ _lsprof_Profiler__creturn_callback(ProfilerObject *self, PyObject *const *args, exit: return return_value; } -/*[clinic end generated code: output=ee788c83b5c85fb1 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_lsprof_Profiler_enable__doc__, +"enable($self, /, subcalls=True, builtins=True)\n" +"--\n" +"\n" +"Start collecting profiling information.\n" +"\n" +"If \'subcalls\' is True, also records for each function\n" +"statistics separated according to its current caller.\n" +"If \'builtins\' is True, records the time spent in\n" +"built-in functions separately from their caller."); + +#define _LSPROF_PROFILER_ENABLE_METHODDEF \ + {"enable", _PyCFunction_CAST(_lsprof_Profiler_enable), METH_FASTCALL|METH_KEYWORDS, _lsprof_Profiler_enable__doc__}, + +static PyObject * +_lsprof_Profiler_enable_impl(ProfilerObject *self, int subcalls, + int builtins); + +static PyObject * +_lsprof_Profiler_enable(ProfilerObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(subcalls), &_Py_ID(builtins), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"subcalls", "builtins", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "enable", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + int subcalls = 1; + int builtins = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 2, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + subcalls = PyObject_IsTrue(args[0]); + if (subcalls < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + builtins = PyObject_IsTrue(args[1]); + if (builtins < 0) { + goto exit; + } +skip_optional_pos: + return_value = _lsprof_Profiler_enable_impl(self, subcalls, builtins); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lsprof_Profiler_disable__doc__, +"disable($self, /)\n" +"--\n" +"\n" +"Stop collecting profiling information."); + +#define _LSPROF_PROFILER_DISABLE_METHODDEF \ + {"disable", (PyCFunction)_lsprof_Profiler_disable, METH_NOARGS, _lsprof_Profiler_disable__doc__}, + +static PyObject * +_lsprof_Profiler_disable_impl(ProfilerObject *self); + +static PyObject * +_lsprof_Profiler_disable(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _lsprof_Profiler_disable_impl(self); +} + +PyDoc_STRVAR(_lsprof_Profiler_clear__doc__, +"clear($self, /)\n" +"--\n" +"\n" +"Clear all profiling information collected so far."); + +#define _LSPROF_PROFILER_CLEAR_METHODDEF \ + {"clear", (PyCFunction)_lsprof_Profiler_clear, METH_NOARGS, _lsprof_Profiler_clear__doc__}, + +static PyObject * +_lsprof_Profiler_clear_impl(ProfilerObject *self); + +static PyObject * +_lsprof_Profiler_clear(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _lsprof_Profiler_clear_impl(self); +} + +PyDoc_STRVAR(_lsprof_Profiler___init____doc__, +"Profiler(timer=None, timeunit=0.0, subcalls=True, builtins=True)\n" +"--\n" +"\n" +"Builds a profiler object using the specified timer function.\n" +"\n" +"The default timer is a fast built-in one based on real time.\n" +"For custom timer functions returning integers, timeunit can\n" +"be a float specifying a scale (i.e. how long each integer unit\n" +"is, in seconds)."); + +static int +_lsprof_Profiler___init___impl(ProfilerObject *self, PyObject *timer, + double timeunit, int subcalls, int builtins); + +static int +_lsprof_Profiler___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 4 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(timer), &_Py_ID(timeunit), &_Py_ID(subcalls), &_Py_ID(builtins), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"timer", "timeunit", "subcalls", "builtins", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "Profiler", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[4]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; + PyObject *timer = NULL; + double timeunit = 0.0; + int subcalls = 1; + int builtins = 1; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 0, 4, 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[0]) { + timer = fastargs[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[1]) { + if (PyFloat_CheckExact(fastargs[1])) { + timeunit = PyFloat_AS_DOUBLE(fastargs[1]); + } + else + { + timeunit = PyFloat_AsDouble(fastargs[1]); + if (timeunit == -1.0 && PyErr_Occurred()) { + goto exit; + } + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[2]) { + subcalls = PyObject_IsTrue(fastargs[2]); + if (subcalls < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + builtins = PyObject_IsTrue(fastargs[3]); + if (builtins < 0) { + goto exit; + } +skip_optional_pos: + return_value = _lsprof_Profiler___init___impl((ProfilerObject *)self, timer, timeunit, subcalls, builtins); + +exit: + return return_value; +} +/*[clinic end generated code: output=c0861e64aeb19d43 input=a9049054013a1b77]*/ From 3cea189c3614618d20a74edf31dece03b3bc00e0 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 2 Nov 2024 08:30:53 +0300 Subject: [PATCH 6/9] Apply suggestions from code review Co-authored-by: Erlend E. Aasland --- Modules/_lsprof.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 614a49b4619b49..6c8212c7076cd1 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -940,11 +940,11 @@ _lsprof.Profiler.__init__ subcalls: bool = True builtins: bool = True -Builds a profiler object using the specified timer function. +Build a profiler object using the specified timer function. The default timer is a fast built-in one based on real time. -For custom timer functions returning integers, timeunit can -be a float specifying a scale (i.e. how long each integer unit +For custom timer functions returning integers, 'timeunit' can +be a float specifying a scale (that is, how long each integer unit is, in seconds). [clinic start generated code]*/ From b84dde3911e6965cca84013d49b6814839f0fe65 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 2 Nov 2024 08:35:25 +0300 Subject: [PATCH 7/9] Address review --- Modules/_lsprof.c | 12 ++++++------ Modules/clinic/_lsprof.c.h | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 6c8212c7076cd1..53bbdd371a4eaf 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -933,7 +933,7 @@ profiler_dealloc(ProfilerObject *op) } /*[clinic input] -_lsprof.Profiler.__init__ +_lsprof.Profiler.__init__ as profile_init timer: object(c_default='NULL') = None timeunit: double = 0.0 @@ -949,9 +949,9 @@ is, in seconds). [clinic start generated code]*/ static int -_lsprof_Profiler___init___impl(ProfilerObject *self, PyObject *timer, - double timeunit, int subcalls, int builtins) -/*[clinic end generated code: output=ab5498359fd34283 input=40225117dd22d4d7]*/ +profile_init_impl(ProfilerObject *self, PyObject *timer, double timeunit, + int subcalls, int builtins) +/*[clinic end generated code: output=123b1ff3fc783e14 input=25202b9566e5441c]*/ { if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) return -1; @@ -985,10 +985,10 @@ static PyMethodDef profiler_methods[] = { }; static PyType_Slot _lsprof_profiler_type_spec_slots[] = { - {Py_tp_doc, (void *)_lsprof_Profiler___init____doc__}, + {Py_tp_doc, (void *)profile_init__doc__}, {Py_tp_methods, profiler_methods}, {Py_tp_dealloc, profiler_dealloc}, - {Py_tp_init, _lsprof_Profiler___init__}, + {Py_tp_init, profile_init}, {Py_tp_traverse, profiler_traverse}, {0, 0} }; diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h index b6f829441fd3d6..2a14889a2fd531 100644 --- a/Modules/clinic/_lsprof.c.h +++ b/Modules/clinic/_lsprof.c.h @@ -303,23 +303,23 @@ _lsprof_Profiler_clear(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) return _lsprof_Profiler_clear_impl(self); } -PyDoc_STRVAR(_lsprof_Profiler___init____doc__, +PyDoc_STRVAR(profile_init__doc__, "Profiler(timer=None, timeunit=0.0, subcalls=True, builtins=True)\n" "--\n" "\n" -"Builds a profiler object using the specified timer function.\n" +"Build a profiler object using the specified timer function.\n" "\n" "The default timer is a fast built-in one based on real time.\n" -"For custom timer functions returning integers, timeunit can\n" -"be a float specifying a scale (i.e. how long each integer unit\n" +"For custom timer functions returning integers, \'timeunit\' can\n" +"be a float specifying a scale (that is, how long each integer unit\n" "is, in seconds)."); static int -_lsprof_Profiler___init___impl(ProfilerObject *self, PyObject *timer, - double timeunit, int subcalls, int builtins); +profile_init_impl(ProfilerObject *self, PyObject *timer, double timeunit, + int subcalls, int builtins); static int -_lsprof_Profiler___init__(PyObject *self, PyObject *args, PyObject *kwargs) +profile_init(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -398,9 +398,9 @@ _lsprof_Profiler___init__(PyObject *self, PyObject *args, PyObject *kwargs) goto exit; } skip_optional_pos: - return_value = _lsprof_Profiler___init___impl((ProfilerObject *)self, timer, timeunit, subcalls, builtins); + return_value = profile_init_impl((ProfilerObject *)self, timer, timeunit, subcalls, builtins); exit: return return_value; } -/*[clinic end generated code: output=c0861e64aeb19d43 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1d1db1dcbb6b10d7 input=a9049054013a1b77]*/ From bf3e120d199a0620896d262c8c36821592032547 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 2 Nov 2024 08:36:51 +0300 Subject: [PATCH 8/9] Typo --- Modules/_lsprof.c | 12 ++++++------ Modules/clinic/_lsprof.c.h | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 53bbdd371a4eaf..3b123f4d2d8c9d 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -933,7 +933,7 @@ profiler_dealloc(ProfilerObject *op) } /*[clinic input] -_lsprof.Profiler.__init__ as profile_init +_lsprof.Profiler.__init__ as profiler_init timer: object(c_default='NULL') = None timeunit: double = 0.0 @@ -949,9 +949,9 @@ is, in seconds). [clinic start generated code]*/ static int -profile_init_impl(ProfilerObject *self, PyObject *timer, double timeunit, - int subcalls, int builtins) -/*[clinic end generated code: output=123b1ff3fc783e14 input=25202b9566e5441c]*/ +profiler_init_impl(ProfilerObject *self, PyObject *timer, double timeunit, + int subcalls, int builtins) +/*[clinic end generated code: output=ac523803ec9f9df2 input=8285ca746f96a414]*/ { if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) return -1; @@ -985,10 +985,10 @@ static PyMethodDef profiler_methods[] = { }; static PyType_Slot _lsprof_profiler_type_spec_slots[] = { - {Py_tp_doc, (void *)profile_init__doc__}, + {Py_tp_doc, (void *)profiler_init__doc__}, {Py_tp_methods, profiler_methods}, {Py_tp_dealloc, profiler_dealloc}, - {Py_tp_init, profile_init}, + {Py_tp_init, profiler_init}, {Py_tp_traverse, profiler_traverse}, {0, 0} }; diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h index 2a14889a2fd531..65a2577e7078db 100644 --- a/Modules/clinic/_lsprof.c.h +++ b/Modules/clinic/_lsprof.c.h @@ -303,7 +303,7 @@ _lsprof_Profiler_clear(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) return _lsprof_Profiler_clear_impl(self); } -PyDoc_STRVAR(profile_init__doc__, +PyDoc_STRVAR(profiler_init__doc__, "Profiler(timer=None, timeunit=0.0, subcalls=True, builtins=True)\n" "--\n" "\n" @@ -315,11 +315,11 @@ PyDoc_STRVAR(profile_init__doc__, "is, in seconds)."); static int -profile_init_impl(ProfilerObject *self, PyObject *timer, double timeunit, - int subcalls, int builtins); +profiler_init_impl(ProfilerObject *self, PyObject *timer, double timeunit, + int subcalls, int builtins); static int -profile_init(PyObject *self, PyObject *args, PyObject *kwargs) +profiler_init(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) @@ -398,9 +398,9 @@ profile_init(PyObject *self, PyObject *args, PyObject *kwargs) goto exit; } skip_optional_pos: - return_value = profile_init_impl((ProfilerObject *)self, timer, timeunit, subcalls, builtins); + return_value = profiler_init_impl((ProfilerObject *)self, timer, timeunit, subcalls, builtins); exit: return return_value; } -/*[clinic end generated code: output=1d1db1dcbb6b10d7 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3750676abdc066ae input=a9049054013a1b77]*/ From 0d35f6074483fdd94e7485ac1269d8e5391db99a Mon Sep 17 00:00:00 2001 From: sobolevn Date: Mon, 4 Nov 2024 11:37:21 +0300 Subject: [PATCH 9/9] Address review --- Modules/_lsprof.c | 15 ++++++++------- Modules/clinic/_lsprof.c.h | 12 +++++++----- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 3b123f4d2d8c9d..4f996c7230e16d 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -755,20 +755,20 @@ static const struct { _lsprof.Profiler.enable subcalls: bool = True + If True, also records for each function + statistics separated according to its current caller. + builtins: bool = True + If True, records the time spent in + built-in functions separately from their caller. Start collecting profiling information. - -If 'subcalls' is True, also records for each function -statistics separated according to its current caller. -If 'builtins' is True, records the time spent in -built-in functions separately from their caller. [clinic start generated code]*/ static PyObject * _lsprof_Profiler_enable_impl(ProfilerObject *self, int subcalls, int builtins) -/*[clinic end generated code: output=1e747f9dc1edd571 input=0b6049b4e398781f]*/ +/*[clinic end generated code: output=1e747f9dc1edd571 input=9ab81405107ab7f1]*/ { int all_events = 0; if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) { @@ -953,8 +953,9 @@ profiler_init_impl(ProfilerObject *self, PyObject *timer, double timeunit, int subcalls, int builtins) /*[clinic end generated code: output=ac523803ec9f9df2 input=8285ca746f96a414]*/ { - if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) + if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) { return -1; + } self->externalTimerUnit = timeunit; Py_XSETREF(self->externalTimer, Py_XNewRef(timer)); self->tool_id = PY_MONITORING_PROFILER_ID; diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h index 65a2577e7078db..234cc9ef3c0eaf 100644 --- a/Modules/clinic/_lsprof.c.h +++ b/Modules/clinic/_lsprof.c.h @@ -194,10 +194,12 @@ PyDoc_STRVAR(_lsprof_Profiler_enable__doc__, "\n" "Start collecting profiling information.\n" "\n" -"If \'subcalls\' is True, also records for each function\n" -"statistics separated according to its current caller.\n" -"If \'builtins\' is True, records the time spent in\n" -"built-in functions separately from their caller."); +" subcalls\n" +" If True, also records for each function\n" +" statistics separated according to its current caller.\n" +" builtins\n" +" If True, records the time spent in\n" +" built-in functions separately from their caller."); #define _LSPROF_PROFILER_ENABLE_METHODDEF \ {"enable", _PyCFunction_CAST(_lsprof_Profiler_enable), METH_FASTCALL|METH_KEYWORDS, _lsprof_Profiler_enable__doc__}, @@ -403,4 +405,4 @@ profiler_init(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=3750676abdc066ae input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0b71f52bee9a7bb1 input=a9049054013a1b77]*/