17db96d56Sopenharmony_ci#ifndef Py_BUILD_CORE_BUILTIN
27db96d56Sopenharmony_ci#  define Py_BUILD_CORE_MODULE 1
37db96d56Sopenharmony_ci#endif
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ci#include "Python.h"
67db96d56Sopenharmony_ci#include "pycore_call.h"          // _PyObject_CallNoArgs()
77db96d56Sopenharmony_ci#include "pycore_pystate.h"       // _PyThreadState_GET()
87db96d56Sopenharmony_ci#include "rotatingtree.h"
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci/************************************************************/
117db96d56Sopenharmony_ci/* Written by Brett Rosen and Ted Czotter */
127db96d56Sopenharmony_ci
137db96d56Sopenharmony_cistruct _ProfilerEntry;
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci/* represents a function called from another function */
167db96d56Sopenharmony_citypedef struct _ProfilerSubEntry {
177db96d56Sopenharmony_ci    rotating_node_t header;
187db96d56Sopenharmony_ci    _PyTime_t tt;
197db96d56Sopenharmony_ci    _PyTime_t it;
207db96d56Sopenharmony_ci    long callcount;
217db96d56Sopenharmony_ci    long recursivecallcount;
227db96d56Sopenharmony_ci    long recursionLevel;
237db96d56Sopenharmony_ci} ProfilerSubEntry;
247db96d56Sopenharmony_ci
257db96d56Sopenharmony_ci/* represents a function or user defined block */
267db96d56Sopenharmony_citypedef struct _ProfilerEntry {
277db96d56Sopenharmony_ci    rotating_node_t header;
287db96d56Sopenharmony_ci    PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
297db96d56Sopenharmony_ci    _PyTime_t tt; /* total time in this entry */
307db96d56Sopenharmony_ci    _PyTime_t it; /* inline time in this entry (not in subcalls) */
317db96d56Sopenharmony_ci    long callcount; /* how many times this was called */
327db96d56Sopenharmony_ci    long recursivecallcount; /* how many times called recursively */
337db96d56Sopenharmony_ci    long recursionLevel;
347db96d56Sopenharmony_ci    rotating_node_t *calls;
357db96d56Sopenharmony_ci} ProfilerEntry;
367db96d56Sopenharmony_ci
377db96d56Sopenharmony_citypedef struct _ProfilerContext {
387db96d56Sopenharmony_ci    _PyTime_t t0;
397db96d56Sopenharmony_ci    _PyTime_t subt;
407db96d56Sopenharmony_ci    struct _ProfilerContext *previous;
417db96d56Sopenharmony_ci    ProfilerEntry *ctxEntry;
427db96d56Sopenharmony_ci} ProfilerContext;
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_citypedef struct {
457db96d56Sopenharmony_ci    PyObject_HEAD
467db96d56Sopenharmony_ci    rotating_node_t *profilerEntries;
477db96d56Sopenharmony_ci    ProfilerContext *currentProfilerContext;
487db96d56Sopenharmony_ci    ProfilerContext *freelistProfilerContext;
497db96d56Sopenharmony_ci    int flags;
507db96d56Sopenharmony_ci    PyObject *externalTimer;
517db96d56Sopenharmony_ci    double externalTimerUnit;
527db96d56Sopenharmony_ci} ProfilerObject;
537db96d56Sopenharmony_ci
547db96d56Sopenharmony_ci#define POF_ENABLED     0x001
557db96d56Sopenharmony_ci#define POF_SUBCALLS    0x002
567db96d56Sopenharmony_ci#define POF_BUILTINS    0x004
577db96d56Sopenharmony_ci#define POF_NOMEMORY    0x100
587db96d56Sopenharmony_ci
597db96d56Sopenharmony_ci/*[clinic input]
607db96d56Sopenharmony_cimodule _lsprof
617db96d56Sopenharmony_ciclass _lsprof.Profiler "ProfilerObject *" "&ProfilerType"
627db96d56Sopenharmony_ci[clinic start generated code]*/
637db96d56Sopenharmony_ci/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e349ac952152f336]*/
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_ci#include "clinic/_lsprof.c.h"
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_citypedef struct {
687db96d56Sopenharmony_ci    PyTypeObject *profiler_type;
697db96d56Sopenharmony_ci    PyTypeObject *stats_entry_type;
707db96d56Sopenharmony_ci    PyTypeObject *stats_subentry_type;
717db96d56Sopenharmony_ci} _lsprof_state;
727db96d56Sopenharmony_ci
737db96d56Sopenharmony_cistatic inline _lsprof_state*
747db96d56Sopenharmony_ci_lsprof_get_state(PyObject *module)
757db96d56Sopenharmony_ci{
767db96d56Sopenharmony_ci    void *state = PyModule_GetState(module);
777db96d56Sopenharmony_ci    assert(state != NULL);
787db96d56Sopenharmony_ci    return (_lsprof_state *)state;
797db96d56Sopenharmony_ci}
807db96d56Sopenharmony_ci
817db96d56Sopenharmony_ci/*** External Timers ***/
827db96d56Sopenharmony_ci
837db96d56Sopenharmony_cistatic _PyTime_t CallExternalTimer(ProfilerObject *pObj)
847db96d56Sopenharmony_ci{
857db96d56Sopenharmony_ci    PyObject *o = _PyObject_CallNoArgs(pObj->externalTimer);
867db96d56Sopenharmony_ci    if (o == NULL) {
877db96d56Sopenharmony_ci        PyErr_WriteUnraisable(pObj->externalTimer);
887db96d56Sopenharmony_ci        return 0;
897db96d56Sopenharmony_ci    }
907db96d56Sopenharmony_ci
917db96d56Sopenharmony_ci    _PyTime_t result;
927db96d56Sopenharmony_ci    int err;
937db96d56Sopenharmony_ci    if (pObj->externalTimerUnit > 0.0) {
947db96d56Sopenharmony_ci        /* interpret the result as an integer that will be scaled
957db96d56Sopenharmony_ci           in profiler_getstats() */
967db96d56Sopenharmony_ci        err = _PyTime_FromNanosecondsObject(&result, o);
977db96d56Sopenharmony_ci    }
987db96d56Sopenharmony_ci    else {
997db96d56Sopenharmony_ci        /* interpret the result as a double measured in seconds.
1007db96d56Sopenharmony_ci           As the profiler works with _PyTime_t internally
1017db96d56Sopenharmony_ci           we convert it to a large integer */
1027db96d56Sopenharmony_ci        err = _PyTime_FromSecondsObject(&result, o, _PyTime_ROUND_FLOOR);
1037db96d56Sopenharmony_ci    }
1047db96d56Sopenharmony_ci    Py_DECREF(o);
1057db96d56Sopenharmony_ci    if (err < 0) {
1067db96d56Sopenharmony_ci        PyErr_WriteUnraisable(pObj->externalTimer);
1077db96d56Sopenharmony_ci        return 0;
1087db96d56Sopenharmony_ci    }
1097db96d56Sopenharmony_ci    return result;
1107db96d56Sopenharmony_ci}
1117db96d56Sopenharmony_ci
1127db96d56Sopenharmony_cistatic inline _PyTime_t
1137db96d56Sopenharmony_cicall_timer(ProfilerObject *pObj)
1147db96d56Sopenharmony_ci{
1157db96d56Sopenharmony_ci    if (pObj->externalTimer != NULL) {
1167db96d56Sopenharmony_ci        return CallExternalTimer(pObj);
1177db96d56Sopenharmony_ci    }
1187db96d56Sopenharmony_ci    else {
1197db96d56Sopenharmony_ci        return _PyTime_GetPerfCounter();
1207db96d56Sopenharmony_ci    }
1217db96d56Sopenharmony_ci}
1227db96d56Sopenharmony_ci
1237db96d56Sopenharmony_ci
1247db96d56Sopenharmony_ci/*** ProfilerObject ***/
1257db96d56Sopenharmony_ci
1267db96d56Sopenharmony_cistatic PyObject *
1277db96d56Sopenharmony_cinormalizeUserObj(PyObject *obj)
1287db96d56Sopenharmony_ci{
1297db96d56Sopenharmony_ci    PyCFunctionObject *fn;
1307db96d56Sopenharmony_ci    if (!PyCFunction_Check(obj)) {
1317db96d56Sopenharmony_ci        Py_INCREF(obj);
1327db96d56Sopenharmony_ci        return obj;
1337db96d56Sopenharmony_ci    }
1347db96d56Sopenharmony_ci    /* Replace built-in function objects with a descriptive string
1357db96d56Sopenharmony_ci       because of built-in methods -- keeping a reference to
1367db96d56Sopenharmony_ci       __self__ is probably not a good idea. */
1377db96d56Sopenharmony_ci    fn = (PyCFunctionObject *)obj;
1387db96d56Sopenharmony_ci
1397db96d56Sopenharmony_ci    if (fn->m_self == NULL) {
1407db96d56Sopenharmony_ci        /* built-in function: look up the module name */
1417db96d56Sopenharmony_ci        PyObject *mod = fn->m_module;
1427db96d56Sopenharmony_ci        PyObject *modname = NULL;
1437db96d56Sopenharmony_ci        if (mod != NULL) {
1447db96d56Sopenharmony_ci            if (PyUnicode_Check(mod)) {
1457db96d56Sopenharmony_ci                modname = mod;
1467db96d56Sopenharmony_ci                Py_INCREF(modname);
1477db96d56Sopenharmony_ci            }
1487db96d56Sopenharmony_ci            else if (PyModule_Check(mod)) {
1497db96d56Sopenharmony_ci                modname = PyModule_GetNameObject(mod);
1507db96d56Sopenharmony_ci                if (modname == NULL)
1517db96d56Sopenharmony_ci                    PyErr_Clear();
1527db96d56Sopenharmony_ci            }
1537db96d56Sopenharmony_ci        }
1547db96d56Sopenharmony_ci        if (modname != NULL) {
1557db96d56Sopenharmony_ci            if (!_PyUnicode_EqualToASCIIString(modname, "builtins")) {
1567db96d56Sopenharmony_ci                PyObject *result;
1577db96d56Sopenharmony_ci                result = PyUnicode_FromFormat("<%U.%s>", modname,
1587db96d56Sopenharmony_ci                                              fn->m_ml->ml_name);
1597db96d56Sopenharmony_ci                Py_DECREF(modname);
1607db96d56Sopenharmony_ci                return result;
1617db96d56Sopenharmony_ci            }
1627db96d56Sopenharmony_ci            Py_DECREF(modname);
1637db96d56Sopenharmony_ci        }
1647db96d56Sopenharmony_ci        return PyUnicode_FromFormat("<%s>", fn->m_ml->ml_name);
1657db96d56Sopenharmony_ci    }
1667db96d56Sopenharmony_ci    else {
1677db96d56Sopenharmony_ci        /* built-in method: try to return
1687db96d56Sopenharmony_ci            repr(getattr(type(__self__), __name__))
1697db96d56Sopenharmony_ci        */
1707db96d56Sopenharmony_ci        PyObject *self = fn->m_self;
1717db96d56Sopenharmony_ci        PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
1727db96d56Sopenharmony_ci        PyObject *modname = fn->m_module;
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci        if (name != NULL) {
1757db96d56Sopenharmony_ci            PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
1767db96d56Sopenharmony_ci            Py_XINCREF(mo);
1777db96d56Sopenharmony_ci            Py_DECREF(name);
1787db96d56Sopenharmony_ci            if (mo != NULL) {
1797db96d56Sopenharmony_ci                PyObject *res = PyObject_Repr(mo);
1807db96d56Sopenharmony_ci                Py_DECREF(mo);
1817db96d56Sopenharmony_ci                if (res != NULL)
1827db96d56Sopenharmony_ci                    return res;
1837db96d56Sopenharmony_ci            }
1847db96d56Sopenharmony_ci        }
1857db96d56Sopenharmony_ci        /* Otherwise, use __module__ */
1867db96d56Sopenharmony_ci        PyErr_Clear();
1877db96d56Sopenharmony_ci        if (modname != NULL && PyUnicode_Check(modname))
1887db96d56Sopenharmony_ci            return PyUnicode_FromFormat("<built-in method %S.%s>",
1897db96d56Sopenharmony_ci                                        modname,  fn->m_ml->ml_name);
1907db96d56Sopenharmony_ci        else
1917db96d56Sopenharmony_ci            return PyUnicode_FromFormat("<built-in method %s>",
1927db96d56Sopenharmony_ci                                        fn->m_ml->ml_name);
1937db96d56Sopenharmony_ci    }
1947db96d56Sopenharmony_ci}
1957db96d56Sopenharmony_ci
1967db96d56Sopenharmony_cistatic ProfilerEntry*
1977db96d56Sopenharmony_cinewProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
1987db96d56Sopenharmony_ci{
1997db96d56Sopenharmony_ci    ProfilerEntry *self;
2007db96d56Sopenharmony_ci    self = (ProfilerEntry*) PyMem_Malloc(sizeof(ProfilerEntry));
2017db96d56Sopenharmony_ci    if (self == NULL) {
2027db96d56Sopenharmony_ci        pObj->flags |= POF_NOMEMORY;
2037db96d56Sopenharmony_ci        return NULL;
2047db96d56Sopenharmony_ci    }
2057db96d56Sopenharmony_ci    userObj = normalizeUserObj(userObj);
2067db96d56Sopenharmony_ci    if (userObj == NULL) {
2077db96d56Sopenharmony_ci        PyErr_Clear();
2087db96d56Sopenharmony_ci        PyMem_Free(self);
2097db96d56Sopenharmony_ci        pObj->flags |= POF_NOMEMORY;
2107db96d56Sopenharmony_ci        return NULL;
2117db96d56Sopenharmony_ci    }
2127db96d56Sopenharmony_ci    self->header.key = key;
2137db96d56Sopenharmony_ci    self->userObj = userObj;
2147db96d56Sopenharmony_ci    self->tt = 0;
2157db96d56Sopenharmony_ci    self->it = 0;
2167db96d56Sopenharmony_ci    self->callcount = 0;
2177db96d56Sopenharmony_ci    self->recursivecallcount = 0;
2187db96d56Sopenharmony_ci    self->recursionLevel = 0;
2197db96d56Sopenharmony_ci    self->calls = EMPTY_ROTATING_TREE;
2207db96d56Sopenharmony_ci    RotatingTree_Add(&pObj->profilerEntries, &self->header);
2217db96d56Sopenharmony_ci    return self;
2227db96d56Sopenharmony_ci}
2237db96d56Sopenharmony_ci
2247db96d56Sopenharmony_cistatic ProfilerEntry*
2257db96d56Sopenharmony_cigetEntry(ProfilerObject *pObj, void *key)
2267db96d56Sopenharmony_ci{
2277db96d56Sopenharmony_ci    return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
2287db96d56Sopenharmony_ci}
2297db96d56Sopenharmony_ci
2307db96d56Sopenharmony_cistatic ProfilerSubEntry *
2317db96d56Sopenharmony_cigetSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
2327db96d56Sopenharmony_ci{
2337db96d56Sopenharmony_ci    return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
2347db96d56Sopenharmony_ci                                                (void *)entry);
2357db96d56Sopenharmony_ci}
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_cistatic ProfilerSubEntry *
2387db96d56Sopenharmony_cinewSubEntry(ProfilerObject *pObj,  ProfilerEntry *caller, ProfilerEntry* entry)
2397db96d56Sopenharmony_ci{
2407db96d56Sopenharmony_ci    ProfilerSubEntry *self;
2417db96d56Sopenharmony_ci    self = (ProfilerSubEntry*) PyMem_Malloc(sizeof(ProfilerSubEntry));
2427db96d56Sopenharmony_ci    if (self == NULL) {
2437db96d56Sopenharmony_ci        pObj->flags |= POF_NOMEMORY;
2447db96d56Sopenharmony_ci        return NULL;
2457db96d56Sopenharmony_ci    }
2467db96d56Sopenharmony_ci    self->header.key = (void *)entry;
2477db96d56Sopenharmony_ci    self->tt = 0;
2487db96d56Sopenharmony_ci    self->it = 0;
2497db96d56Sopenharmony_ci    self->callcount = 0;
2507db96d56Sopenharmony_ci    self->recursivecallcount = 0;
2517db96d56Sopenharmony_ci    self->recursionLevel = 0;
2527db96d56Sopenharmony_ci    RotatingTree_Add(&caller->calls, &self->header);
2537db96d56Sopenharmony_ci    return self;
2547db96d56Sopenharmony_ci}
2557db96d56Sopenharmony_ci
2567db96d56Sopenharmony_cistatic int freeSubEntry(rotating_node_t *header, void *arg)
2577db96d56Sopenharmony_ci{
2587db96d56Sopenharmony_ci    ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
2597db96d56Sopenharmony_ci    PyMem_Free(subentry);
2607db96d56Sopenharmony_ci    return 0;
2617db96d56Sopenharmony_ci}
2627db96d56Sopenharmony_ci
2637db96d56Sopenharmony_cistatic int freeEntry(rotating_node_t *header, void *arg)
2647db96d56Sopenharmony_ci{
2657db96d56Sopenharmony_ci    ProfilerEntry *entry = (ProfilerEntry*) header;
2667db96d56Sopenharmony_ci    RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
2677db96d56Sopenharmony_ci    Py_DECREF(entry->userObj);
2687db96d56Sopenharmony_ci    PyMem_Free(entry);
2697db96d56Sopenharmony_ci    return 0;
2707db96d56Sopenharmony_ci}
2717db96d56Sopenharmony_ci
2727db96d56Sopenharmony_cistatic void clearEntries(ProfilerObject *pObj)
2737db96d56Sopenharmony_ci{
2747db96d56Sopenharmony_ci    RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
2757db96d56Sopenharmony_ci    pObj->profilerEntries = EMPTY_ROTATING_TREE;
2767db96d56Sopenharmony_ci    /* release the memory hold by the ProfilerContexts */
2777db96d56Sopenharmony_ci    if (pObj->currentProfilerContext) {
2787db96d56Sopenharmony_ci        PyMem_Free(pObj->currentProfilerContext);
2797db96d56Sopenharmony_ci        pObj->currentProfilerContext = NULL;
2807db96d56Sopenharmony_ci    }
2817db96d56Sopenharmony_ci    while (pObj->freelistProfilerContext) {
2827db96d56Sopenharmony_ci        ProfilerContext *c = pObj->freelistProfilerContext;
2837db96d56Sopenharmony_ci        pObj->freelistProfilerContext = c->previous;
2847db96d56Sopenharmony_ci        PyMem_Free(c);
2857db96d56Sopenharmony_ci    }
2867db96d56Sopenharmony_ci    pObj->freelistProfilerContext = NULL;
2877db96d56Sopenharmony_ci}
2887db96d56Sopenharmony_ci
2897db96d56Sopenharmony_cistatic void
2907db96d56Sopenharmony_ciinitContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
2917db96d56Sopenharmony_ci{
2927db96d56Sopenharmony_ci    self->ctxEntry = entry;
2937db96d56Sopenharmony_ci    self->subt = 0;
2947db96d56Sopenharmony_ci    self->previous = pObj->currentProfilerContext;
2957db96d56Sopenharmony_ci    pObj->currentProfilerContext = self;
2967db96d56Sopenharmony_ci    ++entry->recursionLevel;
2977db96d56Sopenharmony_ci    if ((pObj->flags & POF_SUBCALLS) && self->previous) {
2987db96d56Sopenharmony_ci        /* find or create an entry for me in my caller's entry */
2997db96d56Sopenharmony_ci        ProfilerEntry *caller = self->previous->ctxEntry;
3007db96d56Sopenharmony_ci        ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
3017db96d56Sopenharmony_ci        if (subentry == NULL)
3027db96d56Sopenharmony_ci            subentry = newSubEntry(pObj, caller, entry);
3037db96d56Sopenharmony_ci        if (subentry)
3047db96d56Sopenharmony_ci            ++subentry->recursionLevel;
3057db96d56Sopenharmony_ci    }
3067db96d56Sopenharmony_ci    self->t0 = call_timer(pObj);
3077db96d56Sopenharmony_ci}
3087db96d56Sopenharmony_ci
3097db96d56Sopenharmony_cistatic void
3107db96d56Sopenharmony_ciStop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
3117db96d56Sopenharmony_ci{
3127db96d56Sopenharmony_ci    _PyTime_t tt = call_timer(pObj) - self->t0;
3137db96d56Sopenharmony_ci    _PyTime_t it = tt - self->subt;
3147db96d56Sopenharmony_ci    if (self->previous)
3157db96d56Sopenharmony_ci        self->previous->subt += tt;
3167db96d56Sopenharmony_ci    pObj->currentProfilerContext = self->previous;
3177db96d56Sopenharmony_ci    if (--entry->recursionLevel == 0)
3187db96d56Sopenharmony_ci        entry->tt += tt;
3197db96d56Sopenharmony_ci    else
3207db96d56Sopenharmony_ci        ++entry->recursivecallcount;
3217db96d56Sopenharmony_ci    entry->it += it;
3227db96d56Sopenharmony_ci    entry->callcount++;
3237db96d56Sopenharmony_ci    if ((pObj->flags & POF_SUBCALLS) && self->previous) {
3247db96d56Sopenharmony_ci        /* find or create an entry for me in my caller's entry */
3257db96d56Sopenharmony_ci        ProfilerEntry *caller = self->previous->ctxEntry;
3267db96d56Sopenharmony_ci        ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
3277db96d56Sopenharmony_ci        if (subentry) {
3287db96d56Sopenharmony_ci            if (--subentry->recursionLevel == 0)
3297db96d56Sopenharmony_ci                subentry->tt += tt;
3307db96d56Sopenharmony_ci            else
3317db96d56Sopenharmony_ci                ++subentry->recursivecallcount;
3327db96d56Sopenharmony_ci            subentry->it += it;
3337db96d56Sopenharmony_ci            ++subentry->callcount;
3347db96d56Sopenharmony_ci        }
3357db96d56Sopenharmony_ci    }
3367db96d56Sopenharmony_ci}
3377db96d56Sopenharmony_ci
3387db96d56Sopenharmony_cistatic void
3397db96d56Sopenharmony_ciptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
3407db96d56Sopenharmony_ci{
3417db96d56Sopenharmony_ci    /* entering a call to the function identified by 'key'
3427db96d56Sopenharmony_ci       (which can be a PyCodeObject or a PyMethodDef pointer) */
3437db96d56Sopenharmony_ci    ProfilerObject *pObj = (ProfilerObject*)self;
3447db96d56Sopenharmony_ci    ProfilerEntry *profEntry;
3457db96d56Sopenharmony_ci    ProfilerContext *pContext;
3467db96d56Sopenharmony_ci
3477db96d56Sopenharmony_ci    /* In the case of entering a generator expression frame via a
3487db96d56Sopenharmony_ci     * throw (gen_send_ex(.., 1)), we may already have an
3497db96d56Sopenharmony_ci     * Exception set here. We must not mess around with this
3507db96d56Sopenharmony_ci     * exception, and some of the code under here assumes that
3517db96d56Sopenharmony_ci     * PyErr_* is its own to mess around with, so we have to
3527db96d56Sopenharmony_ci     * save and restore any current exception. */
3537db96d56Sopenharmony_ci    PyObject *last_type, *last_value, *last_tb;
3547db96d56Sopenharmony_ci    PyErr_Fetch(&last_type, &last_value, &last_tb);
3557db96d56Sopenharmony_ci
3567db96d56Sopenharmony_ci    profEntry = getEntry(pObj, key);
3577db96d56Sopenharmony_ci    if (profEntry == NULL) {
3587db96d56Sopenharmony_ci        profEntry = newProfilerEntry(pObj, key, userObj);
3597db96d56Sopenharmony_ci        if (profEntry == NULL)
3607db96d56Sopenharmony_ci            goto restorePyerr;
3617db96d56Sopenharmony_ci    }
3627db96d56Sopenharmony_ci    /* grab a ProfilerContext out of the free list */
3637db96d56Sopenharmony_ci    pContext = pObj->freelistProfilerContext;
3647db96d56Sopenharmony_ci    if (pContext) {
3657db96d56Sopenharmony_ci        pObj->freelistProfilerContext = pContext->previous;
3667db96d56Sopenharmony_ci    }
3677db96d56Sopenharmony_ci    else {
3687db96d56Sopenharmony_ci        /* free list exhausted, allocate a new one */
3697db96d56Sopenharmony_ci        pContext = (ProfilerContext*)
3707db96d56Sopenharmony_ci            PyMem_Malloc(sizeof(ProfilerContext));
3717db96d56Sopenharmony_ci        if (pContext == NULL) {
3727db96d56Sopenharmony_ci            pObj->flags |= POF_NOMEMORY;
3737db96d56Sopenharmony_ci            goto restorePyerr;
3747db96d56Sopenharmony_ci        }
3757db96d56Sopenharmony_ci    }
3767db96d56Sopenharmony_ci    initContext(pObj, pContext, profEntry);
3777db96d56Sopenharmony_ci
3787db96d56Sopenharmony_cirestorePyerr:
3797db96d56Sopenharmony_ci    PyErr_Restore(last_type, last_value, last_tb);
3807db96d56Sopenharmony_ci}
3817db96d56Sopenharmony_ci
3827db96d56Sopenharmony_cistatic void
3837db96d56Sopenharmony_ciptrace_leave_call(PyObject *self, void *key)
3847db96d56Sopenharmony_ci{
3857db96d56Sopenharmony_ci    /* leaving a call to the function identified by 'key' */
3867db96d56Sopenharmony_ci    ProfilerObject *pObj = (ProfilerObject*)self;
3877db96d56Sopenharmony_ci    ProfilerEntry *profEntry;
3887db96d56Sopenharmony_ci    ProfilerContext *pContext;
3897db96d56Sopenharmony_ci
3907db96d56Sopenharmony_ci    pContext = pObj->currentProfilerContext;
3917db96d56Sopenharmony_ci    if (pContext == NULL)
3927db96d56Sopenharmony_ci        return;
3937db96d56Sopenharmony_ci    profEntry = getEntry(pObj, key);
3947db96d56Sopenharmony_ci    if (profEntry) {
3957db96d56Sopenharmony_ci        Stop(pObj, pContext, profEntry);
3967db96d56Sopenharmony_ci    }
3977db96d56Sopenharmony_ci    else {
3987db96d56Sopenharmony_ci        pObj->currentProfilerContext = pContext->previous;
3997db96d56Sopenharmony_ci    }
4007db96d56Sopenharmony_ci    /* put pContext into the free list */
4017db96d56Sopenharmony_ci    pContext->previous = pObj->freelistProfilerContext;
4027db96d56Sopenharmony_ci    pObj->freelistProfilerContext = pContext;
4037db96d56Sopenharmony_ci}
4047db96d56Sopenharmony_ci
4057db96d56Sopenharmony_cistatic int
4067db96d56Sopenharmony_ciprofiler_callback(PyObject *self, PyFrameObject *frame, int what,
4077db96d56Sopenharmony_ci                  PyObject *arg)
4087db96d56Sopenharmony_ci{
4097db96d56Sopenharmony_ci    switch (what) {
4107db96d56Sopenharmony_ci
4117db96d56Sopenharmony_ci    /* the 'frame' of a called function is about to start its execution */
4127db96d56Sopenharmony_ci    case PyTrace_CALL:
4137db96d56Sopenharmony_ci    {
4147db96d56Sopenharmony_ci        PyCodeObject *code = PyFrame_GetCode(frame);
4157db96d56Sopenharmony_ci        ptrace_enter_call(self, (void *)code, (PyObject *)code);
4167db96d56Sopenharmony_ci        Py_DECREF(code);
4177db96d56Sopenharmony_ci        break;
4187db96d56Sopenharmony_ci    }
4197db96d56Sopenharmony_ci
4207db96d56Sopenharmony_ci    /* the 'frame' of a called function is about to finish
4217db96d56Sopenharmony_ci       (either normally or with an exception) */
4227db96d56Sopenharmony_ci    case PyTrace_RETURN:
4237db96d56Sopenharmony_ci    {
4247db96d56Sopenharmony_ci        PyCodeObject *code = PyFrame_GetCode(frame);
4257db96d56Sopenharmony_ci        ptrace_leave_call(self, (void *)code);
4267db96d56Sopenharmony_ci        Py_DECREF(code);
4277db96d56Sopenharmony_ci        break;
4287db96d56Sopenharmony_ci    }
4297db96d56Sopenharmony_ci
4307db96d56Sopenharmony_ci    /* case PyTrace_EXCEPTION:
4317db96d56Sopenharmony_ci        If the exception results in the function exiting, a
4327db96d56Sopenharmony_ci        PyTrace_RETURN event will be generated, so we don't need to
4337db96d56Sopenharmony_ci        handle it. */
4347db96d56Sopenharmony_ci
4357db96d56Sopenharmony_ci    /* the Python function 'frame' is issuing a call to the built-in
4367db96d56Sopenharmony_ci       function 'arg' */
4377db96d56Sopenharmony_ci    case PyTrace_C_CALL:
4387db96d56Sopenharmony_ci        if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
4397db96d56Sopenharmony_ci            && PyCFunction_Check(arg)) {
4407db96d56Sopenharmony_ci            ptrace_enter_call(self,
4417db96d56Sopenharmony_ci                              ((PyCFunctionObject *)arg)->m_ml,
4427db96d56Sopenharmony_ci                              arg);
4437db96d56Sopenharmony_ci        }
4447db96d56Sopenharmony_ci        break;
4457db96d56Sopenharmony_ci
4467db96d56Sopenharmony_ci    /* the call to the built-in function 'arg' is returning into its
4477db96d56Sopenharmony_ci       caller 'frame' */
4487db96d56Sopenharmony_ci    case PyTrace_C_RETURN:              /* ...normally */
4497db96d56Sopenharmony_ci    case PyTrace_C_EXCEPTION:           /* ...with an exception set */
4507db96d56Sopenharmony_ci        if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
4517db96d56Sopenharmony_ci            && PyCFunction_Check(arg)) {
4527db96d56Sopenharmony_ci            ptrace_leave_call(self,
4537db96d56Sopenharmony_ci                              ((PyCFunctionObject *)arg)->m_ml);
4547db96d56Sopenharmony_ci        }
4557db96d56Sopenharmony_ci        break;
4567db96d56Sopenharmony_ci
4577db96d56Sopenharmony_ci    default:
4587db96d56Sopenharmony_ci        break;
4597db96d56Sopenharmony_ci    }
4607db96d56Sopenharmony_ci    return 0;
4617db96d56Sopenharmony_ci}
4627db96d56Sopenharmony_ci
4637db96d56Sopenharmony_cistatic int
4647db96d56Sopenharmony_cipending_exception(ProfilerObject *pObj)
4657db96d56Sopenharmony_ci{
4667db96d56Sopenharmony_ci    if (pObj->flags & POF_NOMEMORY) {
4677db96d56Sopenharmony_ci        pObj->flags -= POF_NOMEMORY;
4687db96d56Sopenharmony_ci        PyErr_SetString(PyExc_MemoryError,
4697db96d56Sopenharmony_ci                        "memory was exhausted while profiling");
4707db96d56Sopenharmony_ci        return -1;
4717db96d56Sopenharmony_ci    }
4727db96d56Sopenharmony_ci    return 0;
4737db96d56Sopenharmony_ci}
4747db96d56Sopenharmony_ci
4757db96d56Sopenharmony_ci/************************************************************/
4767db96d56Sopenharmony_ci
4777db96d56Sopenharmony_cistatic PyStructSequence_Field profiler_entry_fields[] = {
4787db96d56Sopenharmony_ci    {"code",         "code object or built-in function name"},
4797db96d56Sopenharmony_ci    {"callcount",    "how many times this was called"},
4807db96d56Sopenharmony_ci    {"reccallcount", "how many times called recursively"},
4817db96d56Sopenharmony_ci    {"totaltime",    "total time in this entry"},
4827db96d56Sopenharmony_ci    {"inlinetime",   "inline time in this entry (not in subcalls)"},
4837db96d56Sopenharmony_ci    {"calls",        "details of the calls"},
4847db96d56Sopenharmony_ci    {0}
4857db96d56Sopenharmony_ci};
4867db96d56Sopenharmony_ci
4877db96d56Sopenharmony_cistatic PyStructSequence_Field profiler_subentry_fields[] = {
4887db96d56Sopenharmony_ci    {"code",         "called code object or built-in function name"},
4897db96d56Sopenharmony_ci    {"callcount",    "how many times this is called"},
4907db96d56Sopenharmony_ci    {"reccallcount", "how many times this is called recursively"},
4917db96d56Sopenharmony_ci    {"totaltime",    "total time spent in this call"},
4927db96d56Sopenharmony_ci    {"inlinetime",   "inline time (not in further subcalls)"},
4937db96d56Sopenharmony_ci    {0}
4947db96d56Sopenharmony_ci};
4957db96d56Sopenharmony_ci
4967db96d56Sopenharmony_cistatic PyStructSequence_Desc profiler_entry_desc = {
4977db96d56Sopenharmony_ci    .name = "_lsprof.profiler_entry",
4987db96d56Sopenharmony_ci    .fields = profiler_entry_fields,
4997db96d56Sopenharmony_ci    .doc = NULL,
5007db96d56Sopenharmony_ci    .n_in_sequence = 6
5017db96d56Sopenharmony_ci};
5027db96d56Sopenharmony_ci
5037db96d56Sopenharmony_cistatic PyStructSequence_Desc profiler_subentry_desc = {
5047db96d56Sopenharmony_ci    .name = "_lsprof.profiler_subentry",
5057db96d56Sopenharmony_ci    .fields = profiler_subentry_fields,
5067db96d56Sopenharmony_ci    .doc = NULL,
5077db96d56Sopenharmony_ci    .n_in_sequence = 5
5087db96d56Sopenharmony_ci};
5097db96d56Sopenharmony_ci
5107db96d56Sopenharmony_citypedef struct {
5117db96d56Sopenharmony_ci    PyObject *list;
5127db96d56Sopenharmony_ci    PyObject *sublist;
5137db96d56Sopenharmony_ci    double factor;
5147db96d56Sopenharmony_ci    _lsprof_state *state;
5157db96d56Sopenharmony_ci} statscollector_t;
5167db96d56Sopenharmony_ci
5177db96d56Sopenharmony_cistatic int statsForSubEntry(rotating_node_t *node, void *arg)
5187db96d56Sopenharmony_ci{
5197db96d56Sopenharmony_ci    ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
5207db96d56Sopenharmony_ci    statscollector_t *collect = (statscollector_t*) arg;
5217db96d56Sopenharmony_ci    ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
5227db96d56Sopenharmony_ci    int err;
5237db96d56Sopenharmony_ci    PyObject *sinfo;
5247db96d56Sopenharmony_ci    sinfo = PyObject_CallFunction((PyObject*) collect->state->stats_subentry_type,
5257db96d56Sopenharmony_ci                                  "((Olldd))",
5267db96d56Sopenharmony_ci                                  entry->userObj,
5277db96d56Sopenharmony_ci                                  sentry->callcount,
5287db96d56Sopenharmony_ci                                  sentry->recursivecallcount,
5297db96d56Sopenharmony_ci                                  collect->factor * sentry->tt,
5307db96d56Sopenharmony_ci                                  collect->factor * sentry->it);
5317db96d56Sopenharmony_ci    if (sinfo == NULL)
5327db96d56Sopenharmony_ci        return -1;
5337db96d56Sopenharmony_ci    err = PyList_Append(collect->sublist, sinfo);
5347db96d56Sopenharmony_ci    Py_DECREF(sinfo);
5357db96d56Sopenharmony_ci    return err;
5367db96d56Sopenharmony_ci}
5377db96d56Sopenharmony_ci
5387db96d56Sopenharmony_cistatic int statsForEntry(rotating_node_t *node, void *arg)
5397db96d56Sopenharmony_ci{
5407db96d56Sopenharmony_ci    ProfilerEntry *entry = (ProfilerEntry*) node;
5417db96d56Sopenharmony_ci    statscollector_t *collect = (statscollector_t*) arg;
5427db96d56Sopenharmony_ci    PyObject *info;
5437db96d56Sopenharmony_ci    int err;
5447db96d56Sopenharmony_ci    if (entry->callcount == 0)
5457db96d56Sopenharmony_ci        return 0;   /* skip */
5467db96d56Sopenharmony_ci
5477db96d56Sopenharmony_ci    if (entry->calls != EMPTY_ROTATING_TREE) {
5487db96d56Sopenharmony_ci        collect->sublist = PyList_New(0);
5497db96d56Sopenharmony_ci        if (collect->sublist == NULL)
5507db96d56Sopenharmony_ci            return -1;
5517db96d56Sopenharmony_ci        if (RotatingTree_Enum(entry->calls,
5527db96d56Sopenharmony_ci                              statsForSubEntry, collect) != 0) {
5537db96d56Sopenharmony_ci            Py_DECREF(collect->sublist);
5547db96d56Sopenharmony_ci            return -1;
5557db96d56Sopenharmony_ci        }
5567db96d56Sopenharmony_ci    }
5577db96d56Sopenharmony_ci    else {
5587db96d56Sopenharmony_ci        Py_INCREF(Py_None);
5597db96d56Sopenharmony_ci        collect->sublist = Py_None;
5607db96d56Sopenharmony_ci    }
5617db96d56Sopenharmony_ci
5627db96d56Sopenharmony_ci    info = PyObject_CallFunction((PyObject*) collect->state->stats_entry_type,
5637db96d56Sopenharmony_ci                                 "((OllddO))",
5647db96d56Sopenharmony_ci                                 entry->userObj,
5657db96d56Sopenharmony_ci                                 entry->callcount,
5667db96d56Sopenharmony_ci                                 entry->recursivecallcount,
5677db96d56Sopenharmony_ci                                 collect->factor * entry->tt,
5687db96d56Sopenharmony_ci                                 collect->factor * entry->it,
5697db96d56Sopenharmony_ci                                 collect->sublist);
5707db96d56Sopenharmony_ci    Py_DECREF(collect->sublist);
5717db96d56Sopenharmony_ci    if (info == NULL)
5727db96d56Sopenharmony_ci        return -1;
5737db96d56Sopenharmony_ci    err = PyList_Append(collect->list, info);
5747db96d56Sopenharmony_ci    Py_DECREF(info);
5757db96d56Sopenharmony_ci    return err;
5767db96d56Sopenharmony_ci}
5777db96d56Sopenharmony_ci
5787db96d56Sopenharmony_ci/*[clinic input]
5797db96d56Sopenharmony_ci_lsprof.Profiler.getstats
5807db96d56Sopenharmony_ci
5817db96d56Sopenharmony_ci    cls: defining_class
5827db96d56Sopenharmony_ci
5837db96d56Sopenharmony_cilist of profiler_entry objects.
5847db96d56Sopenharmony_ci
5857db96d56Sopenharmony_cigetstats() -> list of profiler_entry objects
5867db96d56Sopenharmony_ci
5877db96d56Sopenharmony_ciReturn all information collected by the profiler.
5887db96d56Sopenharmony_ciEach profiler_entry is a tuple-like object with the
5897db96d56Sopenharmony_cifollowing attributes:
5907db96d56Sopenharmony_ci
5917db96d56Sopenharmony_ci    code          code object
5927db96d56Sopenharmony_ci    callcount     how many times this was called
5937db96d56Sopenharmony_ci    reccallcount  how many times called recursively
5947db96d56Sopenharmony_ci    totaltime     total time in this entry
5957db96d56Sopenharmony_ci    inlinetime    inline time in this entry (not in subcalls)
5967db96d56Sopenharmony_ci    calls         details of the calls
5977db96d56Sopenharmony_ci
5987db96d56Sopenharmony_ciThe calls attribute is either None or a list of
5997db96d56Sopenharmony_ciprofiler_subentry objects:
6007db96d56Sopenharmony_ci
6017db96d56Sopenharmony_ci    code          called code object
6027db96d56Sopenharmony_ci    callcount     how many times this is called
6037db96d56Sopenharmony_ci    reccallcount  how many times this is called recursively
6047db96d56Sopenharmony_ci    totaltime     total time spent in this call
6057db96d56Sopenharmony_ci    inlinetime    inline time (not in further subcalls)
6067db96d56Sopenharmony_ci[clinic start generated code]*/
6077db96d56Sopenharmony_ci
6087db96d56Sopenharmony_cistatic PyObject *
6097db96d56Sopenharmony_ci_lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls)
6107db96d56Sopenharmony_ci/*[clinic end generated code: output=1806ef720019ee03 input=445e193ef4522902]*/
6117db96d56Sopenharmony_ci{
6127db96d56Sopenharmony_ci    statscollector_t collect;
6137db96d56Sopenharmony_ci    collect.state = PyType_GetModuleState(cls);
6147db96d56Sopenharmony_ci    if (pending_exception(self)) {
6157db96d56Sopenharmony_ci        return NULL;
6167db96d56Sopenharmony_ci    }
6177db96d56Sopenharmony_ci    if (!self->externalTimer || self->externalTimerUnit == 0.0) {
6187db96d56Sopenharmony_ci        _PyTime_t onesec = _PyTime_FromSeconds(1);
6197db96d56Sopenharmony_ci        collect.factor = (double)1 / onesec;
6207db96d56Sopenharmony_ci    }
6217db96d56Sopenharmony_ci    else {
6227db96d56Sopenharmony_ci        collect.factor = self->externalTimerUnit;
6237db96d56Sopenharmony_ci    }
6247db96d56Sopenharmony_ci
6257db96d56Sopenharmony_ci    collect.list = PyList_New(0);
6267db96d56Sopenharmony_ci    if (collect.list == NULL)
6277db96d56Sopenharmony_ci        return NULL;
6287db96d56Sopenharmony_ci    if (RotatingTree_Enum(self->profilerEntries, statsForEntry, &collect)
6297db96d56Sopenharmony_ci        != 0) {
6307db96d56Sopenharmony_ci        Py_DECREF(collect.list);
6317db96d56Sopenharmony_ci        return NULL;
6327db96d56Sopenharmony_ci    }
6337db96d56Sopenharmony_ci    return collect.list;
6347db96d56Sopenharmony_ci}
6357db96d56Sopenharmony_ci
6367db96d56Sopenharmony_cistatic int
6377db96d56Sopenharmony_cisetSubcalls(ProfilerObject *pObj, int nvalue)
6387db96d56Sopenharmony_ci{
6397db96d56Sopenharmony_ci    if (nvalue == 0)
6407db96d56Sopenharmony_ci        pObj->flags &= ~POF_SUBCALLS;
6417db96d56Sopenharmony_ci    else if (nvalue > 0)
6427db96d56Sopenharmony_ci        pObj->flags |=  POF_SUBCALLS;
6437db96d56Sopenharmony_ci    return 0;
6447db96d56Sopenharmony_ci}
6457db96d56Sopenharmony_ci
6467db96d56Sopenharmony_cistatic int
6477db96d56Sopenharmony_cisetBuiltins(ProfilerObject *pObj, int nvalue)
6487db96d56Sopenharmony_ci{
6497db96d56Sopenharmony_ci    if (nvalue == 0)
6507db96d56Sopenharmony_ci        pObj->flags &= ~POF_BUILTINS;
6517db96d56Sopenharmony_ci    else if (nvalue > 0) {
6527db96d56Sopenharmony_ci        pObj->flags |=  POF_BUILTINS;
6537db96d56Sopenharmony_ci    }
6547db96d56Sopenharmony_ci    return 0;
6557db96d56Sopenharmony_ci}
6567db96d56Sopenharmony_ci
6577db96d56Sopenharmony_ciPyDoc_STRVAR(enable_doc, "\
6587db96d56Sopenharmony_cienable(subcalls=True, builtins=True)\n\
6597db96d56Sopenharmony_ci\n\
6607db96d56Sopenharmony_ciStart collecting profiling information.\n\
6617db96d56Sopenharmony_ciIf 'subcalls' is True, also records for each function\n\
6627db96d56Sopenharmony_cistatistics separated according to its current caller.\n\
6637db96d56Sopenharmony_ciIf 'builtins' is True, records the time spent in\n\
6647db96d56Sopenharmony_cibuilt-in functions separately from their caller.\n\
6657db96d56Sopenharmony_ci");
6667db96d56Sopenharmony_ci
6677db96d56Sopenharmony_cistatic PyObject*
6687db96d56Sopenharmony_ciprofiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
6697db96d56Sopenharmony_ci{
6707db96d56Sopenharmony_ci    int subcalls = -1;
6717db96d56Sopenharmony_ci    int builtins = -1;
6727db96d56Sopenharmony_ci    static char *kwlist[] = {"subcalls", "builtins", 0};
6737db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
6747db96d56Sopenharmony_ci                                     kwlist, &subcalls, &builtins))
6757db96d56Sopenharmony_ci        return NULL;
6767db96d56Sopenharmony_ci    if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) {
6777db96d56Sopenharmony_ci        return NULL;
6787db96d56Sopenharmony_ci    }
6797db96d56Sopenharmony_ci
6807db96d56Sopenharmony_ci    PyThreadState *tstate = _PyThreadState_GET();
6817db96d56Sopenharmony_ci    if (_PyEval_SetProfile(tstate, profiler_callback, (PyObject*)self) < 0) {
6827db96d56Sopenharmony_ci        return NULL;
6837db96d56Sopenharmony_ci    }
6847db96d56Sopenharmony_ci
6857db96d56Sopenharmony_ci    self->flags |= POF_ENABLED;
6867db96d56Sopenharmony_ci    Py_RETURN_NONE;
6877db96d56Sopenharmony_ci}
6887db96d56Sopenharmony_ci
6897db96d56Sopenharmony_cistatic void
6907db96d56Sopenharmony_ciflush_unmatched(ProfilerObject *pObj)
6917db96d56Sopenharmony_ci{
6927db96d56Sopenharmony_ci    while (pObj->currentProfilerContext) {
6937db96d56Sopenharmony_ci        ProfilerContext *pContext = pObj->currentProfilerContext;
6947db96d56Sopenharmony_ci        ProfilerEntry *profEntry= pContext->ctxEntry;
6957db96d56Sopenharmony_ci        if (profEntry)
6967db96d56Sopenharmony_ci            Stop(pObj, pContext, profEntry);
6977db96d56Sopenharmony_ci        else
6987db96d56Sopenharmony_ci            pObj->currentProfilerContext = pContext->previous;
6997db96d56Sopenharmony_ci        if (pContext)
7007db96d56Sopenharmony_ci            PyMem_Free(pContext);
7017db96d56Sopenharmony_ci    }
7027db96d56Sopenharmony_ci
7037db96d56Sopenharmony_ci}
7047db96d56Sopenharmony_ci
7057db96d56Sopenharmony_ciPyDoc_STRVAR(disable_doc, "\
7067db96d56Sopenharmony_cidisable()\n\
7077db96d56Sopenharmony_ci\n\
7087db96d56Sopenharmony_ciStop collecting profiling information.\n\
7097db96d56Sopenharmony_ci");
7107db96d56Sopenharmony_ci
7117db96d56Sopenharmony_cistatic PyObject*
7127db96d56Sopenharmony_ciprofiler_disable(ProfilerObject *self, PyObject* noarg)
7137db96d56Sopenharmony_ci{
7147db96d56Sopenharmony_ci    PyThreadState *tstate = _PyThreadState_GET();
7157db96d56Sopenharmony_ci    if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
7167db96d56Sopenharmony_ci        return NULL;
7177db96d56Sopenharmony_ci    }
7187db96d56Sopenharmony_ci    self->flags &= ~POF_ENABLED;
7197db96d56Sopenharmony_ci
7207db96d56Sopenharmony_ci    flush_unmatched(self);
7217db96d56Sopenharmony_ci    if (pending_exception(self)) {
7227db96d56Sopenharmony_ci        return NULL;
7237db96d56Sopenharmony_ci    }
7247db96d56Sopenharmony_ci    Py_RETURN_NONE;
7257db96d56Sopenharmony_ci}
7267db96d56Sopenharmony_ci
7277db96d56Sopenharmony_ciPyDoc_STRVAR(clear_doc, "\
7287db96d56Sopenharmony_ciclear()\n\
7297db96d56Sopenharmony_ci\n\
7307db96d56Sopenharmony_ciClear all profiling information collected so far.\n\
7317db96d56Sopenharmony_ci");
7327db96d56Sopenharmony_ci
7337db96d56Sopenharmony_cistatic PyObject*
7347db96d56Sopenharmony_ciprofiler_clear(ProfilerObject *pObj, PyObject* noarg)
7357db96d56Sopenharmony_ci{
7367db96d56Sopenharmony_ci    clearEntries(pObj);
7377db96d56Sopenharmony_ci    Py_RETURN_NONE;
7387db96d56Sopenharmony_ci}
7397db96d56Sopenharmony_ci
7407db96d56Sopenharmony_cistatic int
7417db96d56Sopenharmony_ciprofiler_traverse(ProfilerObject *op, visitproc visit, void *arg)
7427db96d56Sopenharmony_ci{
7437db96d56Sopenharmony_ci    Py_VISIT(Py_TYPE(op));
7447db96d56Sopenharmony_ci    return 0;
7457db96d56Sopenharmony_ci}
7467db96d56Sopenharmony_ci
7477db96d56Sopenharmony_cistatic void
7487db96d56Sopenharmony_ciprofiler_dealloc(ProfilerObject *op)
7497db96d56Sopenharmony_ci{
7507db96d56Sopenharmony_ci    PyObject_GC_UnTrack(op);
7517db96d56Sopenharmony_ci    if (op->flags & POF_ENABLED) {
7527db96d56Sopenharmony_ci        PyThreadState *tstate = _PyThreadState_GET();
7537db96d56Sopenharmony_ci        if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
7547db96d56Sopenharmony_ci            _PyErr_WriteUnraisableMsg("When destroying _lsprof profiler", NULL);
7557db96d56Sopenharmony_ci        }
7567db96d56Sopenharmony_ci    }
7577db96d56Sopenharmony_ci
7587db96d56Sopenharmony_ci    flush_unmatched(op);
7597db96d56Sopenharmony_ci    clearEntries(op);
7607db96d56Sopenharmony_ci    Py_XDECREF(op->externalTimer);
7617db96d56Sopenharmony_ci    PyTypeObject *tp = Py_TYPE(op);
7627db96d56Sopenharmony_ci    tp->tp_free(op);
7637db96d56Sopenharmony_ci    Py_DECREF(tp);
7647db96d56Sopenharmony_ci}
7657db96d56Sopenharmony_ci
7667db96d56Sopenharmony_cistatic int
7677db96d56Sopenharmony_ciprofiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
7687db96d56Sopenharmony_ci{
7697db96d56Sopenharmony_ci    PyObject *timer = NULL;
7707db96d56Sopenharmony_ci    double timeunit = 0.0;
7717db96d56Sopenharmony_ci    int subcalls = 1;
7727db96d56Sopenharmony_ci    int builtins = 1;
7737db96d56Sopenharmony_ci    static char *kwlist[] = {"timer", "timeunit",
7747db96d56Sopenharmony_ci                                   "subcalls", "builtins", 0};
7757db96d56Sopenharmony_ci
7767db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
7777db96d56Sopenharmony_ci                                     &timer, &timeunit,
7787db96d56Sopenharmony_ci                                     &subcalls, &builtins))
7797db96d56Sopenharmony_ci        return -1;
7807db96d56Sopenharmony_ci
7817db96d56Sopenharmony_ci    if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
7827db96d56Sopenharmony_ci        return -1;
7837db96d56Sopenharmony_ci    pObj->externalTimerUnit = timeunit;
7847db96d56Sopenharmony_ci    Py_XINCREF(timer);
7857db96d56Sopenharmony_ci    Py_XSETREF(pObj->externalTimer, timer);
7867db96d56Sopenharmony_ci    return 0;
7877db96d56Sopenharmony_ci}
7887db96d56Sopenharmony_ci
7897db96d56Sopenharmony_cistatic PyMethodDef profiler_methods[] = {
7907db96d56Sopenharmony_ci    _LSPROF_PROFILER_GETSTATS_METHODDEF
7917db96d56Sopenharmony_ci    {"enable",          _PyCFunction_CAST(profiler_enable),
7927db96d56Sopenharmony_ci                    METH_VARARGS | METH_KEYWORDS,       enable_doc},
7937db96d56Sopenharmony_ci    {"disable",         (PyCFunction)profiler_disable,
7947db96d56Sopenharmony_ci                    METH_NOARGS,                        disable_doc},
7957db96d56Sopenharmony_ci    {"clear",           (PyCFunction)profiler_clear,
7967db96d56Sopenharmony_ci                    METH_NOARGS,                        clear_doc},
7977db96d56Sopenharmony_ci    {NULL, NULL}
7987db96d56Sopenharmony_ci};
7997db96d56Sopenharmony_ci
8007db96d56Sopenharmony_ciPyDoc_STRVAR(profiler_doc, "\
8017db96d56Sopenharmony_ciProfiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\
8027db96d56Sopenharmony_ci\n\
8037db96d56Sopenharmony_ci    Builds a profiler object using the specified timer function.\n\
8047db96d56Sopenharmony_ci    The default timer is a fast built-in one based on real time.\n\
8057db96d56Sopenharmony_ci    For custom timer functions returning integers, timeunit can\n\
8067db96d56Sopenharmony_ci    be a float specifying a scale (i.e. how long each integer unit\n\
8077db96d56Sopenharmony_ci    is, in seconds).\n\
8087db96d56Sopenharmony_ci");
8097db96d56Sopenharmony_ci
8107db96d56Sopenharmony_cistatic PyType_Slot _lsprof_profiler_type_spec_slots[] = {
8117db96d56Sopenharmony_ci    {Py_tp_doc, (void *)profiler_doc},
8127db96d56Sopenharmony_ci    {Py_tp_methods, profiler_methods},
8137db96d56Sopenharmony_ci    {Py_tp_dealloc, profiler_dealloc},
8147db96d56Sopenharmony_ci    {Py_tp_init, profiler_init},
8157db96d56Sopenharmony_ci    {Py_tp_traverse, profiler_traverse},
8167db96d56Sopenharmony_ci    {0, 0}
8177db96d56Sopenharmony_ci};
8187db96d56Sopenharmony_ci
8197db96d56Sopenharmony_cistatic PyType_Spec _lsprof_profiler_type_spec = {
8207db96d56Sopenharmony_ci    .name = "_lsprof.Profiler",
8217db96d56Sopenharmony_ci    .basicsize = sizeof(ProfilerObject),
8227db96d56Sopenharmony_ci    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
8237db96d56Sopenharmony_ci              Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
8247db96d56Sopenharmony_ci    .slots = _lsprof_profiler_type_spec_slots,
8257db96d56Sopenharmony_ci};
8267db96d56Sopenharmony_ci
8277db96d56Sopenharmony_cistatic PyMethodDef moduleMethods[] = {
8287db96d56Sopenharmony_ci    {NULL, NULL}
8297db96d56Sopenharmony_ci};
8307db96d56Sopenharmony_ci
8317db96d56Sopenharmony_cistatic int
8327db96d56Sopenharmony_ci_lsprof_traverse(PyObject *module, visitproc visit, void *arg)
8337db96d56Sopenharmony_ci{
8347db96d56Sopenharmony_ci    _lsprof_state *state = _lsprof_get_state(module);
8357db96d56Sopenharmony_ci    Py_VISIT(state->profiler_type);
8367db96d56Sopenharmony_ci    Py_VISIT(state->stats_entry_type);
8377db96d56Sopenharmony_ci    Py_VISIT(state->stats_subentry_type);
8387db96d56Sopenharmony_ci    return 0;
8397db96d56Sopenharmony_ci}
8407db96d56Sopenharmony_ci
8417db96d56Sopenharmony_cistatic int
8427db96d56Sopenharmony_ci_lsprof_clear(PyObject *module)
8437db96d56Sopenharmony_ci{
8447db96d56Sopenharmony_ci    _lsprof_state *state = _lsprof_get_state(module);
8457db96d56Sopenharmony_ci    Py_CLEAR(state->profiler_type);
8467db96d56Sopenharmony_ci    Py_CLEAR(state->stats_entry_type);
8477db96d56Sopenharmony_ci    Py_CLEAR(state->stats_subentry_type);
8487db96d56Sopenharmony_ci    return 0;
8497db96d56Sopenharmony_ci}
8507db96d56Sopenharmony_ci
8517db96d56Sopenharmony_cistatic void
8527db96d56Sopenharmony_ci_lsprof_free(void *module)
8537db96d56Sopenharmony_ci{
8547db96d56Sopenharmony_ci    _lsprof_clear((PyObject *)module);
8557db96d56Sopenharmony_ci}
8567db96d56Sopenharmony_ci
8577db96d56Sopenharmony_cistatic int
8587db96d56Sopenharmony_ci_lsprof_exec(PyObject *module)
8597db96d56Sopenharmony_ci{
8607db96d56Sopenharmony_ci    _lsprof_state *state = PyModule_GetState(module);
8617db96d56Sopenharmony_ci
8627db96d56Sopenharmony_ci    state->profiler_type = (PyTypeObject *)PyType_FromModuleAndSpec(
8637db96d56Sopenharmony_ci        module, &_lsprof_profiler_type_spec, NULL);
8647db96d56Sopenharmony_ci    if (state->profiler_type == NULL) {
8657db96d56Sopenharmony_ci        return -1;
8667db96d56Sopenharmony_ci    }
8677db96d56Sopenharmony_ci
8687db96d56Sopenharmony_ci    if (PyModule_AddType(module, state->profiler_type) < 0) {
8697db96d56Sopenharmony_ci        return -1;
8707db96d56Sopenharmony_ci    }
8717db96d56Sopenharmony_ci
8727db96d56Sopenharmony_ci    state->stats_entry_type = PyStructSequence_NewType(&profiler_entry_desc);
8737db96d56Sopenharmony_ci    if (state->stats_entry_type == NULL) {
8747db96d56Sopenharmony_ci        return -1;
8757db96d56Sopenharmony_ci    }
8767db96d56Sopenharmony_ci    if (PyModule_AddType(module, state->stats_entry_type) < 0) {
8777db96d56Sopenharmony_ci        return -1;
8787db96d56Sopenharmony_ci    }
8797db96d56Sopenharmony_ci
8807db96d56Sopenharmony_ci    state->stats_subentry_type = PyStructSequence_NewType(&profiler_subentry_desc);
8817db96d56Sopenharmony_ci    if (state->stats_subentry_type == NULL) {
8827db96d56Sopenharmony_ci        return -1;
8837db96d56Sopenharmony_ci    }
8847db96d56Sopenharmony_ci    if (PyModule_AddType(module, state->stats_subentry_type) < 0) {
8857db96d56Sopenharmony_ci        return -1;
8867db96d56Sopenharmony_ci    }
8877db96d56Sopenharmony_ci
8887db96d56Sopenharmony_ci    return 0;
8897db96d56Sopenharmony_ci}
8907db96d56Sopenharmony_ci
8917db96d56Sopenharmony_cistatic PyModuleDef_Slot _lsprofslots[] = {
8927db96d56Sopenharmony_ci    {Py_mod_exec, _lsprof_exec},
8937db96d56Sopenharmony_ci    {0, NULL}
8947db96d56Sopenharmony_ci};
8957db96d56Sopenharmony_ci
8967db96d56Sopenharmony_cistatic struct PyModuleDef _lsprofmodule = {
8977db96d56Sopenharmony_ci    PyModuleDef_HEAD_INIT,
8987db96d56Sopenharmony_ci    .m_name = "_lsprof",
8997db96d56Sopenharmony_ci    .m_doc = "Fast profiler",
9007db96d56Sopenharmony_ci    .m_size = sizeof(_lsprof_state),
9017db96d56Sopenharmony_ci    .m_methods = moduleMethods,
9027db96d56Sopenharmony_ci    .m_slots = _lsprofslots,
9037db96d56Sopenharmony_ci    .m_traverse = _lsprof_traverse,
9047db96d56Sopenharmony_ci    .m_clear = _lsprof_clear,
9057db96d56Sopenharmony_ci    .m_free = _lsprof_free
9067db96d56Sopenharmony_ci};
9077db96d56Sopenharmony_ci
9087db96d56Sopenharmony_ciPyMODINIT_FUNC
9097db96d56Sopenharmony_ciPyInit__lsprof(void)
9107db96d56Sopenharmony_ci{
9117db96d56Sopenharmony_ci    return PyModuleDef_Init(&_lsprofmodule);
9127db96d56Sopenharmony_ci}
913