Minor edits
[pytest.git] / Modules / _lsprof.c
blobd35c894c5aae69cb59db0fdc15c5c20d42888c71
1 #include "Python.h"
2 #include "compile.h"
3 #include "frameobject.h"
4 #include "structseq.h"
5 #include "rotatingtree.h"
7 #if !defined(HAVE_LONG_LONG)
8 #error "This module requires long longs!"
9 #endif
11 /*** Selection of a high-precision timer ***/
13 #ifdef MS_WINDOWS
15 #include <windows.h>
17 static PY_LONG_LONG
18 hpTimer(void)
20 LARGE_INTEGER li;
21 QueryPerformanceCounter(&li);
22 return li.QuadPart;
25 static double
26 hpTimerUnit(void)
28 LARGE_INTEGER li;
29 if (QueryPerformanceFrequency(&li))
30 return 1.0 / li.QuadPart;
31 else
32 return 0.000001; /* unlikely */
35 #else /* !MS_WINDOWS */
37 #ifndef HAVE_GETTIMEOFDAY
38 #error "This module requires gettimeofday() on non-Windows platforms!"
39 #endif
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
48 static PY_LONG_LONG
49 hpTimer(void)
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;
63 static double
64 hpTimerUnit(void)
66 return 0.000001;
69 #endif /* MS_WINDOWS */
71 /************************************************************/
72 /* Written by Brett Rosen and Ted Czotter */
74 struct _ProfilerEntry;
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;
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;
98 typedef struct _ProfilerContext {
99 PY_LONG_LONG t0;
100 PY_LONG_LONG subt;
101 struct _ProfilerContext *previous;
102 ProfilerEntry *ctxEntry;
103 } ProfilerContext;
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;
115 #define POF_ENABLED 0x001
116 #define POF_SUBCALLS 0x002
117 #define POF_BUILTINS 0x004
118 #define POF_NOMEMORY 0x100
120 staticforward PyTypeObject PyProfiler_Type;
122 #define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
123 #define PyProfiler_CheckExact(op) ((op)->ob_type == &PyProfiler_Type)
125 /*** External Timers ***/
127 #define DOUBLE_TIMER_PRECISION 4294967296.0
128 static PyObject *empty_tuple;
130 static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj)
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;
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);
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);
151 Py_DECREF(o);
152 if (PyErr_Occurred()) {
153 PyErr_WriteUnraisable((PyObject *) pObj);
154 return 0;
156 return result;
159 #define CALL_TIMER(pObj) ((pObj)->externalTimer ? \
160 CallExternalTimer(pObj) : \
161 hpTimer())
163 /*** ProfilerObject ***/
165 static PyObject *
166 normalizeUserObj(PyObject *obj)
168 PyCFunctionObject *fn;
169 if (!PyCFunction_Check(obj)) {
170 Py_INCREF(obj);
171 return obj;
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;
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);
185 else if (mod && PyModule_Check(mod)) {
186 modname = PyModule_GetName(mod);
187 if (modname == NULL) {
188 PyErr_Clear();
189 modname = "__builtin__";
192 else {
193 modname = "__builtin__";
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);
203 else {
204 /* built-in method: try to return
205 repr(getattr(type(__self__), __name__))
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(self->ob_type, 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;
220 PyErr_Clear();
221 return PyString_FromFormat("<built-in method %s>",
222 fn->m_ml->ml_name);
226 static ProfilerEntry*
227 newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
229 ProfilerEntry *self;
230 self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry));
231 if (self == NULL) {
232 pObj->flags |= POF_NOMEMORY;
233 return NULL;
235 userObj = normalizeUserObj(userObj);
236 if (userObj == NULL) {
237 PyErr_Clear();
238 free(self);
239 pObj->flags |= POF_NOMEMORY;
240 return NULL;
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;
254 static ProfilerEntry*
255 getEntry(ProfilerObject *pObj, void *key)
257 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
260 static ProfilerSubEntry *
261 getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
263 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
264 (void *)entry);
267 static ProfilerSubEntry *
268 newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
270 ProfilerSubEntry *self;
271 self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry));
272 if (self == NULL) {
273 pObj->flags |= POF_NOMEMORY;
274 return NULL;
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;
286 static int freeSubEntry(rotating_node_t *header, void *arg)
288 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
289 free(subentry);
290 return 0;
293 static int freeEntry(rotating_node_t *header, void *arg)
295 ProfilerEntry *entry = (ProfilerEntry*) header;
296 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
297 Py_DECREF(entry->userObj);
298 free(entry);
299 return 0;
302 static void clearEntries(ProfilerObject *pObj)
304 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
305 pObj->profilerEntries = EMPTY_ROTATING_TREE;
306 /* release the memory hold by the free list of ProfilerContexts */
307 while (pObj->freelistProfilerContext) {
308 ProfilerContext *c = pObj->freelistProfilerContext;
309 pObj->freelistProfilerContext = c->previous;
310 free(c);
314 static void
315 initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
317 self->ctxEntry = entry;
318 self->subt = 0;
319 self->previous = pObj->currentProfilerContext;
320 pObj->currentProfilerContext = self;
321 ++entry->recursionLevel;
322 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
323 /* find or create an entry for me in my caller's entry */
324 ProfilerEntry *caller = self->previous->ctxEntry;
325 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
326 if (subentry == NULL)
327 subentry = newSubEntry(pObj, caller, entry);
328 if (subentry)
329 ++subentry->recursionLevel;
331 self->t0 = CALL_TIMER(pObj);
334 static void
335 Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
337 PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0;
338 PY_LONG_LONG it = tt - self->subt;
339 if (self->previous)
340 self->previous->subt += tt;
341 pObj->currentProfilerContext = self->previous;
342 if (--entry->recursionLevel == 0)
343 entry->tt += tt;
344 else
345 ++entry->recursivecallcount;
346 entry->it += it;
347 entry->callcount++;
348 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
349 /* find or create an entry for me in my caller's entry */
350 ProfilerEntry *caller = self->previous->ctxEntry;
351 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
352 if (subentry) {
353 if (--subentry->recursionLevel == 0)
354 subentry->tt += tt;
355 else
356 ++subentry->recursivecallcount;
357 subentry->it += it;
358 ++subentry->callcount;
363 static void
364 ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
366 /* entering a call to the function identified by 'key'
367 (which can be a PyCodeObject or a PyMethodDef pointer) */
368 ProfilerObject *pObj = (ProfilerObject*)self;
369 ProfilerEntry *profEntry;
370 ProfilerContext *pContext;
372 profEntry = getEntry(pObj, key);
373 if (profEntry == NULL) {
374 profEntry = newProfilerEntry(pObj, key, userObj);
375 if (profEntry == NULL)
376 return;
378 /* grab a ProfilerContext out of the free list */
379 pContext = pObj->freelistProfilerContext;
380 if (pContext) {
381 pObj->freelistProfilerContext = pContext->previous;
383 else {
384 /* free list exhausted, allocate a new one */
385 pContext = (ProfilerContext*)
386 malloc(sizeof(ProfilerContext));
387 if (pContext == NULL) {
388 pObj->flags |= POF_NOMEMORY;
389 return;
392 initContext(pObj, pContext, profEntry);
395 static void
396 ptrace_leave_call(PyObject *self, void *key)
398 /* leaving a call to the function identified by 'key' */
399 ProfilerObject *pObj = (ProfilerObject*)self;
400 ProfilerEntry *profEntry;
401 ProfilerContext *pContext;
403 pContext = pObj->currentProfilerContext;
404 if (pContext == NULL)
405 return;
406 profEntry = getEntry(pObj, key);
407 if (profEntry) {
408 Stop(pObj, pContext, profEntry);
410 else {
411 pObj->currentProfilerContext = pContext->previous;
413 /* put pContext into the free list */
414 pContext->previous = pObj->freelistProfilerContext;
415 pObj->freelistProfilerContext = pContext;
418 static int
419 profiler_callback(PyObject *self, PyFrameObject *frame, int what,
420 PyObject *arg)
422 switch (what) {
424 /* the 'frame' of a called function is about to start its execution */
425 case PyTrace_CALL:
426 ptrace_enter_call(self, (void *)frame->f_code,
427 (PyObject *)frame->f_code);
428 break;
430 /* the 'frame' of a called function is about to finish
431 (either normally or with an exception) */
432 case PyTrace_RETURN:
433 ptrace_leave_call(self, (void *)frame->f_code);
434 break;
436 /* case PyTrace_EXCEPTION:
437 If the exception results in the function exiting, a
438 PyTrace_RETURN event will be generated, so we don't need to
439 handle it. */
441 #ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */
442 /* the Python function 'frame' is issuing a call to the built-in
443 function 'arg' */
444 case PyTrace_C_CALL:
445 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
446 && PyCFunction_Check(arg)) {
447 ptrace_enter_call(self,
448 ((PyCFunctionObject *)arg)->m_ml,
449 arg);
451 break;
453 /* the call to the built-in function 'arg' is returning into its
454 caller 'frame' */
455 case PyTrace_C_RETURN: /* ...normally */
456 case PyTrace_C_EXCEPTION: /* ...with an exception set */
457 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
458 && PyCFunction_Check(arg)) {
459 ptrace_leave_call(self,
460 ((PyCFunctionObject *)arg)->m_ml);
462 break;
463 #endif
465 default:
466 break;
468 return 0;
471 static int
472 pending_exception(ProfilerObject *pObj)
474 if (pObj->flags & POF_NOMEMORY) {
475 pObj->flags -= POF_NOMEMORY;
476 PyErr_SetString(PyExc_MemoryError,
477 "memory was exhausted while profiling");
478 return -1;
480 return 0;
483 /************************************************************/
485 static PyStructSequence_Field profiler_entry_fields[] = {
486 {"code", "code object or built-in function name"},
487 {"callcount", "how many times this was called"},
488 {"reccallcount", "how many times called recursively"},
489 {"totaltime", "total time in this entry"},
490 {"inlinetime", "inline time in this entry (not in subcalls)"},
491 {"calls", "details of the calls"},
495 static PyStructSequence_Field profiler_subentry_fields[] = {
496 {"code", "called code object or built-in function name"},
497 {"callcount", "how many times this is called"},
498 {"reccallcount", "how many times this is called recursively"},
499 {"totaltime", "total time spent in this call"},
500 {"inlinetime", "inline time (not in further subcalls)"},
504 static PyStructSequence_Desc profiler_entry_desc = {
505 "_lsprof.profiler_entry", /* name */
506 NULL, /* doc */
507 profiler_entry_fields,
511 static PyStructSequence_Desc profiler_subentry_desc = {
512 "_lsprof.profiler_subentry", /* name */
513 NULL, /* doc */
514 profiler_subentry_fields,
518 static int initialized;
519 static PyTypeObject StatsEntryType;
520 static PyTypeObject StatsSubEntryType;
523 typedef struct {
524 PyObject *list;
525 PyObject *sublist;
526 double factor;
527 } statscollector_t;
529 static int statsForSubEntry(rotating_node_t *node, void *arg)
531 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
532 statscollector_t *collect = (statscollector_t*) arg;
533 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
534 int err;
535 PyObject *sinfo;
536 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
537 "((Olldd))",
538 entry->userObj,
539 sentry->callcount,
540 sentry->recursivecallcount,
541 collect->factor * sentry->tt,
542 collect->factor * sentry->it);
543 if (sinfo == NULL)
544 return -1;
545 err = PyList_Append(collect->sublist, sinfo);
546 Py_DECREF(sinfo);
547 return err;
550 static int statsForEntry(rotating_node_t *node, void *arg)
552 ProfilerEntry *entry = (ProfilerEntry*) node;
553 statscollector_t *collect = (statscollector_t*) arg;
554 PyObject *info;
555 int err;
556 if (entry->callcount == 0)
557 return 0; /* skip */
559 if (entry->calls != EMPTY_ROTATING_TREE) {
560 collect->sublist = PyList_New(0);
561 if (collect->sublist == NULL)
562 return -1;
563 if (RotatingTree_Enum(entry->calls,
564 statsForSubEntry, collect) != 0) {
565 Py_DECREF(collect->sublist);
566 return -1;
569 else {
570 Py_INCREF(Py_None);
571 collect->sublist = Py_None;
574 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
575 "((OllddO))",
576 entry->userObj,
577 entry->callcount,
578 entry->recursivecallcount,
579 collect->factor * entry->tt,
580 collect->factor * entry->it,
581 collect->sublist);
582 Py_DECREF(collect->sublist);
583 if (info == NULL)
584 return -1;
585 err = PyList_Append(collect->list, info);
586 Py_DECREF(info);
587 return err;
590 PyDoc_STRVAR(getstats_doc, "\
591 getstats() -> list of profiler_entry objects\n\
593 Return all information collected by the profiler.\n\
594 Each profiler_entry is a tuple-like object with the\n\
595 following attributes:\n\
597 code code object\n\
598 callcount how many times this was called\n\
599 reccallcount how many times called recursively\n\
600 totaltime total time in this entry\n\
601 inlinetime inline time in this entry (not in subcalls)\n\
602 calls details of the calls\n\
604 The calls attribute is either None or a list of\n\
605 profiler_subentry objects:\n\
607 code called code object\n\
608 callcount how many times this is called\n\
609 reccallcount how many times this is called recursively\n\
610 totaltime total time spent in this call\n\
611 inlinetime inline time (not in further subcalls)\n\
614 static PyObject*
615 profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
617 statscollector_t collect;
618 if (pending_exception(pObj))
619 return NULL;
620 if (!pObj->externalTimer)
621 collect.factor = hpTimerUnit();
622 else if (pObj->externalTimerUnit > 0.0)
623 collect.factor = pObj->externalTimerUnit;
624 else
625 collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
626 collect.list = PyList_New(0);
627 if (collect.list == NULL)
628 return NULL;
629 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
630 != 0) {
631 Py_DECREF(collect.list);
632 return NULL;
634 return collect.list;
637 static int
638 setSubcalls(ProfilerObject *pObj, int nvalue)
640 if (nvalue == 0)
641 pObj->flags &= ~POF_SUBCALLS;
642 else if (nvalue > 0)
643 pObj->flags |= POF_SUBCALLS;
644 return 0;
647 static int
648 setBuiltins(ProfilerObject *pObj, int nvalue)
650 if (nvalue == 0)
651 pObj->flags &= ~POF_BUILTINS;
652 else if (nvalue > 0) {
653 #ifndef PyTrace_C_CALL
654 PyErr_SetString(PyExc_ValueError,
655 "builtins=True requires Python >= 2.4");
656 return -1;
657 #else
658 pObj->flags |= POF_BUILTINS;
659 #endif
661 return 0;
664 PyDoc_STRVAR(enable_doc, "\
665 enable(subcalls=True, builtins=True)\n\
667 Start collecting profiling information.\n\
668 If 'subcalls' is True, also records for each function\n\
669 statistics separated according to its current caller.\n\
670 If 'builtins' is True, records the time spent in\n\
671 built-in functions separately from their caller.\n\
674 static PyObject*
675 profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
677 int subcalls = -1;
678 int builtins = -1;
679 static char *kwlist[] = {"subcalls", "builtins", 0};
680 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
681 kwlist, &subcalls, &builtins))
682 return NULL;
683 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
684 return NULL;
685 PyEval_SetProfile(profiler_callback, (PyObject*)self);
686 self->flags |= POF_ENABLED;
687 Py_INCREF(Py_None);
688 return Py_None;
691 static void
692 flush_unmatched(ProfilerObject *pObj)
694 while (pObj->currentProfilerContext) {
695 ProfilerContext *pContext = pObj->currentProfilerContext;
696 ProfilerEntry *profEntry= pContext->ctxEntry;
697 if (profEntry)
698 Stop(pObj, pContext, profEntry);
699 else
700 pObj->currentProfilerContext = pContext->previous;
701 if (pContext)
702 free(pContext);
707 PyDoc_STRVAR(disable_doc, "\
708 disable()\n\
710 Stop collecting profiling information.\n\
713 static PyObject*
714 profiler_disable(ProfilerObject *self, PyObject* noarg)
716 self->flags &= ~POF_ENABLED;
717 PyEval_SetProfile(NULL, NULL);
718 flush_unmatched(self);
719 if (pending_exception(self))
720 return NULL;
721 Py_INCREF(Py_None);
722 return Py_None;
725 PyDoc_STRVAR(clear_doc, "\
726 clear()\n\
728 Clear all profiling information collected so far.\n\
731 static PyObject*
732 profiler_clear(ProfilerObject *pObj, PyObject* noarg)
734 clearEntries(pObj);
735 Py_INCREF(Py_None);
736 return Py_None;
739 static void
740 profiler_dealloc(ProfilerObject *op)
742 if (op->flags & POF_ENABLED)
743 PyEval_SetProfile(NULL, NULL);
744 flush_unmatched(op);
745 clearEntries(op);
746 Py_XDECREF(op->externalTimer);
747 op->ob_type->tp_free(op);
750 static int
751 profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
753 PyObject *o;
754 PyObject *timer = NULL;
755 double timeunit = 0.0;
756 int subcalls = 1;
757 #ifdef PyTrace_C_CALL
758 int builtins = 1;
759 #else
760 int builtins = 0;
761 #endif
762 static char *kwlist[] = {"timer", "timeunit",
763 "subcalls", "builtins", 0};
765 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
766 &timer, &timeunit,
767 &subcalls, &builtins))
768 return -1;
770 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
771 return -1;
772 o = pObj->externalTimer;
773 pObj->externalTimer = timer;
774 Py_XINCREF(timer);
775 Py_XDECREF(o);
776 pObj->externalTimerUnit = timeunit;
777 return 0;
780 static PyMethodDef profiler_methods[] = {
781 {"getstats", (PyCFunction)profiler_getstats,
782 METH_NOARGS, getstats_doc},
783 {"enable", (PyCFunction)profiler_enable,
784 METH_VARARGS | METH_KEYWORDS, enable_doc},
785 {"disable", (PyCFunction)profiler_disable,
786 METH_NOARGS, disable_doc},
787 {"clear", (PyCFunction)profiler_clear,
788 METH_NOARGS, clear_doc},
789 {NULL, NULL}
792 PyDoc_STRVAR(profiler_doc, "\
793 Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
795 Builds a profiler object using the specified timer function.\n\
796 The default timer is a fast built-in one based on real time.\n\
797 For custom timer functions returning integers, time_unit can\n\
798 be a float specifying a scale (i.e. how long each integer unit\n\
799 is, in seconds).\n\
802 statichere PyTypeObject PyProfiler_Type = {
803 PyObject_HEAD_INIT(NULL)
804 0, /* ob_size */
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_compare */
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 */
845 static PyMethodDef moduleMethods[] = {
846 {NULL, NULL}
849 PyMODINIT_FUNC
850 init_lsprof(void)
852 PyObject *module, *d;
853 module = Py_InitModule3("_lsprof", moduleMethods, "Fast profiler");
854 if (module == NULL)
855 return;
856 d = PyModule_GetDict(module);
857 if (PyType_Ready(&PyProfiler_Type) < 0)
858 return;
859 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
861 if (!initialized) {
862 PyStructSequence_InitType(&StatsEntryType,
863 &profiler_entry_desc);
864 PyStructSequence_InitType(&StatsSubEntryType,
865 &profiler_subentry_desc);
867 Py_INCREF((PyObject*) &StatsEntryType);
868 Py_INCREF((PyObject*) &StatsSubEntryType);
869 PyModule_AddObject(module, "profiler_entry",
870 (PyObject*) &StatsEntryType);
871 PyModule_AddObject(module, "profiler_subentry",
872 (PyObject*) &StatsSubEntryType);
873 empty_tuple = PyTuple_New(0);
874 initialized = 1;