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