/Modules/_lsprof.c
http://unladen-swallow.googlecode.com/ · C · 905 lines · 773 code · 85 blank · 47 comment · 119 complexity · 7b4fab24e75dfcf80aa92a450d9cb354 MD5 · raw file
- #include "Python.h"
- #include "compile.h"
- #include "frameobject.h"
- #include "structseq.h"
- #include "rotatingtree.h"
- #if !defined(HAVE_LONG_LONG)
- #error "This module requires long longs!"
- #endif
- /*** Selection of a high-precision timer ***/
- #ifdef MS_WINDOWS
- #include <windows.h>
- static PY_LONG_LONG
- hpTimer(void)
- {
- LARGE_INTEGER li;
- QueryPerformanceCounter(&li);
- return li.QuadPart;
- }
- static double
- hpTimerUnit(void)
- {
- LARGE_INTEGER li;
- if (QueryPerformanceFrequency(&li))
- return 1.0 / li.QuadPart;
- else
- return 0.000001; /* unlikely */
- }
- #else /* !MS_WINDOWS */
- #ifndef HAVE_GETTIMEOFDAY
- #error "This module requires gettimeofday() on non-Windows platforms!"
- #endif
- #if (defined(PYOS_OS2) && defined(PYCC_GCC))
- #include <sys/time.h>
- #else
- #include <sys/resource.h>
- #include <sys/times.h>
- #endif
- static PY_LONG_LONG
- hpTimer(void)
- {
- struct timeval tv;
- PY_LONG_LONG ret;
- #ifdef GETTIMEOFDAY_NO_TZ
- gettimeofday(&tv);
- #else
- gettimeofday(&tv, (struct timezone *)NULL);
- #endif
- ret = tv.tv_sec;
- ret = ret * 1000000 + tv.tv_usec;
- return ret;
- }
- static double
- hpTimerUnit(void)
- {
- return 0.000001;
- }
- #endif /* MS_WINDOWS */
- /************************************************************/
- /* Written by Brett Rosen and Ted Czotter */
- struct _ProfilerEntry;
- /* represents a function called from another function */
- typedef struct _ProfilerSubEntry {
- rotating_node_t header;
- PY_LONG_LONG tt;
- PY_LONG_LONG it;
- long callcount;
- long recursivecallcount;
- long recursionLevel;
- } ProfilerSubEntry;
- /* represents a function or user defined block */
- typedef struct _ProfilerEntry {
- rotating_node_t header;
- PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
- PY_LONG_LONG tt; /* total time in this entry */
- PY_LONG_LONG it; /* inline time in this entry (not in subcalls) */
- long callcount; /* how many times this was called */
- long recursivecallcount; /* how many times called recursively */
- long recursionLevel;
- rotating_node_t *calls;
- } ProfilerEntry;
- typedef struct _ProfilerContext {
- PY_LONG_LONG t0;
- PY_LONG_LONG subt;
- struct _ProfilerContext *previous;
- ProfilerEntry *ctxEntry;
- } ProfilerContext;
- typedef struct {
- PyObject_HEAD
- rotating_node_t *profilerEntries;
- ProfilerContext *currentProfilerContext;
- ProfilerContext *freelistProfilerContext;
- int flags;
- PyObject *externalTimer;
- double externalTimerUnit;
- } ProfilerObject;
- #define POF_ENABLED 0x001
- #define POF_SUBCALLS 0x002
- #define POF_BUILTINS 0x004
- #define POF_NOMEMORY 0x100
- staticforward PyTypeObject PyProfiler_Type;
- #define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
- #define PyProfiler_CheckExact(op) (Py_TYPE(op) == &PyProfiler_Type)
- /*** External Timers ***/
- #define DOUBLE_TIMER_PRECISION 4294967296.0
- static PyObject *empty_tuple;
- static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj)
- {
- PY_LONG_LONG result;
- PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL);
- if (o == NULL) {
- PyErr_WriteUnraisable(pObj->externalTimer);
- return 0;
- }
- if (pObj->externalTimerUnit > 0.0) {
- /* interpret the result as an integer that will be scaled
- in profiler_getstats() */
- result = PyLong_AsLongLong(o);
- }
- else {
- /* interpret the result as a double measured in seconds.
- As the profiler works with PY_LONG_LONG internally
- we convert it to a large integer */
- double val = PyFloat_AsDouble(o);
- /* error handling delayed to the code below */
- result = (PY_LONG_LONG) (val * DOUBLE_TIMER_PRECISION);
- }
- Py_DECREF(o);
- if (PyErr_Occurred()) {
- PyErr_WriteUnraisable(pObj->externalTimer);
- return 0;
- }
- return result;
- }
- #define CALL_TIMER(pObj) ((pObj)->externalTimer ? \
- CallExternalTimer(pObj) : \
- hpTimer())
- /*** ProfilerObject ***/
- static PyObject *
- normalizeUserObj(PyObject *obj)
- {
- /* Replace built-in function objects with a descriptive string
- because of built-in methods -- keeping a reference to
- __self__ is probably not a good idea. */
- PyCFunctionObject *fn = (PyCFunctionObject *)obj;
- if (PyCFunction_Check(obj) && fn->m_self == NULL) {
- /* built-in function: look up the module name */
- PyObject *mod = fn->m_module;
- char *modname;
- if (mod && PyString_Check(mod)) {
- modname = PyString_AS_STRING(mod);
- }
- else if (mod && PyModule_Check(mod)) {
- modname = PyModule_GetName(mod);
- if (modname == NULL) {
- PyErr_Clear();
- modname = "__builtin__";
- }
- }
- else {
- modname = "__builtin__";
- }
- if (strcmp(modname, "__builtin__") != 0)
- return PyString_FromFormat("<%s.%s>",
- modname,
- fn->m_ml->ml_name);
- else
- return PyString_FromFormat("<%s>",
- fn->m_ml->ml_name);
- }
- else if (PyCFunction_Check(obj) || PyMethodDescr_Check(obj)) {
- /* built-in method: try to return
- repr(getattr(type(__self__), __name__))
- */
- PyTypeObject *type;
- const char *name;
- PyObject *name_obj;
- if (PyCFunction_Check(obj)) {
- type = Py_TYPE(fn->m_self);
- name = fn->m_ml->ml_name;
- }
- else {
- PyMethodDescrObject *descr = (PyMethodDescrObject *)obj;
- type = descr->d_type;
- name = descr->d_method->ml_name;
- }
- name_obj = PyString_FromString(name);
- if (name_obj != NULL) {
- PyObject *mo = _PyType_Lookup(type, name_obj);
- Py_XINCREF(mo);
- Py_DECREF(name_obj);
- if (mo != NULL) {
- PyObject *res = PyObject_Repr(mo);
- Py_DECREF(mo);
- if (res != NULL)
- return res;
- }
- }
- PyErr_Clear();
- return PyString_FromFormat("<built-in method %s>", name);
- }
- else {
- Py_INCREF(obj);
- return obj;
- }
- }
- static ProfilerEntry*
- newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
- {
- ProfilerEntry *self;
- self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry));
- if (self == NULL) {
- pObj->flags |= POF_NOMEMORY;
- return NULL;
- }
- userObj = normalizeUserObj(userObj);
- if (userObj == NULL) {
- PyErr_Clear();
- free(self);
- pObj->flags |= POF_NOMEMORY;
- return NULL;
- }
- self->header.key = key;
- self->userObj = userObj;
- self->tt = 0;
- self->it = 0;
- self->callcount = 0;
- self->recursivecallcount = 0;
- self->recursionLevel = 0;
- self->calls = EMPTY_ROTATING_TREE;
- RotatingTree_Add(&pObj->profilerEntries, &self->header);
- return self;
- }
- static ProfilerEntry*
- getEntry(ProfilerObject *pObj, void *key)
- {
- return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
- }
- static ProfilerSubEntry *
- getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
- {
- return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
- (void *)entry);
- }
- static ProfilerSubEntry *
- newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
- {
- ProfilerSubEntry *self;
- self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry));
- if (self == NULL) {
- pObj->flags |= POF_NOMEMORY;
- return NULL;
- }
- self->header.key = (void *)entry;
- self->tt = 0;
- self->it = 0;
- self->callcount = 0;
- self->recursivecallcount = 0;
- self->recursionLevel = 0;
- RotatingTree_Add(&caller->calls, &self->header);
- return self;
- }
- static int freeSubEntry(rotating_node_t *header, void *arg)
- {
- ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
- free(subentry);
- return 0;
- }
- static int freeEntry(rotating_node_t *header, void *arg)
- {
- ProfilerEntry *entry = (ProfilerEntry*) header;
- RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
- Py_DECREF(entry->userObj);
- free(entry);
- return 0;
- }
- static void clearEntries(ProfilerObject *pObj)
- {
- RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
- pObj->profilerEntries = EMPTY_ROTATING_TREE;
- /* release the memory hold by the free list of ProfilerContexts */
- while (pObj->freelistProfilerContext) {
- ProfilerContext *c = pObj->freelistProfilerContext;
- pObj->freelistProfilerContext = c->previous;
- free(c);
- }
- }
- static void
- initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
- {
- self->ctxEntry = entry;
- self->subt = 0;
- self->previous = pObj->currentProfilerContext;
- pObj->currentProfilerContext = self;
- ++entry->recursionLevel;
- if ((pObj->flags & POF_SUBCALLS) && self->previous) {
- /* find or create an entry for me in my caller's entry */
- ProfilerEntry *caller = self->previous->ctxEntry;
- ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
- if (subentry == NULL)
- subentry = newSubEntry(pObj, caller, entry);
- if (subentry)
- ++subentry->recursionLevel;
- }
- self->t0 = CALL_TIMER(pObj);
- }
- static void
- Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
- {
- PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0;
- PY_LONG_LONG it = tt - self->subt;
- if (self->previous)
- self->previous->subt += tt;
- pObj->currentProfilerContext = self->previous;
- if (--entry->recursionLevel == 0)
- entry->tt += tt;
- else
- ++entry->recursivecallcount;
- entry->it += it;
- entry->callcount++;
- if ((pObj->flags & POF_SUBCALLS) && self->previous) {
- /* find or create an entry for me in my caller's entry */
- ProfilerEntry *caller = self->previous->ctxEntry;
- ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
- if (subentry) {
- if (--subentry->recursionLevel == 0)
- subentry->tt += tt;
- else
- ++subentry->recursivecallcount;
- subentry->it += it;
- ++subentry->callcount;
- }
- }
- }
- static void
- ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
- {
- /* entering a call to the function identified by 'key'
- (which can be a PyCodeObject or a PyMethodDef pointer) */
- ProfilerObject *pObj = (ProfilerObject*)self;
- ProfilerEntry *profEntry;
- ProfilerContext *pContext;
- /* In the case of entering a generator expression frame via a
- * throw (gen_send_ex(.., 1)), we may already have an
- * Exception set here. We must not mess around with this
- * exception, and some of the code under here assumes that
- * PyErr_* is its own to mess around with, so we have to
- * save and restore any current exception. */
- PyObject *last_type, *last_value, *last_tb;
- PyErr_Fetch(&last_type, &last_value, &last_tb);
- profEntry = getEntry(pObj, key);
- if (profEntry == NULL) {
- profEntry = newProfilerEntry(pObj, key, userObj);
- if (profEntry == NULL)
- goto restorePyerr;
- }
- /* grab a ProfilerContext out of the free list */
- pContext = pObj->freelistProfilerContext;
- if (pContext) {
- pObj->freelistProfilerContext = pContext->previous;
- }
- else {
- /* free list exhausted, allocate a new one */
- pContext = (ProfilerContext*)
- malloc(sizeof(ProfilerContext));
- if (pContext == NULL) {
- pObj->flags |= POF_NOMEMORY;
- goto restorePyerr;
- }
- }
- initContext(pObj, pContext, profEntry);
- restorePyerr:
- PyErr_Restore(last_type, last_value, last_tb);
- }
- static void
- ptrace_leave_call(PyObject *self, void *key)
- {
- /* leaving a call to the function identified by 'key' */
- ProfilerObject *pObj = (ProfilerObject*)self;
- ProfilerEntry *profEntry;
- ProfilerContext *pContext;
- pContext = pObj->currentProfilerContext;
- if (pContext == NULL)
- return;
- profEntry = getEntry(pObj, key);
- if (profEntry) {
- Stop(pObj, pContext, profEntry);
- }
- else {
- pObj->currentProfilerContext = pContext->previous;
- }
- /* put pContext into the free list */
- pContext->previous = pObj->freelistProfilerContext;
- pObj->freelistProfilerContext = pContext;
- }
- static int
- profiler_callback(PyObject *self, PyFrameObject *frame, int what,
- PyObject *arg)
- {
- switch (what) {
- /* the 'frame' of a called function is about to start its execution */
- case PyTrace_CALL:
- ptrace_enter_call(self, (void *)frame->f_code,
- (PyObject *)frame->f_code);
- break;
- /* the 'frame' of a called function is about to finish
- (either normally or with an exception) */
- case PyTrace_RETURN:
- ptrace_leave_call(self, (void *)frame->f_code);
- break;
- /* case PyTrace_EXCEPTION:
- If the exception results in the function exiting, a
- PyTrace_RETURN event will be generated, so we don't need to
- handle it. */
- #ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */
- /* the Python function 'frame' is issuing a call to the built-in
- function 'arg' */
- case PyTrace_C_CALL:
- if (((ProfilerObject *)self)->flags & POF_BUILTINS) {
- PyMethodDef *ml = NULL;
- if (PyCFunction_Check(arg)) {
- ml = ((PyCFunctionObject *)arg)->m_ml;
- }
- else if (PyMethodDescr_Check(arg)) {
- ml = ((PyMethodDescrObject*)arg)->d_method;
- }
- ptrace_enter_call(self, ml, arg);
- }
- break;
- /* the call to the built-in function 'arg' is returning into its
- caller 'frame' */
- case PyTrace_C_RETURN: /* ...normally */
- case PyTrace_C_EXCEPTION: /* ...with an exception set */
- if (((ProfilerObject *)self)->flags & POF_BUILTINS) {
- PyMethodDef *ml = NULL;
- if (PyCFunction_Check(arg)) {
- ml = ((PyCFunctionObject *)arg)->m_ml;
- }
- else if (PyMethodDescr_Check(arg)) {
- ml = ((PyMethodDescrObject*)arg)->d_method;
- }
- ptrace_leave_call(self, ml);
- }
- break;
- #endif
- default:
- break;
- }
- return 0;
- }
- static int
- pending_exception(ProfilerObject *pObj)
- {
- if (pObj->flags & POF_NOMEMORY) {
- pObj->flags -= POF_NOMEMORY;
- PyErr_SetString(PyExc_MemoryError,
- "memory was exhausted while profiling");
- return -1;
- }
- return 0;
- }
- /************************************************************/
- static PyStructSequence_Field profiler_entry_fields[] = {
- {"code", "code object or built-in function name"},
- {"callcount", "how many times this was called"},
- {"reccallcount", "how many times called recursively"},
- {"totaltime", "total time in this entry"},
- {"inlinetime", "inline time in this entry (not in subcalls)"},
- {"calls", "details of the calls"},
- {0}
- };
- static PyStructSequence_Field profiler_subentry_fields[] = {
- {"code", "called code object or built-in function name"},
- {"callcount", "how many times this is called"},
- {"reccallcount", "how many times this is called recursively"},
- {"totaltime", "total time spent in this call"},
- {"inlinetime", "inline time (not in further subcalls)"},
- {0}
- };
- static PyStructSequence_Desc profiler_entry_desc = {
- "_lsprof.profiler_entry", /* name */
- NULL, /* doc */
- profiler_entry_fields,
- 6
- };
- static PyStructSequence_Desc profiler_subentry_desc = {
- "_lsprof.profiler_subentry", /* name */
- NULL, /* doc */
- profiler_subentry_fields,
- 5
- };
- static int initialized;
- static PyTypeObject StatsEntryType;
- static PyTypeObject StatsSubEntryType;
- typedef struct {
- PyObject *list;
- PyObject *sublist;
- double factor;
- } statscollector_t;
- static int statsForSubEntry(rotating_node_t *node, void *arg)
- {
- ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
- statscollector_t *collect = (statscollector_t*) arg;
- ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
- int err;
- PyObject *sinfo;
- sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
- "((Olldd))",
- entry->userObj,
- sentry->callcount,
- sentry->recursivecallcount,
- collect->factor * sentry->tt,
- collect->factor * sentry->it);
- if (sinfo == NULL)
- return -1;
- err = PyList_Append(collect->sublist, sinfo);
- Py_DECREF(sinfo);
- return err;
- }
- static int statsForEntry(rotating_node_t *node, void *arg)
- {
- ProfilerEntry *entry = (ProfilerEntry*) node;
- statscollector_t *collect = (statscollector_t*) arg;
- PyObject *info;
- int err;
- if (entry->callcount == 0)
- return 0; /* skip */
- if (entry->calls != EMPTY_ROTATING_TREE) {
- collect->sublist = PyList_New(0);
- if (collect->sublist == NULL)
- return -1;
- if (RotatingTree_Enum(entry->calls,
- statsForSubEntry, collect) != 0) {
- Py_DECREF(collect->sublist);
- return -1;
- }
- }
- else {
- Py_INCREF(Py_None);
- collect->sublist = Py_None;
- }
- info = PyObject_CallFunction((PyObject*) &StatsEntryType,
- "((OllddO))",
- entry->userObj,
- entry->callcount,
- entry->recursivecallcount,
- collect->factor * entry->tt,
- collect->factor * entry->it,
- collect->sublist);
- Py_DECREF(collect->sublist);
- if (info == NULL)
- return -1;
- err = PyList_Append(collect->list, info);
- Py_DECREF(info);
- return err;
- }
- PyDoc_STRVAR(getstats_doc, "\
- getstats() -> list of profiler_entry objects\n\
- \n\
- Return all information collected by the profiler.\n\
- Each profiler_entry is a tuple-like object with the\n\
- following attributes:\n\
- \n\
- code code object\n\
- callcount how many times this was called\n\
- reccallcount how many times called recursively\n\
- totaltime total time in this entry\n\
- inlinetime inline time in this entry (not in subcalls)\n\
- calls details of the calls\n\
- \n\
- The calls attribute is either None or a list of\n\
- profiler_subentry objects:\n\
- \n\
- code called code object\n\
- callcount how many times this is called\n\
- reccallcount how many times this is called recursively\n\
- totaltime total time spent in this call\n\
- inlinetime inline time (not in further subcalls)\n\
- ");
- static PyObject*
- profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
- {
- statscollector_t collect;
- if (pending_exception(pObj))
- return NULL;
- if (!pObj->externalTimer)
- collect.factor = hpTimerUnit();
- else if (pObj->externalTimerUnit > 0.0)
- collect.factor = pObj->externalTimerUnit;
- else
- collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
- collect.list = PyList_New(0);
- if (collect.list == NULL)
- return NULL;
- if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
- != 0) {
- Py_DECREF(collect.list);
- return NULL;
- }
- return collect.list;
- }
- static int
- setSubcalls(ProfilerObject *pObj, int nvalue)
- {
- if (nvalue == 0)
- pObj->flags &= ~POF_SUBCALLS;
- else if (nvalue > 0)
- pObj->flags |= POF_SUBCALLS;
- return 0;
- }
- static int
- setBuiltins(ProfilerObject *pObj, int nvalue)
- {
- if (nvalue == 0)
- pObj->flags &= ~POF_BUILTINS;
- else if (nvalue > 0) {
- #ifndef PyTrace_C_CALL
- PyErr_SetString(PyExc_ValueError,
- "builtins=True requires Python >= 2.4");
- return -1;
- #else
- pObj->flags |= POF_BUILTINS;
- #endif
- }
- return 0;
- }
- PyDoc_STRVAR(enable_doc, "\
- enable(subcalls=True, builtins=True)\n\
- \n\
- Start collecting profiling information.\n\
- If 'subcalls' is True, also records for each function\n\
- statistics separated according to its current caller.\n\
- If 'builtins' is True, records the time spent in\n\
- built-in functions separately from their caller.\n\
- ");
- static PyObject*
- profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
- {
- int subcalls = -1;
- int builtins = -1;
- static char *kwlist[] = {"subcalls", "builtins", 0};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
- kwlist, &subcalls, &builtins))
- return NULL;
- if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
- return NULL;
- PyEval_SetProfile(profiler_callback, (PyObject*)self);
- self->flags |= POF_ENABLED;
- Py_INCREF(Py_None);
- return Py_None;
- }
- static void
- flush_unmatched(ProfilerObject *pObj)
- {
- while (pObj->currentProfilerContext) {
- ProfilerContext *pContext = pObj->currentProfilerContext;
- ProfilerEntry *profEntry= pContext->ctxEntry;
- if (profEntry)
- Stop(pObj, pContext, profEntry);
- else
- pObj->currentProfilerContext = pContext->previous;
- if (pContext)
- free(pContext);
- }
- }
- PyDoc_STRVAR(disable_doc, "\
- disable()\n\
- \n\
- Stop collecting profiling information.\n\
- ");
- static PyObject*
- profiler_disable(ProfilerObject *self, PyObject* noarg)
- {
- self->flags &= ~POF_ENABLED;
- PyEval_SetProfile(NULL, NULL);
- flush_unmatched(self);
- if (pending_exception(self))
- return NULL;
- Py_INCREF(Py_None);
- return Py_None;
- }
- PyDoc_STRVAR(clear_doc, "\
- clear()\n\
- \n\
- Clear all profiling information collected so far.\n\
- ");
- static PyObject*
- profiler_clear(ProfilerObject *pObj, PyObject* noarg)
- {
- clearEntries(pObj);
- Py_INCREF(Py_None);
- return Py_None;
- }
- static void
- profiler_dealloc(ProfilerObject *op)
- {
- if (op->flags & POF_ENABLED)
- PyEval_SetProfile(NULL, NULL);
- flush_unmatched(op);
- clearEntries(op);
- Py_XDECREF(op->externalTimer);
- Py_TYPE(op)->tp_free(op);
- }
- static int
- profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
- {
- PyObject *o;
- PyObject *timer = NULL;
- double timeunit = 0.0;
- int subcalls = 1;
- #ifdef PyTrace_C_CALL
- int builtins = 1;
- #else
- int builtins = 0;
- #endif
- static char *kwlist[] = {"timer", "timeunit",
- "subcalls", "builtins", 0};
- if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
- &timer, &timeunit,
- &subcalls, &builtins))
- return -1;
- if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
- return -1;
- o = pObj->externalTimer;
- pObj->externalTimer = timer;
- Py_XINCREF(timer);
- Py_XDECREF(o);
- pObj->externalTimerUnit = timeunit;
- return 0;
- }
- static PyMethodDef profiler_methods[] = {
- {"getstats", (PyCFunction)profiler_getstats,
- METH_NOARGS, getstats_doc},
- {"enable", (PyCFunction)profiler_enable,
- METH_VARARGS | METH_KEYWORDS, enable_doc},
- {"disable", (PyCFunction)profiler_disable,
- METH_NOARGS, disable_doc},
- {"clear", (PyCFunction)profiler_clear,
- METH_NOARGS, clear_doc},
- {NULL, NULL}
- };
- PyDoc_STRVAR(profiler_doc, "\
- Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
- \n\
- Builds a profiler object using the specified timer function.\n\
- The default timer is a fast built-in one based on real time.\n\
- For custom timer functions returning integers, time_unit can\n\
- be a float specifying a scale (i.e. how long each integer unit\n\
- is, in seconds).\n\
- ");
- statichere PyTypeObject PyProfiler_Type = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "_lsprof.Profiler", /* tp_name */
- sizeof(ProfilerObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)profiler_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- profiler_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- profiler_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)profiler_init, /* tp_init */
- PyType_GenericAlloc, /* tp_alloc */
- PyType_GenericNew, /* tp_new */
- PyObject_Del, /* tp_free */
- };
- static PyMethodDef moduleMethods[] = {
- {NULL, NULL}
- };
- PyMODINIT_FUNC
- init_lsprof(void)
- {
- PyObject *module, *d;
- module = Py_InitModule3("_lsprof", moduleMethods, "Fast profiler");
- if (module == NULL)
- return;
- d = PyModule_GetDict(module);
- if (PyType_Ready(&PyProfiler_Type) < 0)
- return;
- PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
- if (!initialized) {
- PyStructSequence_InitType(&StatsEntryType,
- &profiler_entry_desc);
- PyStructSequence_InitType(&StatsSubEntryType,
- &profiler_subentry_desc);
- }
- Py_INCREF((PyObject*) &StatsEntryType);
- Py_INCREF((PyObject*) &StatsSubEntryType);
- PyModule_AddObject(module, "profiler_entry",
- (PyObject*) &StatsEntryType);
- PyModule_AddObject(module, "profiler_subentry",
- (PyObject*) &StatsSubEntryType);
- empty_tuple = PyTuple_New(0);
- initialized = 1;
- }