bpo-1635741: Port _lsprof extension to multi-phase init (PEP 489) (GH-22220)

This commit is contained in:
Mohamed Koubaa 2020-09-23 05:33:21 -05:00 committed by GitHub
parent 438e9fc66f
commit 83de110dce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 139 additions and 99 deletions

View File

@ -0,0 +1,2 @@
Port the :mod:`_lsprof` extension module to multi-phase initialization
(:pep:`489`).

View File

@ -55,12 +55,22 @@ module _lsprof
class _lsprof.Profiler "ProfilerObject *" "&ProfilerType" class _lsprof.Profiler "ProfilerObject *" "&ProfilerType"
[clinic start generated code]*/ [clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e349ac952152f336]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e349ac952152f336]*/
static PyTypeObject PyProfiler_Type;
#include "clinic/_lsprof.c.h" #include "clinic/_lsprof.c.h"
#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type) typedef struct {
#define PyProfiler_CheckExact(op) Py_IS_TYPE(op, &PyProfiler_Type) 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 ***/ /*** External Timers ***/
@ -478,28 +488,24 @@ static PyStructSequence_Field profiler_subentry_fields[] = {
}; };
static PyStructSequence_Desc profiler_entry_desc = { static PyStructSequence_Desc profiler_entry_desc = {
"_lsprof.profiler_entry", /* name */ .name = "_lsprof.profiler_entry",
NULL, /* doc */ .doc = "",
profiler_entry_fields, .fields = profiler_entry_fields,
6 .n_in_sequence = 6
}; };
static PyStructSequence_Desc profiler_subentry_desc = { static PyStructSequence_Desc profiler_subentry_desc = {
"_lsprof.profiler_subentry", /* name */ .name = "_lsprof.profiler_subentry",
NULL, /* doc */ .doc = "",
profiler_subentry_fields, .fields = profiler_subentry_fields,
5 .n_in_sequence = 5
}; };
static int initialized;
static PyTypeObject StatsEntryType;
static PyTypeObject StatsSubEntryType;
typedef struct { typedef struct {
PyObject *list; PyObject *list;
PyObject *sublist; PyObject *sublist;
double factor; double factor;
_lsprof_state *state;
} statscollector_t; } statscollector_t;
static int statsForSubEntry(rotating_node_t *node, void *arg) 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; ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
int err; int err;
PyObject *sinfo; PyObject *sinfo;
sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType, sinfo = PyObject_CallFunction((PyObject*) collect->state->stats_subentry_type,
"((Olldd))", "((Olldd))",
entry->userObj, entry->userObj,
sentry->callcount, sentry->callcount,
@ -547,7 +553,7 @@ static int statsForEntry(rotating_node_t *node, void *arg)
collect->sublist = Py_None; collect->sublist = Py_None;
} }
info = PyObject_CallFunction((PyObject*) &StatsEntryType, info = PyObject_CallFunction((PyObject*) collect->state->stats_entry_type,
"((OllddO))", "((OllddO))",
entry->userObj, entry->userObj,
entry->callcount, entry->callcount,
@ -566,6 +572,8 @@ static int statsForEntry(rotating_node_t *node, void *arg)
/*[clinic input] /*[clinic input]
_lsprof.Profiler.getstats _lsprof.Profiler.getstats
cls: defining_class
list of profiler_entry objects. list of profiler_entry objects.
getstats() -> list of profiler_entry objects getstats() -> list of profiler_entry objects
@ -592,10 +600,11 @@ profiler_subentry objects:
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_lsprof_Profiler_getstats_impl(ProfilerObject *self) _lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls)
/*[clinic end generated code: output=9461b451e9ef0f24 input=ade04fa384ce450a]*/ /*[clinic end generated code: output=1806ef720019ee03 input=445e193ef4522902]*/
{ {
statscollector_t collect; statscollector_t collect;
collect.state = PyType_GetModuleState(cls);
if (pending_exception(self)) { if (pending_exception(self)) {
return NULL; return NULL;
} }
@ -735,7 +744,9 @@ profiler_dealloc(ProfilerObject *op)
flush_unmatched(op); flush_unmatched(op);
clearEntries(op); clearEntries(op);
Py_XDECREF(op->externalTimer); Py_XDECREF(op->externalTimer);
Py_TYPE(op)->tp_free(op); PyTypeObject *tp = Py_TYPE(op);
tp->tp_free(op);
Py_DECREF(tp);
} }
static int static int
@ -782,91 +793,107 @@ Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\
is, in seconds).\n\ is, in seconds).\n\
"); ");
static PyTypeObject PyProfiler_Type = { static PyType_Slot _lsprof_profiler_type_spec_slots[] = {
PyVarObject_HEAD_INIT(NULL, 0) {Py_tp_doc, (void *)profiler_doc},
"_lsprof.Profiler", /* tp_name */ {Py_tp_methods, profiler_methods},
sizeof(ProfilerObject), /* tp_basicsize */ {Py_tp_dealloc, profiler_dealloc},
0, /* tp_itemsize */ {Py_tp_init, profiler_init},
(destructor)profiler_dealloc, /* tp_dealloc */ {Py_tp_alloc, PyType_GenericAlloc},
0, /* tp_vectorcall_offset */ {Py_tp_new, PyType_GenericNew},
0, /* tp_getattr */ {Py_tp_free, PyObject_Del},
0, /* tp_setattr */ {0, 0}
0, /* tp_as_async */ };
0, /* tp_repr */
0, /* tp_as_number */ static PyType_Spec _lsprof_profiler_type_spec = {
0, /* tp_as_sequence */ .name = "_lsprof.Profiler",
0, /* tp_as_mapping */ .basicsize = sizeof(ProfilerObject),
0, /* tp_hash */ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
0, /* tp_call */ .slots = _lsprof_profiler_type_spec_slots,
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 PyMethodDef moduleMethods[] = { static PyMethodDef moduleMethods[] = {
{NULL, NULL} {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 = { static struct PyModuleDef _lsprofmodule = {
PyModuleDef_HEAD_INIT, PyModuleDef_HEAD_INIT,
"_lsprof", .m_name = "_lsprof",
"Fast profiler", .m_doc = "Fast profiler",
-1, .m_size = sizeof(_lsprof_state),
moduleMethods, .m_methods = moduleMethods,
NULL, .m_slots = _lsprofslots,
NULL, .m_traverse = _lsprof_traverse,
NULL, .m_clear = _lsprof_clear,
NULL .m_free = _lsprof_free
}; };
PyMODINIT_FUNC PyMODINIT_FUNC
PyInit__lsprof(void) PyInit__lsprof(void)
{ {
PyObject *module, *d; return PyModuleDef_Init(&_lsprofmodule);
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;
} }

View File

@ -31,14 +31,25 @@ PyDoc_STRVAR(_lsprof_Profiler_getstats__doc__,
" inlinetime inline time (not in further subcalls)"); " inlinetime inline time (not in further subcalls)");
#define _LSPROF_PROFILER_GETSTATS_METHODDEF \ #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 * static PyObject *
_lsprof_Profiler_getstats_impl(ProfilerObject *self); _lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls);
static PyObject * 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;
} }
/*[clinic end generated code: output=24c525812713e00f input=a9049054013a1b77]*/ return_value = _lsprof_Profiler_getstats_impl(self, cls);
exit:
return return_value;
}
/*[clinic end generated code: output=b4727cfebecdd22d input=a9049054013a1b77]*/