diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-09-12-18-34-34.bpo-1635741.lh335O.rst b/Misc/NEWS.d/next/Core and Builtins/2020-09-12-18-34-34.bpo-1635741.lh335O.rst new file mode 100644 index 00000000000..ba61819df9e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-09-12-18-34-34.bpo-1635741.lh335O.rst @@ -0,0 +1,2 @@ +Port the :mod:`_lsprof` extension module to multi-phase initialization +(:pep:`489`). diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index a4ba7d52300..78d464d1481 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -55,12 +55,22 @@ module _lsprof class _lsprof.Profiler "ProfilerObject *" "&ProfilerType" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e349ac952152f336]*/ -static PyTypeObject PyProfiler_Type; #include "clinic/_lsprof.c.h" -#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type) -#define PyProfiler_CheckExact(op) Py_IS_TYPE(op, &PyProfiler_Type) +typedef struct { + PyTypeObject *profiler_type; + PyTypeObject *stats_entry_type; + PyTypeObject *stats_subentry_type; +} _lsprof_state; + +static inline _lsprof_state* +_lsprof_get_state(PyObject *module) +{ + void *state = PyModule_GetState(module); + assert(state != NULL); + return (_lsprof_state *)state; +} /*** External Timers ***/ @@ -478,28 +488,24 @@ static PyStructSequence_Field profiler_subentry_fields[] = { }; static PyStructSequence_Desc profiler_entry_desc = { - "_lsprof.profiler_entry", /* name */ - NULL, /* doc */ - profiler_entry_fields, - 6 + .name = "_lsprof.profiler_entry", + .doc = "", + .fields = profiler_entry_fields, + .n_in_sequence = 6 }; static PyStructSequence_Desc profiler_subentry_desc = { - "_lsprof.profiler_subentry", /* name */ - NULL, /* doc */ - profiler_subentry_fields, - 5 + .name = "_lsprof.profiler_subentry", + .doc = "", + .fields = profiler_subentry_fields, + .n_in_sequence = 5 }; -static int initialized; -static PyTypeObject StatsEntryType; -static PyTypeObject StatsSubEntryType; - - typedef struct { PyObject *list; PyObject *sublist; double factor; + _lsprof_state *state; } statscollector_t; static int statsForSubEntry(rotating_node_t *node, void *arg) @@ -509,7 +515,7 @@ static int statsForSubEntry(rotating_node_t *node, void *arg) ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key; int err; PyObject *sinfo; - sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType, + sinfo = PyObject_CallFunction((PyObject*) collect->state->stats_subentry_type, "((Olldd))", entry->userObj, sentry->callcount, @@ -547,7 +553,7 @@ static int statsForEntry(rotating_node_t *node, void *arg) collect->sublist = Py_None; } - info = PyObject_CallFunction((PyObject*) &StatsEntryType, + info = PyObject_CallFunction((PyObject*) collect->state->stats_entry_type, "((OllddO))", entry->userObj, entry->callcount, @@ -566,6 +572,8 @@ static int statsForEntry(rotating_node_t *node, void *arg) /*[clinic input] _lsprof.Profiler.getstats + cls: defining_class + list of profiler_entry objects. getstats() -> list of profiler_entry objects @@ -592,10 +600,11 @@ profiler_subentry objects: [clinic start generated code]*/ static PyObject * -_lsprof_Profiler_getstats_impl(ProfilerObject *self) -/*[clinic end generated code: output=9461b451e9ef0f24 input=ade04fa384ce450a]*/ +_lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=1806ef720019ee03 input=445e193ef4522902]*/ { statscollector_t collect; + collect.state = PyType_GetModuleState(cls); if (pending_exception(self)) { return NULL; } @@ -735,7 +744,9 @@ profiler_dealloc(ProfilerObject *op) flush_unmatched(op); clearEntries(op); Py_XDECREF(op->externalTimer); - Py_TYPE(op)->tp_free(op); + PyTypeObject *tp = Py_TYPE(op); + tp->tp_free(op); + Py_DECREF(tp); } static int @@ -782,91 +793,107 @@ Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\ is, in seconds).\n\ "); -static PyTypeObject PyProfiler_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_lsprof.Profiler", /* tp_name */ - sizeof(ProfilerObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)profiler_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - profiler_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - profiler_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)profiler_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - PyObject_Del, /* tp_free */ +static PyType_Slot _lsprof_profiler_type_spec_slots[] = { + {Py_tp_doc, (void *)profiler_doc}, + {Py_tp_methods, profiler_methods}, + {Py_tp_dealloc, profiler_dealloc}, + {Py_tp_init, profiler_init}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, PyType_GenericNew}, + {Py_tp_free, PyObject_Del}, + {0, 0} +}; + +static PyType_Spec _lsprof_profiler_type_spec = { + .name = "_lsprof.Profiler", + .basicsize = sizeof(ProfilerObject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .slots = _lsprof_profiler_type_spec_slots, }; static PyMethodDef moduleMethods[] = { {NULL, NULL} }; +static int +_lsprof_traverse(PyObject *module, visitproc visit, void *arg) +{ + _lsprof_state *state = _lsprof_get_state(module); + Py_VISIT(state->profiler_type); + Py_VISIT(state->stats_entry_type); + Py_VISIT(state->stats_subentry_type); + return 0; +} + +static int +_lsprof_clear(PyObject *module) +{ + _lsprof_state *state = _lsprof_get_state(module); + Py_CLEAR(state->profiler_type); + Py_CLEAR(state->stats_entry_type); + Py_CLEAR(state->stats_subentry_type); + return 0; +} + +static void +_lsprof_free(void *module) +{ + _lsprof_clear((PyObject *)module); +} + +static int +_lsprof_exec(PyObject *module) +{ + _lsprof_state *state = PyModule_GetState(module); + + state->profiler_type = (PyTypeObject *)PyType_FromModuleAndSpec( + module, &_lsprof_profiler_type_spec, NULL); + if (state->profiler_type == NULL) { + return -1; + } + + if (PyModule_AddType(module, state->profiler_type) < 0) { + return -1; + } + + state->stats_entry_type = PyStructSequence_NewType(&profiler_entry_desc); + if (state->stats_entry_type == NULL) { + return -1; + } + if (PyModule_AddType(module, state->stats_entry_type) < 0) { + return -1; + } + + state->stats_subentry_type = PyStructSequence_NewType(&profiler_subentry_desc); + if (state->stats_subentry_type == NULL) { + return -1; + } + if (PyModule_AddType(module, state->stats_subentry_type) < 0) { + return -1; + } + + return 0; +} + +static PyModuleDef_Slot _lsprofslots[] = { + {Py_mod_exec, _lsprof_exec}, + {0, NULL} +}; static struct PyModuleDef _lsprofmodule = { PyModuleDef_HEAD_INIT, - "_lsprof", - "Fast profiler", - -1, - moduleMethods, - NULL, - NULL, - NULL, - NULL + .m_name = "_lsprof", + .m_doc = "Fast profiler", + .m_size = sizeof(_lsprof_state), + .m_methods = moduleMethods, + .m_slots = _lsprofslots, + .m_traverse = _lsprof_traverse, + .m_clear = _lsprof_clear, + .m_free = _lsprof_free }; PyMODINIT_FUNC PyInit__lsprof(void) { - PyObject *module, *d; - module = PyModule_Create(&_lsprofmodule); - if (module == NULL) - return NULL; - d = PyModule_GetDict(module); - if (PyType_Ready(&PyProfiler_Type) < 0) - return NULL; - PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type); - - if (!initialized) { - if (PyStructSequence_InitType2(&StatsEntryType, - &profiler_entry_desc) < 0) - return NULL; - if (PyStructSequence_InitType2(&StatsSubEntryType, - &profiler_subentry_desc) < 0) - return NULL; - } - Py_INCREF((PyObject*) &StatsEntryType); - Py_INCREF((PyObject*) &StatsSubEntryType); - PyModule_AddObject(module, "profiler_entry", - (PyObject*) &StatsEntryType); - PyModule_AddObject(module, "profiler_subentry", - (PyObject*) &StatsSubEntryType); - initialized = 1; - return module; + return PyModuleDef_Init(&_lsprofmodule); } diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h index 50762e3ff35..5d9c209eab8 100644 --- a/Modules/clinic/_lsprof.c.h +++ b/Modules/clinic/_lsprof.c.h @@ -31,14 +31,25 @@ PyDoc_STRVAR(_lsprof_Profiler_getstats__doc__, " inlinetime inline time (not in further subcalls)"); #define _LSPROF_PROFILER_GETSTATS_METHODDEF \ - {"getstats", (PyCFunction)_lsprof_Profiler_getstats, METH_NOARGS, _lsprof_Profiler_getstats__doc__}, + {"getstats", (PyCFunction)(void(*)(void))_lsprof_Profiler_getstats, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _lsprof_Profiler_getstats__doc__}, static PyObject * -_lsprof_Profiler_getstats_impl(ProfilerObject *self); +_lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls); static PyObject * -_lsprof_Profiler_getstats(ProfilerObject *self, PyObject *Py_UNUSED(ignored)) +_lsprof_Profiler_getstats(ProfilerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _lsprof_Profiler_getstats_impl(self); + PyObject *return_value = NULL; + static const char * const _keywords[] = { NULL}; + static _PyArg_Parser _parser = {":getstats", _keywords, 0}; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser + )) { + goto exit; + } + return_value = _lsprof_Profiler_getstats_impl(self, cls); + +exit: + return return_value; } -/*[clinic end generated code: output=24c525812713e00f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b4727cfebecdd22d input=a9049054013a1b77]*/