Skip to content

Commit 83de110

Browse files
authored
bpo-1635741: Port _lsprof extension to multi-phase init (PEP 489) (GH-22220)
1 parent 438e9fc commit 83de110

File tree

3 files changed

+139
-99
lines changed

3 files changed

+139
-99
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Port the :mod:`_lsprof` extension module to multi-phase initialization
2+
(:pep:`489`).

Modules/_lsprof.c

Lines changed: 121 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,22 @@ module _lsprof
5555
class _lsprof.Profiler "ProfilerObject *" "&ProfilerType"
5656
[clinic start generated code]*/
5757
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e349ac952152f336]*/
58-
static PyTypeObject PyProfiler_Type;
5958

6059
#include "clinic/_lsprof.c.h"
6160

62-
#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
63-
#define PyProfiler_CheckExact(op) Py_IS_TYPE(op, &PyProfiler_Type)
61+
typedef struct {
62+
PyTypeObject *profiler_type;
63+
PyTypeObject *stats_entry_type;
64+
PyTypeObject *stats_subentry_type;
65+
} _lsprof_state;
66+
67+
static inline _lsprof_state*
68+
_lsprof_get_state(PyObject *module)
69+
{
70+
void *state = PyModule_GetState(module);
71+
assert(state != NULL);
72+
return (_lsprof_state *)state;
73+
}
6474

6575
/*** External Timers ***/
6676

@@ -478,28 +488,24 @@ static PyStructSequence_Field profiler_subentry_fields[] = {
478488
};
479489

480490
static PyStructSequence_Desc profiler_entry_desc = {
481-
"_lsprof.profiler_entry", /* name */
482-
NULL, /* doc */
483-
profiler_entry_fields,
484-
6
491+
.name = "_lsprof.profiler_entry",
492+
.doc = "",
493+
.fields = profiler_entry_fields,
494+
.n_in_sequence = 6
485495
};
486496

487497
static PyStructSequence_Desc profiler_subentry_desc = {
488-
"_lsprof.profiler_subentry", /* name */
489-
NULL, /* doc */
490-
profiler_subentry_fields,
491-
5
498+
.name = "_lsprof.profiler_subentry",
499+
.doc = "",
500+
.fields = profiler_subentry_fields,
501+
.n_in_sequence = 5
492502
};
493503

494-
static int initialized;
495-
static PyTypeObject StatsEntryType;
496-
static PyTypeObject StatsSubEntryType;
497-
498-
499504
typedef struct {
500505
PyObject *list;
501506
PyObject *sublist;
502507
double factor;
508+
_lsprof_state *state;
503509
} statscollector_t;
504510

505511
static int statsForSubEntry(rotating_node_t *node, void *arg)
@@ -509,7 +515,7 @@ static int statsForSubEntry(rotating_node_t *node, void *arg)
509515
ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
510516
int err;
511517
PyObject *sinfo;
512-
sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
518+
sinfo = PyObject_CallFunction((PyObject*) collect->state->stats_subentry_type,
513519
"((Olldd))",
514520
entry->userObj,
515521
sentry->callcount,
@@ -547,7 +553,7 @@ static int statsForEntry(rotating_node_t *node, void *arg)
547553
collect->sublist = Py_None;
548554
}
549555

550-
info = PyObject_CallFunction((PyObject*) &StatsEntryType,
556+
info = PyObject_CallFunction((PyObject*) collect->state->stats_entry_type,
551557
"((OllddO))",
552558
entry->userObj,
553559
entry->callcount,
@@ -566,6 +572,8 @@ static int statsForEntry(rotating_node_t *node, void *arg)
566572
/*[clinic input]
567573
_lsprof.Profiler.getstats
568574
575+
cls: defining_class
576+
569577
list of profiler_entry objects.
570578
571579
getstats() -> list of profiler_entry objects
@@ -592,10 +600,11 @@ profiler_subentry objects:
592600
[clinic start generated code]*/
593601

594602
static PyObject *
595-
_lsprof_Profiler_getstats_impl(ProfilerObject *self)
596-
/*[clinic end generated code: output=9461b451e9ef0f24 input=ade04fa384ce450a]*/
603+
_lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls)
604+
/*[clinic end generated code: output=1806ef720019ee03 input=445e193ef4522902]*/
597605
{
598606
statscollector_t collect;
607+
collect.state = PyType_GetModuleState(cls);
599608
if (pending_exception(self)) {
600609
return NULL;
601610
}
@@ -735,7 +744,9 @@ profiler_dealloc(ProfilerObject *op)
735744
flush_unmatched(op);
736745
clearEntries(op);
737746
Py_XDECREF(op->externalTimer);
738-
Py_TYPE(op)->tp_free(op);
747+
PyTypeObject *tp = Py_TYPE(op);
748+
tp->tp_free(op);
749+
Py_DECREF(tp);
739750
}
740751

741752
static int
@@ -782,91 +793,107 @@ Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\
782793
is, in seconds).\n\
783794
");
784795

785-
static PyTypeObject PyProfiler_Type = {
786-
PyVarObject_HEAD_INIT(NULL, 0)
787-
"_lsprof.Profiler", /* tp_name */
788-
sizeof(ProfilerObject), /* tp_basicsize */
789-
0, /* tp_itemsize */
790-
(destructor)profiler_dealloc, /* tp_dealloc */
791-
0, /* tp_vectorcall_offset */
792-
0, /* tp_getattr */
793-
0, /* tp_setattr */
794-
0, /* tp_as_async */
795-
0, /* tp_repr */
796-
0, /* tp_as_number */
797-
0, /* tp_as_sequence */
798-
0, /* tp_as_mapping */
799-
0, /* tp_hash */
800-
0, /* tp_call */
801-
0, /* tp_str */
802-
0, /* tp_getattro */
803-
0, /* tp_setattro */
804-
0, /* tp_as_buffer */
805-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
806-
profiler_doc, /* tp_doc */
807-
0, /* tp_traverse */
808-
0, /* tp_clear */
809-
0, /* tp_richcompare */
810-
0, /* tp_weaklistoffset */
811-
0, /* tp_iter */
812-
0, /* tp_iternext */
813-
profiler_methods, /* tp_methods */
814-
0, /* tp_members */
815-
0, /* tp_getset */
816-
0, /* tp_base */
817-
0, /* tp_dict */
818-
0, /* tp_descr_get */
819-
0, /* tp_descr_set */
820-
0, /* tp_dictoffset */
821-
(initproc)profiler_init, /* tp_init */
822-
PyType_GenericAlloc, /* tp_alloc */
823-
PyType_GenericNew, /* tp_new */
824-
PyObject_Del, /* tp_free */
796+
static PyType_Slot _lsprof_profiler_type_spec_slots[] = {
797+
{Py_tp_doc, (void *)profiler_doc},
798+
{Py_tp_methods, profiler_methods},
799+
{Py_tp_dealloc, profiler_dealloc},
800+
{Py_tp_init, profiler_init},
801+
{Py_tp_alloc, PyType_GenericAlloc},
802+
{Py_tp_new, PyType_GenericNew},
803+
{Py_tp_free, PyObject_Del},
804+
{0, 0}
805+
};
806+
807+
static PyType_Spec _lsprof_profiler_type_spec = {
808+
.name = "_lsprof.Profiler",
809+
.basicsize = sizeof(ProfilerObject),
810+
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
811+
.slots = _lsprof_profiler_type_spec_slots,
825812
};
826813

827814
static PyMethodDef moduleMethods[] = {
828815
{NULL, NULL}
829816
};
830817

818+
static int
819+
_lsprof_traverse(PyObject *module, visitproc visit, void *arg)
820+
{
821+
_lsprof_state *state = _lsprof_get_state(module);
822+
Py_VISIT(state->profiler_type);
823+
Py_VISIT(state->stats_entry_type);
824+
Py_VISIT(state->stats_subentry_type);
825+
return 0;
826+
}
827+
828+
static int
829+
_lsprof_clear(PyObject *module)
830+
{
831+
_lsprof_state *state = _lsprof_get_state(module);
832+
Py_CLEAR(state->profiler_type);
833+
Py_CLEAR(state->stats_entry_type);
834+
Py_CLEAR(state->stats_subentry_type);
835+
return 0;
836+
}
837+
838+
static void
839+
_lsprof_free(void *module)
840+
{
841+
_lsprof_clear((PyObject *)module);
842+
}
843+
844+
static int
845+
_lsprof_exec(PyObject *module)
846+
{
847+
_lsprof_state *state = PyModule_GetState(module);
848+
849+
state->profiler_type = (PyTypeObject *)PyType_FromModuleAndSpec(
850+
module, &_lsprof_profiler_type_spec, NULL);
851+
if (state->profiler_type == NULL) {
852+
return -1;
853+
}
854+
855+
if (PyModule_AddType(module, state->profiler_type) < 0) {
856+
return -1;
857+
}
858+
859+
state->stats_entry_type = PyStructSequence_NewType(&profiler_entry_desc);
860+
if (state->stats_entry_type == NULL) {
861+
return -1;
862+
}
863+
if (PyModule_AddType(module, state->stats_entry_type) < 0) {
864+
return -1;
865+
}
866+
867+
state->stats_subentry_type = PyStructSequence_NewType(&profiler_subentry_desc);
868+
if (state->stats_subentry_type == NULL) {
869+
return -1;
870+
}
871+
if (PyModule_AddType(module, state->stats_subentry_type) < 0) {
872+
return -1;
873+
}
874+
875+
return 0;
876+
}
877+
878+
static PyModuleDef_Slot _lsprofslots[] = {
879+
{Py_mod_exec, _lsprof_exec},
880+
{0, NULL}
881+
};
831882

832883
static struct PyModuleDef _lsprofmodule = {
833884
PyModuleDef_HEAD_INIT,
834-
"_lsprof",
835-
"Fast profiler",
836-
-1,
837-
moduleMethods,
838-
NULL,
839-
NULL,
840-
NULL,
841-
NULL
885+
.m_name = "_lsprof",
886+
.m_doc = "Fast profiler",
887+
.m_size = sizeof(_lsprof_state),
888+
.m_methods = moduleMethods,
889+
.m_slots = _lsprofslots,
890+
.m_traverse = _lsprof_traverse,
891+
.m_clear = _lsprof_clear,
892+
.m_free = _lsprof_free
842893
};
843894

844895
PyMODINIT_FUNC
845896
PyInit__lsprof(void)
846897
{
847-
PyObject *module, *d;
848-
module = PyModule_Create(&_lsprofmodule);
849-
if (module == NULL)
850-
return NULL;
851-
d = PyModule_GetDict(module);
852-
if (PyType_Ready(&PyProfiler_Type) < 0)
853-
return NULL;
854-
PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
855-
856-
if (!initialized) {
857-
if (PyStructSequence_InitType2(&StatsEntryType,
858-
&profiler_entry_desc) < 0)
859-
return NULL;
860-
if (PyStructSequence_InitType2(&StatsSubEntryType,
861-
&profiler_subentry_desc) < 0)
862-
return NULL;
863-
}
864-
Py_INCREF((PyObject*) &StatsEntryType);
865-
Py_INCREF((PyObject*) &StatsSubEntryType);
866-
PyModule_AddObject(module, "profiler_entry",
867-
(PyObject*) &StatsEntryType);
868-
PyModule_AddObject(module, "profiler_subentry",
869-
(PyObject*) &StatsSubEntryType);
870-
initialized = 1;
871-
return module;
898+
return PyModuleDef_Init(&_lsprofmodule);
872899
}

Modules/clinic/_lsprof.c.h

Lines changed: 16 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)