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

Mohamed Koubaa webhook-mailer at python.org
Wed Sep 23 06:33:49 EDT 2020


https://github.com/python/cpython/commit/83de110dce94a9196dccc01d526628615714e362
commit: 83de110dce94a9196dccc01d526628615714e362
branch: master
author: Mohamed Koubaa <koubaa.m at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020-09-23T12:33:21+02:00
summary:

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

files:
A Misc/NEWS.d/next/Core and Builtins/2020-09-12-18-34-34.bpo-1635741.lh335O.rst
M Modules/_lsprof.c
M Modules/clinic/_lsprof.c.h

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 0000000000000..ba61819df9e08
--- /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 a4ba7d5230033..78d464d1481d7 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 50762e3ff3596..5d9c209eab856 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]*/



More information about the Python-checkins mailing list