bpo-1635741: Port _lsprof extension to multi-phase init (PEP 489) (GH-22220)
This commit is contained in:
parent
438e9fc66f
commit
83de110dce
|
@ -0,0 +1,2 @@
|
||||||
|
Port the :mod:`_lsprof` extension module to multi-phase initialization
|
||||||
|
(:pep:`489`).
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]*/
|
||||||
|
|
Loading…
Reference in New Issue