diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 932738c3049882..da9f28406bd27b 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -829,6 +829,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(call)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(call_exception_handler)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(call_soon)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(callable)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(callback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cancel)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(capath)); @@ -999,6 +1000,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(input)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(insert_comments)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(insert_pis)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(instruction_offset)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(instructions)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(intern)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(intersection)); @@ -1169,6 +1171,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reset)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(resetids)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(return)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(retval)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reverse)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reversed)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(s)); @@ -1180,6 +1183,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(seekable)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(selectors)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(self)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(self_arg)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(send)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sep)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sequence)); @@ -1221,6 +1225,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(strict_mode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(string)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sub_key)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(subclass)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(symmetric_difference_update)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tabsize)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tag)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index da62b4f0a951ff..664202d4ca46ab 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -318,6 +318,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(call) STRUCT_FOR_ID(call_exception_handler) STRUCT_FOR_ID(call_soon) + STRUCT_FOR_ID(callable) STRUCT_FOR_ID(callback) STRUCT_FOR_ID(cancel) STRUCT_FOR_ID(capath) @@ -488,6 +489,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(input) STRUCT_FOR_ID(insert_comments) STRUCT_FOR_ID(insert_pis) + STRUCT_FOR_ID(instruction_offset) STRUCT_FOR_ID(instructions) STRUCT_FOR_ID(intern) STRUCT_FOR_ID(intersection) @@ -658,6 +660,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(reset) STRUCT_FOR_ID(resetids) STRUCT_FOR_ID(return) + STRUCT_FOR_ID(retval) STRUCT_FOR_ID(reverse) STRUCT_FOR_ID(reversed) STRUCT_FOR_ID(s) @@ -669,6 +672,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(seekable) STRUCT_FOR_ID(selectors) STRUCT_FOR_ID(self) + STRUCT_FOR_ID(self_arg) STRUCT_FOR_ID(send) STRUCT_FOR_ID(sep) STRUCT_FOR_ID(sequence) @@ -710,6 +714,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(strict_mode) STRUCT_FOR_ID(string) STRUCT_FOR_ID(sub_key) + STRUCT_FOR_ID(subclass) STRUCT_FOR_ID(symmetric_difference_update) STRUCT_FOR_ID(tabsize) STRUCT_FOR_ID(tag) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 68fbbcb4378e17..3799dfd9767a79 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -827,6 +827,7 @@ extern "C" { INIT_ID(call), \ INIT_ID(call_exception_handler), \ INIT_ID(call_soon), \ + INIT_ID(callable), \ INIT_ID(callback), \ INIT_ID(cancel), \ INIT_ID(capath), \ @@ -997,6 +998,7 @@ extern "C" { INIT_ID(input), \ INIT_ID(insert_comments), \ INIT_ID(insert_pis), \ + INIT_ID(instruction_offset), \ INIT_ID(instructions), \ INIT_ID(intern), \ INIT_ID(intersection), \ @@ -1167,6 +1169,7 @@ extern "C" { INIT_ID(reset), \ INIT_ID(resetids), \ INIT_ID(return), \ + INIT_ID(retval), \ INIT_ID(reverse), \ INIT_ID(reversed), \ INIT_ID(s), \ @@ -1178,6 +1181,7 @@ extern "C" { INIT_ID(seekable), \ INIT_ID(selectors), \ INIT_ID(self), \ + INIT_ID(self_arg), \ INIT_ID(send), \ INIT_ID(sep), \ INIT_ID(sequence), \ @@ -1219,6 +1223,7 @@ extern "C" { INIT_ID(strict_mode), \ INIT_ID(string), \ INIT_ID(sub_key), \ + INIT_ID(subclass), \ INIT_ID(symmetric_difference_update), \ INIT_ID(tabsize), \ INIT_ID(tag), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index c8458b4e36ccc9..6298cc39d71de9 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -795,6 +795,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(call_soon); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(callable); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(callback); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -1305,6 +1308,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(insert_pis); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(instruction_offset); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(instructions); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -1815,6 +1821,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(return); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(retval); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(reverse); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -1848,6 +1857,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(self); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(self_arg); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(send); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -1971,6 +1983,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(sub_key); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(subclass); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(symmetric_difference_update); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 8f09204097529f..5c00a0a3256647 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -68,10 +68,13 @@ class _lsprof.Profiler "ProfilerObject *" "&ProfilerType" #include "clinic/_lsprof.c.h" +static struct PyModuleDef _lsprofmodule; + typedef struct { PyTypeObject *profiler_type; PyTypeObject *stats_entry_type; PyTypeObject *stats_subentry_type; + random_state_t random_state; } _lsprof_state; static inline _lsprof_state* @@ -224,16 +227,18 @@ newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj) } static ProfilerEntry* -getEntry(ProfilerObject *pObj, void *key) +getEntry(_lsprof_state *state, ProfilerObject *pObj, void *key) { - return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key); + return (ProfilerEntry*) RotatingTree_Get(&state->random_state, + &pObj->profilerEntries, key); } static ProfilerSubEntry * -getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry) +getSubEntry(_lsprof_state *state, ProfilerObject *pObj, ProfilerEntry *caller, + ProfilerEntry* entry) { - return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls, - (void *)entry); + return (ProfilerSubEntry*) RotatingTree_Get(&state->random_state, + &caller->calls, (void *)entry); } static ProfilerSubEntry * @@ -289,7 +294,8 @@ static void clearEntries(ProfilerObject *pObj) } static void -initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry) +initContext(_lsprof_state *state, ProfilerObject *pObj, ProfilerContext *self, + ProfilerEntry *entry) { self->ctxEntry = entry; self->subt = 0; @@ -299,7 +305,7 @@ initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry) if ((pObj->flags & POF_SUBCALLS) && self->previous) { /* find or create an entry for me in my caller's entry */ ProfilerEntry *caller = self->previous->ctxEntry; - ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry); + ProfilerSubEntry *subentry = getSubEntry(state, pObj, caller, entry); if (subentry == NULL) subentry = newSubEntry(pObj, caller, entry); if (subentry) @@ -309,7 +315,8 @@ initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry) } static void -Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry) +Stop(_lsprof_state *state, ProfilerObject *pObj, ProfilerContext *self, + ProfilerEntry *entry) { _PyTime_t tt = call_timer(pObj) - self->t0; _PyTime_t it = tt - self->subt; @@ -325,7 +332,7 @@ Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry) if ((pObj->flags & POF_SUBCALLS) && self->previous) { /* find or create an entry for me in my caller's entry */ ProfilerEntry *caller = self->previous->ctxEntry; - ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry); + ProfilerSubEntry *subentry = getSubEntry(state, pObj, caller, entry); if (subentry) { if (--subentry->recursionLevel == 0) subentry->tt += tt; @@ -338,7 +345,8 @@ Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry) } static void -ptrace_enter_call(PyObject *self, void *key, PyObject *userObj) +ptrace_enter_call(_lsprof_state *state, PyObject *self, void *key, + PyObject *userObj) { /* entering a call to the function identified by 'key' (which can be a PyCodeObject or a PyMethodDef pointer) */ @@ -354,7 +362,7 @@ ptrace_enter_call(PyObject *self, void *key, PyObject *userObj) * save and restore any current exception. */ PyObject *exc = PyErr_GetRaisedException(); - profEntry = getEntry(pObj, key); + profEntry = getEntry(state, pObj, key); if (profEntry == NULL) { profEntry = newProfilerEntry(pObj, key, userObj); if (profEntry == NULL) @@ -374,14 +382,14 @@ ptrace_enter_call(PyObject *self, void *key, PyObject *userObj) goto restorePyerr; } } - initContext(pObj, pContext, profEntry); + initContext(state, pObj, pContext, profEntry); restorePyerr: PyErr_SetRaisedException(exc); } static void -ptrace_leave_call(PyObject *self, void *key) +ptrace_leave_call(_lsprof_state *state, PyObject *self, void *key) { /* leaving a call to the function identified by 'key' */ ProfilerObject *pObj = (ProfilerObject*)self; @@ -391,9 +399,9 @@ ptrace_leave_call(PyObject *self, void *key) pContext = pObj->currentProfilerContext; if (pContext == NULL) return; - profEntry = getEntry(pObj, key); + profEntry = getEntry(state, pObj, key); if (profEntry) { - Stop(pObj, pContext, profEntry); + Stop(state, pObj, pContext, profEntry); } else { pObj->currentProfilerContext = pContext->previous; @@ -596,18 +604,49 @@ setBuiltins(ProfilerObject *pObj, int nvalue) return 0; } -PyObject* pystart_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) +/*[clinic input] +_lsprof.Profiler._pystart_callback + + cls: defining_class + code: object + instruction_offset: int + +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler__pystart_callback_impl(ProfilerObject *self, + PyTypeObject *cls, PyObject *code, + int instruction_offset) +/*[clinic end generated code: output=18c97a9f41e8dd68 input=9a52e348d39c8b79]*/ { - PyObject* code = args[0]; - ptrace_enter_call((PyObject*)self, (void *)code, (PyObject *)code); + _lsprof_state *state = (_lsprof_state *)_PyType_GetModuleState(cls); + assert(state != NULL); + ptrace_enter_call(state, (PyObject*)self, (void *)code, (PyObject *)code); Py_RETURN_NONE; } -PyObject* pyreturn_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) +/*[clinic input] +_lsprof.Profiler._pyreturn_callback + + cls: defining_class + code: object + instruction_offset: int + retval: object + +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler__pyreturn_callback_impl(ProfilerObject *self, + PyTypeObject *cls, PyObject *code, + int instruction_offset, + PyObject *retval) +/*[clinic end generated code: output=6d798ecfcd20ca7d input=3b5f03997ea10d90]*/ { - PyObject* code = args[0]; - ptrace_leave_call((PyObject*)self, (void *)code); + _lsprof_state *state = (_lsprof_state *)_PyType_GetModuleState(cls); + assert(state != NULL); + + ptrace_leave_call(state, (PyObject*)self, (void *)code); Py_RETURN_NONE; } @@ -639,16 +678,32 @@ PyObject* get_cfunc_from_callable(PyObject* callable, PyObject* self_arg, PyObje return NULL; } -PyObject* ccall_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) +/*[clinic input] +_lsprof.Profiler._ccall_callback + + cls: defining_class + code: object + instruction_offset: int + callable: object + self_arg: object + +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler__ccall_callback_impl(ProfilerObject *self, + PyTypeObject *cls, PyObject *code, + int instruction_offset, + PyObject *callable, PyObject *self_arg) +/*[clinic end generated code: output=b505501f78e9b4b6 input=722128bc0faa9ca2]*/ { if (self->flags & POF_BUILTINS) { - PyObject* callable = args[2]; - PyObject* self_arg = args[3]; + _lsprof_state *state = (_lsprof_state *)_PyType_GetModuleState(cls); + assert(state != NULL); PyObject* cfunc = get_cfunc_from_callable(callable, self_arg, self->missing); if (cfunc) { - ptrace_enter_call((PyObject*)self, + ptrace_enter_call(state, (PyObject*)self, ((PyCFunctionObject *)cfunc)->m_ml, cfunc); Py_DECREF(cfunc); @@ -657,16 +712,33 @@ PyObject* ccall_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t Py_RETURN_NONE; } -PyObject* creturn_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) +/*[clinic input] +_lsprof.Profiler._creturn_callback + + cls: defining_class + code: object + instruction_offset: int + callable: object + self_arg: object + +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler__creturn_callback_impl(ProfilerObject *self, + PyTypeObject *cls, PyObject *code, + int instruction_offset, + PyObject *callable, + PyObject *self_arg) +/*[clinic end generated code: output=4647808fadffcfdb input=fc695ffb36ce0e4a]*/ { if (self->flags & POF_BUILTINS) { - PyObject* callable = args[2]; - PyObject* self_arg = args[3]; + _lsprof_state *state = (_lsprof_state *)_PyType_GetModuleState(cls); + assert(state != NULL); PyObject* cfunc = get_cfunc_from_callable(callable, self_arg, self->missing); if (cfunc) { - ptrace_leave_call((PyObject*)self, + ptrace_leave_call(state, (PyObject*)self, ((PyCFunctionObject *)cfunc)->m_ml); Py_DECREF(cfunc); } @@ -690,31 +762,30 @@ static const struct { {0, NULL} }; -PyDoc_STRVAR(enable_doc, "\ -enable(subcalls=True, builtins=True)\n\ -\n\ -Start collecting profiling information.\n\ -If 'subcalls' is True, also records for each function\n\ -statistics separated according to its current caller.\n\ -If 'builtins' is True, records the time spent in\n\ -built-in functions separately from their caller.\n\ -"); -static PyObject* -profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds) + +/*[clinic input] +_lsprof.Profiler.enable + + cls: defining_class + subclass: bool = True + builtins: bool = True + +Start collecting profiling information. + +If 'subcalls' is True, also records for each function +statistics separated according to its current caller. +If 'builtins' is True, records the time spent in +built-in functions separately from their caller. +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler_enable_impl(ProfilerObject *self, PyTypeObject *cls, + int subclass, int builtins) +/*[clinic end generated code: output=fd728a3f2aebd1ab input=83411b9d1486d8d6]*/ { - int subcalls = -1; - int builtins = -1; - static char *kwlist[] = {"subcalls", "builtins", 0}; int all_events = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|pp:enable", - kwlist, &subcalls, &builtins)) - return NULL; - if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) { - return NULL; - } - PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); if (!monitoring) { return NULL; @@ -751,13 +822,13 @@ profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds) } static void -flush_unmatched(ProfilerObject *pObj) +flush_unmatched(_lsprof_state *state, ProfilerObject *pObj) { while (pObj->currentProfilerContext) { ProfilerContext *pContext = pObj->currentProfilerContext; ProfilerEntry *profEntry= pContext->ctxEntry; if (profEntry) - Stop(pObj, pContext, profEntry); + Stop(state, pObj, pContext, profEntry); else pObj->currentProfilerContext = pContext->previous; if (pContext) @@ -766,15 +837,22 @@ flush_unmatched(ProfilerObject *pObj) } -PyDoc_STRVAR(disable_doc, "\ -disable()\n\ -\n\ -Stop collecting profiling information.\n\ -"); -static PyObject* -profiler_disable(ProfilerObject *self, PyObject* noarg) +/*[clinic input] +_lsprof.Profiler.disable + + cls: defining_class + +Stop collecting profiling information. +[clinic start generated code]*/ + +static PyObject * +_lsprof_Profiler_disable_impl(ProfilerObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=5e8e1b3df7fc0923 input=e14fc1835664fe9c]*/ { + _lsprof_state *state = (_lsprof_state *)PyType_GetModuleState(cls); + assert(state != NULL); + if (self->flags & POF_ENABLED) { PyObject* result = NULL; PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); @@ -810,7 +888,7 @@ profiler_disable(ProfilerObject *self, PyObject* noarg) Py_DECREF(monitoring); self->flags &= ~POF_ENABLED; - flush_unmatched(self); + flush_unmatched(state, self); } if (pending_exception(self)) { @@ -842,6 +920,12 @@ profiler_traverse(ProfilerObject *op, visitproc visit, void *arg) static void profiler_dealloc(ProfilerObject *op) { + PyObject *module = PyType_GetModuleByDef(Py_TYPE(op), &_lsprofmodule); + _lsprof_state *state = (_lsprof_state *)PyModule_GetState(module); + if (state == NULL) { + return; + } + PyObject_GC_UnTrack(op); if (op->flags & POF_ENABLED) { PyThreadState *tstate = _PyThreadState_GET(); @@ -850,7 +934,7 @@ profiler_dealloc(ProfilerObject *op) } } - flush_unmatched(op); + flush_unmatched(state, op); clearEntries(op); Py_XDECREF(op->externalTimer); PyTypeObject *tp = Py_TYPE(op); @@ -894,20 +978,13 @@ profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw) static PyMethodDef profiler_methods[] = { _LSPROF_PROFILER_GETSTATS_METHODDEF - {"enable", _PyCFunction_CAST(profiler_enable), - METH_VARARGS | METH_KEYWORDS, enable_doc}, - {"disable", (PyCFunction)profiler_disable, - METH_NOARGS, disable_doc}, - {"clear", (PyCFunction)profiler_clear, - METH_NOARGS, clear_doc}, - {"_pystart_callback", _PyCFunction_CAST(pystart_callback), - METH_FASTCALL, NULL}, - {"_pyreturn_callback", _PyCFunction_CAST(pyreturn_callback), - METH_FASTCALL, NULL}, - {"_ccall_callback", _PyCFunction_CAST(ccall_callback), - METH_FASTCALL, NULL}, - {"_creturn_callback", _PyCFunction_CAST(creturn_callback), - METH_FASTCALL, NULL}, + _LSPROF_PROFILER_ENABLE_METHODDEF + _LSPROF_PROFILER_DISABLE_METHODDEF + _LSPROF_PROFILER__PYSTART_CALLBACK_METHODDEF + _LSPROF_PROFILER__PYRETURN_CALLBACK_METHODDEF + _LSPROF_PROFILER__CCALL_CALLBACK_METHODDEF + _LSPROF_PROFILER__CRETURN_CALLBACK_METHODDEF + {"clear", (PyCFunction)profiler_clear, METH_NOARGS, clear_doc}, {NULL, NULL} }; @@ -972,6 +1049,8 @@ static int _lsprof_exec(PyObject *module) { _lsprof_state *state = PyModule_GetState(module); + state->random_state.random_value = 1; + state->random_state.random_stream = 0; state->profiler_type = (PyTypeObject *)PyType_FromModuleAndSpec( module, &_lsprof_profiler_type_spec, NULL); @@ -1004,9 +1083,7 @@ _lsprof_exec(PyObject *module) static PyModuleDef_Slot _lsprofslots[] = { {Py_mod_exec, _lsprof_exec}, - // XXX gh-103092: fix isolation. - {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, - //{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h index b3b7fda5660bfd..175dd5b2f15ff0 100644 --- a/Modules/clinic/_lsprof.c.h +++ b/Modules/clinic/_lsprof.c.h @@ -2,6 +2,12 @@ preserve [clinic start generated code]*/ +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif +#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + PyDoc_STRVAR(_lsprof_Profiler_getstats__doc__, "getstats($self, /)\n" "--\n" @@ -45,4 +51,364 @@ _lsprof_Profiler_getstats(ProfilerObject *self, PyTypeObject *cls, PyObject *con } return _lsprof_Profiler_getstats_impl(self, cls); } -/*[clinic end generated code: output=5c9d87d89863dc83 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_lsprof_Profiler__pystart_callback__doc__, +"_pystart_callback($self, /, code, instruction_offset)\n" +"--\n" +"\n"); + +#define _LSPROF_PROFILER__PYSTART_CALLBACK_METHODDEF \ + {"_pystart_callback", _PyCFunction_CAST(_lsprof_Profiler__pystart_callback), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _lsprof_Profiler__pystart_callback__doc__}, + +static PyObject * +_lsprof_Profiler__pystart_callback_impl(ProfilerObject *self, + PyTypeObject *cls, PyObject *code, + int instruction_offset); + +static PyObject * +_lsprof_Profiler__pystart_callback(ProfilerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(code), &_Py_ID(instruction_offset), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"code", "instruction_offset", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_pystart_callback", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyObject *code; + int instruction_offset; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!args) { + goto exit; + } + code = args[0]; + instruction_offset = PyLong_AsInt(args[1]); + if (instruction_offset == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = _lsprof_Profiler__pystart_callback_impl(self, cls, code, instruction_offset); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lsprof_Profiler__pyreturn_callback__doc__, +"_pyreturn_callback($self, /, code, instruction_offset, retval)\n" +"--\n" +"\n"); + +#define _LSPROF_PROFILER__PYRETURN_CALLBACK_METHODDEF \ + {"_pyreturn_callback", _PyCFunction_CAST(_lsprof_Profiler__pyreturn_callback), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _lsprof_Profiler__pyreturn_callback__doc__}, + +static PyObject * +_lsprof_Profiler__pyreturn_callback_impl(ProfilerObject *self, + PyTypeObject *cls, PyObject *code, + int instruction_offset, + PyObject *retval); + +static PyObject * +_lsprof_Profiler__pyreturn_callback(ProfilerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 4 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(code), &_Py_ID(instruction_offset), &_Py_ID(retval), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"code", "instruction_offset", "retval", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_pyreturn_callback", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + PyObject *code; + int instruction_offset; + PyObject *retval; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf); + if (!args) { + goto exit; + } + code = args[0]; + instruction_offset = PyLong_AsInt(args[1]); + if (instruction_offset == -1 && PyErr_Occurred()) { + goto exit; + } + retval = args[2]; + return_value = _lsprof_Profiler__pyreturn_callback_impl(self, cls, code, instruction_offset, retval); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lsprof_Profiler__ccall_callback__doc__, +"_ccall_callback($self, /, code, instruction_offset, callable, self_arg)\n" +"--\n" +"\n"); + +#define _LSPROF_PROFILER__CCALL_CALLBACK_METHODDEF \ + {"_ccall_callback", _PyCFunction_CAST(_lsprof_Profiler__ccall_callback), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _lsprof_Profiler__ccall_callback__doc__}, + +static PyObject * +_lsprof_Profiler__ccall_callback_impl(ProfilerObject *self, + PyTypeObject *cls, PyObject *code, + int instruction_offset, + PyObject *callable, PyObject *self_arg); + +static PyObject * +_lsprof_Profiler__ccall_callback(ProfilerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 5 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(code), &_Py_ID(instruction_offset), &_Py_ID(callable), &_Py_ID(self_arg), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"code", "instruction_offset", "callable", "self_arg", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_ccall_callback", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[4]; + PyObject *code; + int instruction_offset; + PyObject *callable; + PyObject *self_arg; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 4, 4, 0, argsbuf); + if (!args) { + goto exit; + } + code = args[0]; + instruction_offset = PyLong_AsInt(args[1]); + if (instruction_offset == -1 && PyErr_Occurred()) { + goto exit; + } + callable = args[2]; + self_arg = args[3]; + return_value = _lsprof_Profiler__ccall_callback_impl(self, cls, code, instruction_offset, callable, self_arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lsprof_Profiler__creturn_callback__doc__, +"_creturn_callback($self, /, code, instruction_offset, callable,\n" +" self_arg)\n" +"--\n" +"\n"); + +#define _LSPROF_PROFILER__CRETURN_CALLBACK_METHODDEF \ + {"_creturn_callback", _PyCFunction_CAST(_lsprof_Profiler__creturn_callback), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _lsprof_Profiler__creturn_callback__doc__}, + +static PyObject * +_lsprof_Profiler__creturn_callback_impl(ProfilerObject *self, + PyTypeObject *cls, PyObject *code, + int instruction_offset, + PyObject *callable, + PyObject *self_arg); + +static PyObject * +_lsprof_Profiler__creturn_callback(ProfilerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 5 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(code), &_Py_ID(instruction_offset), &_Py_ID(callable), &_Py_ID(self_arg), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"code", "instruction_offset", "callable", "self_arg", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_creturn_callback", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[4]; + PyObject *code; + int instruction_offset; + PyObject *callable; + PyObject *self_arg; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 4, 4, 0, argsbuf); + if (!args) { + goto exit; + } + code = args[0]; + instruction_offset = PyLong_AsInt(args[1]); + if (instruction_offset == -1 && PyErr_Occurred()) { + goto exit; + } + callable = args[2]; + self_arg = args[3]; + return_value = _lsprof_Profiler__creturn_callback_impl(self, cls, code, instruction_offset, callable, self_arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lsprof_Profiler_enable__doc__, +"enable($self, /, subclass=True, builtins=True)\n" +"--\n" +"\n" +"Start collecting profiling information.\n" +"\n" +"If \'subcalls\' is True, also records for each function\n" +"statistics separated according to its current caller.\n" +"If \'builtins\' is True, records the time spent in\n" +"built-in functions separately from their caller."); + +#define _LSPROF_PROFILER_ENABLE_METHODDEF \ + {"enable", _PyCFunction_CAST(_lsprof_Profiler_enable), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _lsprof_Profiler_enable__doc__}, + +static PyObject * +_lsprof_Profiler_enable_impl(ProfilerObject *self, PyTypeObject *cls, + int subclass, int builtins); + +static PyObject * +_lsprof_Profiler_enable(ProfilerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(subclass), &_Py_ID(builtins), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"subclass", "builtins", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "enable", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + int subclass = 1; + int builtins = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 2, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + subclass = PyObject_IsTrue(args[0]); + if (subclass < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + builtins = PyObject_IsTrue(args[1]); + if (builtins < 0) { + goto exit; + } +skip_optional_pos: + return_value = _lsprof_Profiler_enable_impl(self, cls, subclass, builtins); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lsprof_Profiler_disable__doc__, +"disable($self, /)\n" +"--\n" +"\n" +"Stop collecting profiling information."); + +#define _LSPROF_PROFILER_DISABLE_METHODDEF \ + {"disable", _PyCFunction_CAST(_lsprof_Profiler_disable), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _lsprof_Profiler_disable__doc__}, + +static PyObject * +_lsprof_Profiler_disable_impl(ProfilerObject *self, PyTypeObject *cls); + +static PyObject * +_lsprof_Profiler_disable(ProfilerObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "disable() takes no arguments"); + return NULL; + } + return _lsprof_Profiler_disable_impl(self, cls); +} +/*[clinic end generated code: output=2ac943b3f8180cdb input=a9049054013a1b77]*/ diff --git a/Modules/rotatingtree.c b/Modules/rotatingtree.c index 07e08bc3167c0a..3d390538cef7cf 100644 --- a/Modules/rotatingtree.c +++ b/Modules/rotatingtree.c @@ -7,20 +7,16 @@ * I think that ones are slightly more probable than zeroes. It's not * important here, though. */ - -static unsigned int random_value = 1; -static unsigned int random_stream = 0; - static int -randombits(int bits) +randombits(random_state_t *st, int bits) { int result; - if (random_stream < (1U << bits)) { - random_value *= 1082527; - random_stream = random_value; + if (st->random_stream < (1U << bits)) { + st->random_value *= 1082527; + st->random_stream = st->random_value; } - result = random_stream & ((1<>= bits; + result = st->random_stream & ((1<random_stream >>= bits; return result; } @@ -45,9 +41,9 @@ RotatingTree_Add(rotating_node_t **root, rotating_node_t *node) function because it occasionally rebalances the tree to move the resulting node closer to the root. */ rotating_node_t * -RotatingTree_Get(rotating_node_t **root, void *key) +RotatingTree_Get(random_state_t *st, rotating_node_t **root, void *key) { - if (randombits(3) != 4) { + if (randombits(st, 3) != 4) { /* Fast path, no rebalancing */ rotating_node_t *node = *root; while (node != NULL) { @@ -70,7 +66,7 @@ RotatingTree_Get(rotating_node_t **root, void *key) while (1) { if (node->key == key) return node; - rotate = !randombits(1); + rotate = !randombits(st, 1); if (KEY_LOWER_THAN(key, node->key)) { next = node->left; if (next == NULL) diff --git a/Modules/rotatingtree.h b/Modules/rotatingtree.h index 7b3e5fde921cb3..6dab738997b263 100644 --- a/Modules/rotatingtree.h +++ b/Modules/rotatingtree.h @@ -21,7 +21,13 @@ struct rotating_node_s { rotating_node_t *right; }; +typedef struct { + unsigned int random_value; + unsigned int random_stream; +} random_state_t; + void RotatingTree_Add(rotating_node_t **root, rotating_node_t *node); -rotating_node_t* RotatingTree_Get(rotating_node_t **root, void *key); +rotating_node_t* RotatingTree_Get(random_state_t *st, rotating_node_t **root, + void *key); int RotatingTree_Enum(rotating_node_t *root, rotating_tree_enum_fn enumfn, void *arg); diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 1d9576d083d8dc..61c586cba22fb8 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -478,5 +478,3 @@ Modules/readline.c - should_auto_add_history - Modules/readline.c - sigwinch_received - Modules/readline.c - sigwinch_ohandler - Modules/readline.c - completed_input_string - -Modules/rotatingtree.c - random_stream - -Modules/rotatingtree.c - random_value -