Home | History | Annotate | Download | only in Modules
      1 #include "Python.h"
      2 #include "compile.h"
      3 #include "frameobject.h"
      4 #include "structseq.h"
      5 #include "rotatingtree.h"
      6 
      7 #if !defined(HAVE_LONG_LONG)
      8 #error "This module requires long longs!"
      9 #endif
     10 
     11 /*** Selection of a high-precision timer ***/
     12 
     13 #ifdef MS_WINDOWS
     14 
     15 #include <windows.h>
     16 
     17 static PY_LONG_LONG
     18 hpTimer(void)
     19 {
     20     LARGE_INTEGER li;
     21     QueryPerformanceCounter(&li);
     22     return li.QuadPart;
     23 }
     24 
     25 static double
     26 hpTimerUnit(void)
     27 {
     28     LARGE_INTEGER li;
     29     if (QueryPerformanceFrequency(&li))
     30         return 1.0 / li.QuadPart;
     31     else
     32         return 0.000001;  /* unlikely */
     33 }
     34 
     35 #else  /* !MS_WINDOWS */
     36 
     37 #ifndef HAVE_GETTIMEOFDAY
     38 #error "This module requires gettimeofday() on non-Windows platforms!"
     39 #endif
     40 
     41 #if (defined(PYOS_OS2) && defined(PYCC_GCC))
     42 #include <sys/time.h>
     43 #else
     44 #include <sys/resource.h>
     45 #include <sys/times.h>
     46 #endif
     47 
     48 static PY_LONG_LONG
     49 hpTimer(void)
     50 {
     51     struct timeval tv;
     52     PY_LONG_LONG ret;
     53 #ifdef GETTIMEOFDAY_NO_TZ
     54     gettimeofday(&tv);
     55 #else
     56     gettimeofday(&tv, (struct timezone *)NULL);
     57 #endif
     58     ret = tv.tv_sec;
     59     ret = ret * 1000000 + tv.tv_usec;
     60     return ret;
     61 }
     62 
     63 static double
     64 hpTimerUnit(void)
     65 {
     66     return 0.000001;
     67 }
     68 
     69 #endif  /* MS_WINDOWS */
     70 
     71 /************************************************************/
     72 /* Written by Brett Rosen and Ted Czotter */
     73 
     74 struct _ProfilerEntry;
     75 
     76 /* represents a function called from another function */
     77 typedef struct _ProfilerSubEntry {
     78     rotating_node_t header;
     79     PY_LONG_LONG tt;
     80     PY_LONG_LONG it;
     81     long callcount;
     82     long recursivecallcount;
     83     long recursionLevel;
     84 } ProfilerSubEntry;
     85 
     86 /* represents a function or user defined block */
     87 typedef struct _ProfilerEntry {
     88     rotating_node_t header;
     89     PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
     90     PY_LONG_LONG tt; /* total time in this entry */
     91     PY_LONG_LONG it; /* inline time in this entry (not in subcalls) */
     92     long callcount; /* how many times this was called */
     93     long recursivecallcount; /* how many times called recursively */
     94     long recursionLevel;
     95     rotating_node_t *calls;
     96 } ProfilerEntry;
     97 
     98 typedef struct _ProfilerContext {
     99     PY_LONG_LONG t0;
    100     PY_LONG_LONG subt;
    101     struct _ProfilerContext *previous;
    102     ProfilerEntry *ctxEntry;
    103 } ProfilerContext;
    104 
    105 typedef struct {
    106     PyObject_HEAD
    107     rotating_node_t *profilerEntries;
    108     ProfilerContext *currentProfilerContext;
    109     ProfilerContext *freelistProfilerContext;
    110     int flags;
    111     PyObject *externalTimer;
    112     double externalTimerUnit;
    113 } ProfilerObject;
    114 
    115 #define POF_ENABLED     0x001
    116 #define POF_SUBCALLS    0x002
    117 #define POF_BUILTINS    0x004
    118 #define POF_NOMEMORY    0x100
    119 
    120 staticforward PyTypeObject PyProfiler_Type;
    121 
    122 #define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
    123 #define PyProfiler_CheckExact(op) (Py_TYPE(op) == &PyProfiler_Type)
    124 
    125 /*** External Timers ***/
    126 
    127 #define DOUBLE_TIMER_PRECISION   4294967296.0
    128 static PyObject *empty_tuple;
    129 
    130 static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj)
    131 {
    132     PY_LONG_LONG result;
    133     PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL);
    134     if (o == NULL) {
    135         PyErr_WriteUnraisable(pObj->externalTimer);
    136         return 0;
    137     }
    138     if (pObj->externalTimerUnit > 0.0) {
    139         /* interpret the result as an integer that will be scaled
    140            in profiler_getstats() */
    141         result = PyLong_AsLongLong(o);
    142     }
    143     else {
    144         /* interpret the result as a double measured in seconds.
    145            As the profiler works with PY_LONG_LONG internally
    146            we convert it to a large integer */
    147         double val = PyFloat_AsDouble(o);
    148         /* error handling delayed to the code below */
    149         result = (PY_LONG_LONG) (val * DOUBLE_TIMER_PRECISION);
    150     }
    151     Py_DECREF(o);
    152     if (PyErr_Occurred()) {
    153         PyErr_WriteUnraisable(pObj->externalTimer);
    154         return 0;
    155     }
    156     return result;
    157 }
    158 
    159 #define CALL_TIMER(pObj)        ((pObj)->externalTimer ?                \
    160                                         CallExternalTimer(pObj) :       \
    161                                         hpTimer())
    162 
    163 /*** ProfilerObject ***/
    164 
    165 static PyObject *
    166 normalizeUserObj(PyObject *obj)
    167 {
    168     PyCFunctionObject *fn;
    169     if (!PyCFunction_Check(obj)) {
    170         Py_INCREF(obj);
    171         return obj;
    172     }
    173     /* Replace built-in function objects with a descriptive string
    174        because of built-in methods -- keeping a reference to
    175        __self__ is probably not a good idea. */
    176     fn = (PyCFunctionObject *)obj;
    177 
    178     if (fn->m_self == NULL) {
    179         /* built-in function: look up the module name */
    180         PyObject *mod = fn->m_module;
    181         char *modname;
    182         if (mod && PyString_Check(mod)) {
    183             modname = PyString_AS_STRING(mod);
    184         }
    185         else if (mod && PyModule_Check(mod)) {
    186             modname = PyModule_GetName(mod);
    187             if (modname == NULL) {
    188                 PyErr_Clear();
    189                 modname = "__builtin__";
    190             }
    191         }
    192         else {
    193             modname = "__builtin__";
    194         }
    195         if (strcmp(modname, "__builtin__") != 0)
    196             return PyString_FromFormat("<%s.%s>",
    197                                        modname,
    198                                        fn->m_ml->ml_name);
    199         else
    200             return PyString_FromFormat("<%s>",
    201                                        fn->m_ml->ml_name);
    202     }
    203     else {
    204         /* built-in method: try to return
    205             repr(getattr(type(__self__), __name__))
    206         */
    207         PyObject *self = fn->m_self;
    208         PyObject *name = PyString_FromString(fn->m_ml->ml_name);
    209         if (name != NULL) {
    210             PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
    211             Py_XINCREF(mo);
    212             Py_DECREF(name);
    213             if (mo != NULL) {
    214                 PyObject *res = PyObject_Repr(mo);
    215                 Py_DECREF(mo);
    216                 if (res != NULL)
    217                     return res;
    218             }
    219         }
    220         PyErr_Clear();
    221         return PyString_FromFormat("<built-in method %s>",
    222                                    fn->m_ml->ml_name);
    223     }
    224 }
    225 
    226 static ProfilerEntry*
    227 newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
    228 {
    229     ProfilerEntry *self;
    230     self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry));
    231     if (self == NULL) {
    232         pObj->flags |= POF_NOMEMORY;
    233         return NULL;
    234     }
    235     userObj = normalizeUserObj(userObj);
    236     if (userObj == NULL) {
    237         PyErr_Clear();
    238         free(self);
    239         pObj->flags |= POF_NOMEMORY;
    240         return NULL;
    241     }
    242     self->header.key = key;
    243     self->userObj = userObj;
    244     self->tt = 0;
    245     self->it = 0;
    246     self->callcount = 0;
    247     self->recursivecallcount = 0;
    248     self->recursionLevel = 0;
    249     self->calls = EMPTY_ROTATING_TREE;
    250     RotatingTree_Add(&pObj->profilerEntries, &self->header);
    251     return self;
    252 }
    253 
    254 static ProfilerEntry*
    255 getEntry(ProfilerObject *pObj, void *key)
    256 {
    257     return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
    258 }
    259 
    260 static ProfilerSubEntry *
    261 getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
    262 {
    263     return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
    264                                                 (void *)entry);
    265 }
    266 
    267 static ProfilerSubEntry *
    268 newSubEntry(ProfilerObject *pObj,  ProfilerEntry *caller, ProfilerEntry* entry)
    269 {
    270     ProfilerSubEntry *self;
    271     self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry));
    272     if (self == NULL) {
    273         pObj->flags |= POF_NOMEMORY;
    274         return NULL;
    275     }
    276     self->header.key = (void *)entry;
    277     self->tt = 0;
    278     self->it = 0;
    279     self->callcount = 0;
    280     self->recursivecallcount = 0;
    281     self->recursionLevel = 0;
    282     RotatingTree_Add(&caller->calls, &self->header);
    283     return self;
    284 }
    285 
    286 static int freeSubEntry(rotating_node_t *header, void *arg)
    287 {
    288     ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
    289     free(subentry);
    290     return 0;
    291 }
    292 
    293 static int freeEntry(rotating_node_t *header, void *arg)
    294 {
    295     ProfilerEntry *entry = (ProfilerEntry*) header;
    296     RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
    297     Py_DECREF(entry->userObj);
    298     free(entry);
    299     return 0;
    300 }
    301 
    302 static void clearEntries(ProfilerObject *pObj)
    303 {
    304     RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
    305     pObj->profilerEntries = EMPTY_ROTATING_TREE;
    306     /* release the memory hold by the ProfilerContexts */
    307     if (pObj->currentProfilerContext) {
    308         free(pObj->currentProfilerContext);
    309         pObj->currentProfilerContext = NULL;
    310     }
    311     while (pObj->freelistProfilerContext) {
    312         ProfilerContext *c = pObj->freelistProfilerContext;
    313         pObj->freelistProfilerContext = c->previous;
    314         free(c);
    315     }
    316     pObj->freelistProfilerContext = NULL;
    317 }
    318 
    319 static void
    320 initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
    321 {
    322     self->ctxEntry = entry;
    323     self->subt = 0;
    324     self->previous = pObj->currentProfilerContext;
    325     pObj->currentProfilerContext = self;
    326     ++entry->recursionLevel;
    327     if ((pObj->flags & POF_SUBCALLS) && self->previous) {
    328         /* find or create an entry for me in my caller's entry */
    329         ProfilerEntry *caller = self->previous->ctxEntry;
    330         ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
    331         if (subentry == NULL)
    332             subentry = newSubEntry(pObj, caller, entry);
    333         if (subentry)
    334             ++subentry->recursionLevel;
    335     }
    336     self->t0 = CALL_TIMER(pObj);
    337 }
    338 
    339 static void
    340 Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
    341 {
    342     PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0;
    343     PY_LONG_LONG it = tt - self->subt;
    344     if (self->previous)
    345         self->previous->subt += tt;
    346     pObj->currentProfilerContext = self->previous;
    347     if (--entry->recursionLevel == 0)
    348         entry->tt += tt;
    349     else
    350         ++entry->recursivecallcount;
    351     entry->it += it;
    352     entry->callcount++;
    353     if ((pObj->flags & POF_SUBCALLS) && self->previous) {
    354         /* find or create an entry for me in my caller's entry */
    355         ProfilerEntry *caller = self->previous->ctxEntry;
    356         ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
    357         if (subentry) {
    358             if (--subentry->recursionLevel == 0)
    359                 subentry->tt += tt;
    360             else
    361                 ++subentry->recursivecallcount;
    362             subentry->it += it;
    363             ++subentry->callcount;
    364         }
    365     }
    366 }
    367 
    368 static void
    369 ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
    370 {
    371     /* entering a call to the function identified by 'key'
    372        (which can be a PyCodeObject or a PyMethodDef pointer) */
    373     ProfilerObject *pObj = (ProfilerObject*)self;
    374     ProfilerEntry *profEntry;
    375     ProfilerContext *pContext;
    376 
    377     /* In the case of entering a generator expression frame via a
    378      * throw (gen_send_ex(.., 1)), we may already have an
    379      * Exception set here. We must not mess around with this
    380      * exception, and some of the code under here assumes that
    381      * PyErr_* is its own to mess around with, so we have to
    382      * save and restore any current exception. */
    383     PyObject *last_type, *last_value, *last_tb;
    384     PyErr_Fetch(&last_type, &last_value, &last_tb);
    385 
    386     profEntry = getEntry(pObj, key);
    387     if (profEntry == NULL) {
    388         profEntry = newProfilerEntry(pObj, key, userObj);
    389         if (profEntry == NULL)
    390             goto restorePyerr;
    391     }
    392     /* grab a ProfilerContext out of the free list */
    393     pContext = pObj->freelistProfilerContext;
    394     if (pContext) {
    395         pObj->freelistProfilerContext = pContext->previous;
    396     }
    397     else {
    398         /* free list exhausted, allocate a new one */
    399         pContext = (ProfilerContext*)
    400             malloc(sizeof(ProfilerContext));
    401         if (pContext == NULL) {
    402             pObj->flags |= POF_NOMEMORY;
    403             goto restorePyerr;
    404         }
    405     }
    406     initContext(pObj, pContext, profEntry);
    407 
    408 restorePyerr:
    409     PyErr_Restore(last_type, last_value, last_tb);
    410 }
    411 
    412 static void
    413 ptrace_leave_call(PyObject *self, void *key)
    414 {
    415     /* leaving a call to the function identified by 'key' */
    416     ProfilerObject *pObj = (ProfilerObject*)self;
    417     ProfilerEntry *profEntry;
    418     ProfilerContext *pContext;
    419 
    420     pContext = pObj->currentProfilerContext;
    421     if (pContext == NULL)
    422         return;
    423     profEntry = getEntry(pObj, key);
    424     if (profEntry) {
    425         Stop(pObj, pContext, profEntry);
    426     }
    427     else {
    428         pObj->currentProfilerContext = pContext->previous;
    429     }
    430     /* put pContext into the free list */
    431     pContext->previous = pObj->freelistProfilerContext;
    432     pObj->freelistProfilerContext = pContext;
    433 }
    434 
    435 static int
    436 profiler_callback(PyObject *self, PyFrameObject *frame, int what,
    437                   PyObject *arg)
    438 {
    439     switch (what) {
    440 
    441     /* the 'frame' of a called function is about to start its execution */
    442     case PyTrace_CALL:
    443         ptrace_enter_call(self, (void *)frame->f_code,
    444                                 (PyObject *)frame->f_code);
    445         break;
    446 
    447     /* the 'frame' of a called function is about to finish
    448        (either normally or with an exception) */
    449     case PyTrace_RETURN:
    450         ptrace_leave_call(self, (void *)frame->f_code);
    451         break;
    452 
    453     /* case PyTrace_EXCEPTION:
    454         If the exception results in the function exiting, a
    455         PyTrace_RETURN event will be generated, so we don't need to
    456         handle it. */
    457 
    458 #ifdef PyTrace_C_CALL   /* not defined in Python <= 2.3 */
    459     /* the Python function 'frame' is issuing a call to the built-in
    460        function 'arg' */
    461     case PyTrace_C_CALL:
    462         if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
    463             && PyCFunction_Check(arg)) {
    464             ptrace_enter_call(self,
    465                               ((PyCFunctionObject *)arg)->m_ml,
    466                               arg);
    467         }
    468         break;
    469 
    470     /* the call to the built-in function 'arg' is returning into its
    471        caller 'frame' */
    472     case PyTrace_C_RETURN:              /* ...normally */
    473     case PyTrace_C_EXCEPTION:           /* ...with an exception set */
    474         if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
    475             && PyCFunction_Check(arg)) {
    476             ptrace_leave_call(self,
    477                               ((PyCFunctionObject *)arg)->m_ml);
    478         }
    479         break;
    480 #endif
    481 
    482     default:
    483         break;
    484     }
    485     return 0;
    486 }
    487 
    488 static int
    489 pending_exception(ProfilerObject *pObj)
    490 {
    491     if (pObj->flags & POF_NOMEMORY) {
    492         pObj->flags -= POF_NOMEMORY;
    493         PyErr_SetString(PyExc_MemoryError,
    494                         "memory was exhausted while profiling");
    495         return -1;
    496     }
    497     return 0;
    498 }
    499 
    500 /************************************************************/
    501 
    502 static PyStructSequence_Field profiler_entry_fields[] = {
    503     {"code",         "code object or built-in function name"},
    504     {"callcount",    "how many times this was called"},
    505     {"reccallcount", "how many times called recursively"},
    506     {"totaltime",    "total time in this entry"},
    507     {"inlinetime",   "inline time in this entry (not in subcalls)"},
    508     {"calls",        "details of the calls"},
    509     {0}
    510 };
    511 
    512 static PyStructSequence_Field profiler_subentry_fields[] = {
    513     {"code",         "called code object or built-in function name"},
    514     {"callcount",    "how many times this is called"},
    515     {"reccallcount", "how many times this is called recursively"},
    516     {"totaltime",    "total time spent in this call"},
    517     {"inlinetime",   "inline time (not in further subcalls)"},
    518     {0}
    519 };
    520 
    521 static PyStructSequence_Desc profiler_entry_desc = {
    522     "_lsprof.profiler_entry", /* name */
    523     NULL, /* doc */
    524     profiler_entry_fields,
    525     6
    526 };
    527 
    528 static PyStructSequence_Desc profiler_subentry_desc = {
    529     "_lsprof.profiler_subentry", /* name */
    530     NULL, /* doc */
    531     profiler_subentry_fields,
    532     5
    533 };
    534 
    535 static int initialized;
    536 static PyTypeObject StatsEntryType;
    537 static PyTypeObject StatsSubEntryType;
    538 
    539 
    540 typedef struct {
    541     PyObject *list;
    542     PyObject *sublist;
    543     double factor;
    544 } statscollector_t;
    545 
    546 static int statsForSubEntry(rotating_node_t *node, void *arg)
    547 {
    548     ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
    549     statscollector_t *collect = (statscollector_t*) arg;
    550     ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
    551     int err;
    552     PyObject *sinfo;
    553     sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
    554                                   "((Olldd))",
    555                                   entry->userObj,
    556                                   sentry->callcount,
    557                                   sentry->recursivecallcount,
    558                                   collect->factor * sentry->tt,
    559                                   collect->factor * sentry->it);
    560     if (sinfo == NULL)
    561         return -1;
    562     err = PyList_Append(collect->sublist, sinfo);
    563     Py_DECREF(sinfo);
    564     return err;
    565 }
    566 
    567 static int statsForEntry(rotating_node_t *node, void *arg)
    568 {
    569     ProfilerEntry *entry = (ProfilerEntry*) node;
    570     statscollector_t *collect = (statscollector_t*) arg;
    571     PyObject *info;
    572     int err;
    573     if (entry->callcount == 0)
    574         return 0;   /* skip */
    575 
    576     if (entry->calls != EMPTY_ROTATING_TREE) {
    577         collect->sublist = PyList_New(0);
    578         if (collect->sublist == NULL)
    579             return -1;
    580         if (RotatingTree_Enum(entry->calls,
    581                               statsForSubEntry, collect) != 0) {
    582             Py_DECREF(collect->sublist);
    583             return -1;
    584         }
    585     }
    586     else {
    587         Py_INCREF(Py_None);
    588         collect->sublist = Py_None;
    589     }
    590 
    591     info = PyObject_CallFunction((PyObject*) &StatsEntryType,
    592                                  "((OllddO))",
    593                                  entry->userObj,
    594                                  entry->callcount,
    595                                  entry->recursivecallcount,
    596                                  collect->factor * entry->tt,
    597                                  collect->factor * entry->it,
    598                                  collect->sublist);
    599     Py_DECREF(collect->sublist);
    600     if (info == NULL)
    601         return -1;
    602     err = PyList_Append(collect->list, info);
    603     Py_DECREF(info);
    604     return err;
    605 }
    606 
    607 PyDoc_STRVAR(getstats_doc, "\
    608 getstats() -> list of profiler_entry objects\n\
    609 \n\
    610 Return all information collected by the profiler.\n\
    611 Each profiler_entry is a tuple-like object with the\n\
    612 following attributes:\n\
    613 \n\
    614     code          code object\n\
    615     callcount     how many times this was called\n\
    616     reccallcount  how many times called recursively\n\
    617     totaltime     total time in this entry\n\
    618     inlinetime    inline time in this entry (not in subcalls)\n\
    619     calls         details of the calls\n\
    620 \n\
    621 The calls attribute is either None or a list of\n\
    622 profiler_subentry objects:\n\
    623 \n\
    624     code          called code object\n\
    625     callcount     how many times this is called\n\
    626     reccallcount  how many times this is called recursively\n\
    627     totaltime     total time spent in this call\n\
    628     inlinetime    inline time (not in further subcalls)\n\
    629 ");
    630 
    631 static PyObject*
    632 profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
    633 {
    634     statscollector_t collect;
    635     if (pending_exception(pObj))
    636         return NULL;
    637     if (!pObj->externalTimer)
    638         collect.factor = hpTimerUnit();
    639     else if (pObj->externalTimerUnit > 0.0)
    640         collect.factor = pObj->externalTimerUnit;
    641     else
    642         collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
    643     collect.list = PyList_New(0);
    644     if (collect.list == NULL)
    645         return NULL;
    646     if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
    647         != 0) {
    648         Py_DECREF(collect.list);
    649         return NULL;
    650     }
    651     return collect.list;
    652 }
    653 
    654 static int
    655 setSubcalls(ProfilerObject *pObj, int nvalue)
    656 {
    657     if (nvalue == 0)
    658         pObj->flags &= ~POF_SUBCALLS;
    659     else if (nvalue > 0)
    660         pObj->flags |=  POF_SUBCALLS;
    661     return 0;
    662 }
    663 
    664 static int
    665 setBuiltins(ProfilerObject *pObj, int nvalue)
    666 {
    667     if (nvalue == 0)
    668         pObj->flags &= ~POF_BUILTINS;
    669     else if (nvalue > 0) {
    670 #ifndef PyTrace_C_CALL
    671         PyErr_SetString(PyExc_ValueError,
    672                         "builtins=True requires Python >= 2.4");
    673         return -1;
    674 #else
    675         pObj->flags |=  POF_BUILTINS;
    676 #endif
    677     }
    678     return 0;
    679 }
    680 
    681 PyDoc_STRVAR(enable_doc, "\
    682 enable(subcalls=True, builtins=True)\n\
    683 \n\
    684 Start collecting profiling information.\n\
    685 If 'subcalls' is True, also records for each function\n\
    686 statistics separated according to its current caller.\n\
    687 If 'builtins' is True, records the time spent in\n\
    688 built-in functions separately from their caller.\n\
    689 ");
    690 
    691 static PyObject*
    692 profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
    693 {
    694     int subcalls = -1;
    695     int builtins = -1;
    696     static char *kwlist[] = {"subcalls", "builtins", 0};
    697     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
    698                                      kwlist, &subcalls, &builtins))
    699         return NULL;
    700     if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
    701         return NULL;
    702     PyEval_SetProfile(profiler_callback, (PyObject*)self);
    703     self->flags |= POF_ENABLED;
    704     Py_INCREF(Py_None);
    705     return Py_None;
    706 }
    707 
    708 static void
    709 flush_unmatched(ProfilerObject *pObj)
    710 {
    711     while (pObj->currentProfilerContext) {
    712         ProfilerContext *pContext = pObj->currentProfilerContext;
    713         ProfilerEntry *profEntry= pContext->ctxEntry;
    714         if (profEntry)
    715             Stop(pObj, pContext, profEntry);
    716         else
    717             pObj->currentProfilerContext = pContext->previous;
    718         if (pContext)
    719             free(pContext);
    720     }
    721 
    722 }
    723 
    724 PyDoc_STRVAR(disable_doc, "\
    725 disable()\n\
    726 \n\
    727 Stop collecting profiling information.\n\
    728 ");
    729 
    730 static PyObject*
    731 profiler_disable(ProfilerObject *self, PyObject* noarg)
    732 {
    733     self->flags &= ~POF_ENABLED;
    734     PyEval_SetProfile(NULL, NULL);
    735     flush_unmatched(self);
    736     if (pending_exception(self))
    737         return NULL;
    738     Py_INCREF(Py_None);
    739     return Py_None;
    740 }
    741 
    742 PyDoc_STRVAR(clear_doc, "\
    743 clear()\n\
    744 \n\
    745 Clear all profiling information collected so far.\n\
    746 ");
    747 
    748 static PyObject*
    749 profiler_clear(ProfilerObject *pObj, PyObject* noarg)
    750 {
    751     clearEntries(pObj);
    752     Py_INCREF(Py_None);
    753     return Py_None;
    754 }
    755 
    756 static void
    757 profiler_dealloc(ProfilerObject *op)
    758 {
    759     if (op->flags & POF_ENABLED)
    760         PyEval_SetProfile(NULL, NULL);
    761     flush_unmatched(op);
    762     clearEntries(op);
    763     Py_XDECREF(op->externalTimer);
    764     Py_TYPE(op)->tp_free(op);
    765 }
    766 
    767 static int
    768 profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
    769 {
    770     PyObject *o;
    771     PyObject *timer = NULL;
    772     double timeunit = 0.0;
    773     int subcalls = 1;
    774 #ifdef PyTrace_C_CALL
    775     int builtins = 1;
    776 #else
    777     int builtins = 0;
    778 #endif
    779     static char *kwlist[] = {"timer", "timeunit",
    780                                    "subcalls", "builtins", 0};
    781 
    782     if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
    783                                      &timer, &timeunit,
    784                                      &subcalls, &builtins))
    785         return -1;
    786 
    787     if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
    788         return -1;
    789     o = pObj->externalTimer;
    790     pObj->externalTimer = timer;
    791     Py_XINCREF(timer);
    792     Py_XDECREF(o);
    793     pObj->externalTimerUnit = timeunit;
    794     return 0;
    795 }
    796 
    797 static PyMethodDef profiler_methods[] = {
    798     {"getstats",    (PyCFunction)profiler_getstats,
    799                     METH_NOARGS,                        getstats_doc},
    800     {"enable",          (PyCFunction)profiler_enable,
    801                     METH_VARARGS | METH_KEYWORDS,       enable_doc},
    802     {"disable",         (PyCFunction)profiler_disable,
    803                     METH_NOARGS,                        disable_doc},
    804     {"clear",           (PyCFunction)profiler_clear,
    805                     METH_NOARGS,                        clear_doc},
    806     {NULL, NULL}
    807 };
    808 
    809 PyDoc_STRVAR(profiler_doc, "\
    810 Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
    811 \n\
    812     Builds a profiler object using the specified timer function.\n\
    813     The default timer is a fast built-in one based on real time.\n\
    814     For custom timer functions returning integers, time_unit can\n\
    815     be a float specifying a scale (i.e. how long each integer unit\n\
    816     is, in seconds).\n\
    817 ");
    818 
    819 statichere PyTypeObject PyProfiler_Type = {
    820     PyObject_HEAD_INIT(NULL)
    821     0,                                      /* ob_size */
    822     "_lsprof.Profiler",                     /* tp_name */
    823     sizeof(ProfilerObject),                 /* tp_basicsize */
    824     0,                                      /* tp_itemsize */
    825     (destructor)profiler_dealloc,           /* tp_dealloc */
    826     0,                                      /* tp_print */
    827     0,                                      /* tp_getattr */
    828     0,                                      /* tp_setattr */
    829     0,                                      /* tp_compare */
    830     0,                                      /* tp_repr */
    831     0,                                      /* tp_as_number */
    832     0,                                      /* tp_as_sequence */
    833     0,                                      /* tp_as_mapping */
    834     0,                                      /* tp_hash */
    835     0,                                      /* tp_call */
    836     0,                                      /* tp_str */
    837     0,                                      /* tp_getattro */
    838     0,                                      /* tp_setattro */
    839     0,                                      /* tp_as_buffer */
    840     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    841     profiler_doc,                           /* tp_doc */
    842     0,                                      /* tp_traverse */
    843     0,                                      /* tp_clear */
    844     0,                                      /* tp_richcompare */
    845     0,                                      /* tp_weaklistoffset */
    846     0,                                      /* tp_iter */
    847     0,                                      /* tp_iternext */
    848     profiler_methods,                       /* tp_methods */
    849     0,                                      /* tp_members */
    850     0,                                      /* tp_getset */
    851     0,                                      /* tp_base */
    852     0,                                      /* tp_dict */
    853     0,                                      /* tp_descr_get */
    854     0,                                      /* tp_descr_set */
    855     0,                                      /* tp_dictoffset */
    856     (initproc)profiler_init,                /* tp_init */
    857     PyType_GenericAlloc,                    /* tp_alloc */
    858     PyType_GenericNew,                      /* tp_new */
    859     PyObject_Del,                           /* tp_free */
    860 };
    861 
    862 static PyMethodDef moduleMethods[] = {
    863     {NULL, NULL}
    864 };
    865 
    866 PyMODINIT_FUNC
    867 init_lsprof(void)
    868 {
    869     PyObject *module, *d;
    870     module = Py_InitModule3("_lsprof", moduleMethods, "Fast profiler");
    871     if (module == NULL)
    872         return;
    873     d = PyModule_GetDict(module);
    874     if (PyType_Ready(&PyProfiler_Type) < 0)
    875         return;
    876     PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
    877 
    878     if (!initialized) {
    879         PyStructSequence_InitType(&StatsEntryType,
    880                                   &profiler_entry_desc);
    881         PyStructSequence_InitType(&StatsSubEntryType,
    882                                   &profiler_subentry_desc);
    883     }
    884     Py_INCREF((PyObject*) &StatsEntryType);
    885     Py_INCREF((PyObject*) &StatsSubEntryType);
    886     PyModule_AddObject(module, "profiler_entry",
    887                        (PyObject*) &StatsEntryType);
    888     PyModule_AddObject(module, "profiler_subentry",
    889                        (PyObject*) &StatsSubEntryType);
    890     empty_tuple = PyTuple_New(0);
    891     initialized = 1;
    892 }
    893