summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohamed Koubaa <koubaa.m@gmail.com>2020-09-23 10:33:21 (GMT)
committerGitHub <noreply@github.com>2020-09-23 10:33:21 (GMT)
commit83de110dce94a9196dccc01d526628615714e362 (patch)
treee018ea13563651069e9f2ef2dbd8a5044630b559
parent438e9fc66f664eff0526a16a6d900349bfd1f9d2 (diff)
downloadcpython-83de110dce94a9196dccc01d526628615714e362.zip
cpython-83de110dce94a9196dccc01d526628615714e362.tar.gz
cpython-83de110dce94a9196dccc01d526628615714e362.tar.bz2
bpo-1635741: Port _lsprof extension to multi-phase init (PEP 489) (GH-22220)
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2020-09-12-18-34-34.bpo-1635741.lh335O.rst2
-rw-r--r--Modules/_lsprof.c215
-rw-r--r--Modules/clinic/_lsprof.c.h21
3 files changed, 139 insertions, 99 deletions
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 0000000..ba61819d
--- /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 a4ba7d5..78d464d 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 50762e3..5d9c209 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]*/