blob: dd74a436bbf334a308512ffba808e0d062b2a1a2 [file] [log] [blame]
Armin Rigoa871ef22006-02-08 12:53:56 +00001#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
17static PY_LONG_LONG
18hpTimer(void)
19{
20 LARGE_INTEGER li;
21 QueryPerformanceCounter(&li);
22 return li.QuadPart;
23}
24
25static double
26hpTimerUnit(void)
27{
28 LARGE_INTEGER li;
29 if (QueryPerformanceFrequency(&li))
Armin Rigo2bc23f52006-02-10 13:19:53 +000030 return 1.0 / li.QuadPart;
Armin Rigoa871ef22006-02-08 12:53:56 +000031 else
Armin Rigo2bc23f52006-02-10 13:19:53 +000032 return 0.000001; /* unlikely */
Armin Rigoa871ef22006-02-08 12:53:56 +000033}
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
48static PY_LONG_LONG
49hpTimer(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
63static double
64hpTimerUnit(void)
65{
Armin Rigo2bc23f52006-02-10 13:19:53 +000066 return 0.000001;
Armin Rigoa871ef22006-02-08 12:53:56 +000067}
68
69#endif /* MS_WINDOWS */
70
71/************************************************************/
72/* Written by Brett Rosen and Ted Czotter */
73
74struct _ProfilerEntry;
75
76/* represents a function called from another function */
77typedef 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 */
87typedef 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
98typedef struct _ProfilerContext {
99 PY_LONG_LONG t0;
100 PY_LONG_LONG subt;
101 struct _ProfilerContext *previous;
102 ProfilerEntry *ctxEntry;
103} ProfilerContext;
104
105typedef 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
Neal Norwitz227b5332006-03-22 09:28:35 +0000120static PyTypeObject PyProfiler_Type;
Armin Rigoa871ef22006-02-08 12:53:56 +0000121
122#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000123#define PyProfiler_CheckExact(op) (Py_Type(op) == &PyProfiler_Type)
Armin Rigoa871ef22006-02-08 12:53:56 +0000124
125/*** External Timers ***/
126
127#define DOUBLE_TIMER_PRECISION 4294967296.0
128static PyObject *empty_tuple;
129
130static 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((PyObject *) pObj);
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
165static PyObject *
166normalizeUserObj(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;
Neal Norwitz1e93f2b2007-08-27 02:10:06 +0000181 const char *modname;
Armin Rigoa871ef22006-02-08 12:53:56 +0000182 if (mod && PyString_Check(mod)) {
183 modname = PyString_AS_STRING(mod);
184 }
Guido van Rossum1c5a98a2007-07-16 23:36:05 +0000185 else if (mod && PyUnicode_Check(mod)) {
186 modname = PyUnicode_AsString(mod);
187 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000188 else if (mod && PyModule_Check(mod)) {
189 modname = PyModule_GetName(mod);
190 if (modname == NULL) {
191 PyErr_Clear();
192 modname = "__builtin__";
193 }
194 }
195 else {
196 modname = "__builtin__";
197 }
198 if (strcmp(modname, "__builtin__") != 0)
Neal Norwitze1188622007-08-26 02:22:30 +0000199 return PyUnicode_FromFormat("<%s.%s>",
200 modname,
201 fn->m_ml->ml_name);
Armin Rigoa871ef22006-02-08 12:53:56 +0000202 else
Neal Norwitze1188622007-08-26 02:22:30 +0000203 return PyUnicode_FromFormat("<%s>",
204 fn->m_ml->ml_name);
Armin Rigoa871ef22006-02-08 12:53:56 +0000205 }
206 else {
207 /* built-in method: try to return
208 repr(getattr(type(__self__), __name__))
209 */
210 PyObject *self = fn->m_self;
Neal Norwitze1188622007-08-26 02:22:30 +0000211 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
Armin Rigoa871ef22006-02-08 12:53:56 +0000212 if (name != NULL) {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000213 PyObject *mo = _PyType_Lookup(Py_Type(self), name);
Armin Rigoa871ef22006-02-08 12:53:56 +0000214 Py_XINCREF(mo);
215 Py_DECREF(name);
216 if (mo != NULL) {
217 PyObject *res = PyObject_Repr(mo);
218 Py_DECREF(mo);
219 if (res != NULL)
220 return res;
221 }
222 }
223 PyErr_Clear();
Neal Norwitze1188622007-08-26 02:22:30 +0000224 return PyUnicode_FromFormat("<built-in method %s>",
225 fn->m_ml->ml_name);
Armin Rigoa871ef22006-02-08 12:53:56 +0000226 }
227}
228
229static ProfilerEntry*
230newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
231{
232 ProfilerEntry *self;
233 self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry));
234 if (self == NULL) {
235 pObj->flags |= POF_NOMEMORY;
236 return NULL;
237 }
238 userObj = normalizeUserObj(userObj);
239 if (userObj == NULL) {
240 PyErr_Clear();
241 free(self);
242 pObj->flags |= POF_NOMEMORY;
243 return NULL;
244 }
245 self->header.key = key;
246 self->userObj = userObj;
247 self->tt = 0;
248 self->it = 0;
249 self->callcount = 0;
250 self->recursivecallcount = 0;
251 self->recursionLevel = 0;
252 self->calls = EMPTY_ROTATING_TREE;
253 RotatingTree_Add(&pObj->profilerEntries, &self->header);
254 return self;
255}
256
257static ProfilerEntry*
258getEntry(ProfilerObject *pObj, void *key)
259{
260 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
261}
262
263static ProfilerSubEntry *
264getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
265{
266 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
267 (void *)entry);
268}
269
270static ProfilerSubEntry *
271newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
272{
273 ProfilerSubEntry *self;
274 self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry));
275 if (self == NULL) {
276 pObj->flags |= POF_NOMEMORY;
277 return NULL;
278 }
279 self->header.key = (void *)entry;
280 self->tt = 0;
281 self->it = 0;
282 self->callcount = 0;
283 self->recursivecallcount = 0;
284 self->recursionLevel = 0;
285 RotatingTree_Add(&caller->calls, &self->header);
286 return self;
287}
288
289static int freeSubEntry(rotating_node_t *header, void *arg)
290{
291 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
292 free(subentry);
293 return 0;
294}
295
296static int freeEntry(rotating_node_t *header, void *arg)
297{
298 ProfilerEntry *entry = (ProfilerEntry*) header;
299 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
300 Py_DECREF(entry->userObj);
301 free(entry);
302 return 0;
303}
304
305static void clearEntries(ProfilerObject *pObj)
306{
307 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
308 pObj->profilerEntries = EMPTY_ROTATING_TREE;
309 /* release the memory hold by the free list of ProfilerContexts */
310 while (pObj->freelistProfilerContext) {
311 ProfilerContext *c = pObj->freelistProfilerContext;
312 pObj->freelistProfilerContext = c->previous;
313 free(c);
314 }
315}
316
317static void
318initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
319{
320 self->ctxEntry = entry;
321 self->subt = 0;
322 self->previous = pObj->currentProfilerContext;
323 pObj->currentProfilerContext = self;
324 ++entry->recursionLevel;
325 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
326 /* find or create an entry for me in my caller's entry */
327 ProfilerEntry *caller = self->previous->ctxEntry;
328 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
329 if (subentry == NULL)
330 subentry = newSubEntry(pObj, caller, entry);
331 if (subentry)
332 ++subentry->recursionLevel;
333 }
334 self->t0 = CALL_TIMER(pObj);
335}
336
337static void
338Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
339{
340 PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0;
341 PY_LONG_LONG it = tt - self->subt;
342 if (self->previous)
343 self->previous->subt += tt;
344 pObj->currentProfilerContext = self->previous;
345 if (--entry->recursionLevel == 0)
346 entry->tt += tt;
347 else
348 ++entry->recursivecallcount;
349 entry->it += it;
350 entry->callcount++;
351 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
352 /* find or create an entry for me in my caller's entry */
353 ProfilerEntry *caller = self->previous->ctxEntry;
354 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
355 if (subentry) {
356 if (--subentry->recursionLevel == 0)
357 subentry->tt += tt;
358 else
359 ++subentry->recursivecallcount;
360 subentry->it += it;
361 ++subentry->callcount;
362 }
363 }
364}
365
366static void
367ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
368{
369 /* entering a call to the function identified by 'key'
370 (which can be a PyCodeObject or a PyMethodDef pointer) */
371 ProfilerObject *pObj = (ProfilerObject*)self;
372 ProfilerEntry *profEntry;
373 ProfilerContext *pContext;
374
375 profEntry = getEntry(pObj, key);
376 if (profEntry == NULL) {
377 profEntry = newProfilerEntry(pObj, key, userObj);
378 if (profEntry == NULL)
379 return;
380 }
381 /* grab a ProfilerContext out of the free list */
382 pContext = pObj->freelistProfilerContext;
383 if (pContext) {
384 pObj->freelistProfilerContext = pContext->previous;
385 }
386 else {
387 /* free list exhausted, allocate a new one */
388 pContext = (ProfilerContext*)
389 malloc(sizeof(ProfilerContext));
390 if (pContext == NULL) {
391 pObj->flags |= POF_NOMEMORY;
392 return;
393 }
394 }
395 initContext(pObj, pContext, profEntry);
396}
397
398static void
399ptrace_leave_call(PyObject *self, void *key)
400{
401 /* leaving a call to the function identified by 'key' */
402 ProfilerObject *pObj = (ProfilerObject*)self;
403 ProfilerEntry *profEntry;
404 ProfilerContext *pContext;
405
406 pContext = pObj->currentProfilerContext;
407 if (pContext == NULL)
408 return;
409 profEntry = getEntry(pObj, key);
410 if (profEntry) {
411 Stop(pObj, pContext, profEntry);
412 }
413 else {
414 pObj->currentProfilerContext = pContext->previous;
415 }
416 /* put pContext into the free list */
417 pContext->previous = pObj->freelistProfilerContext;
418 pObj->freelistProfilerContext = pContext;
419}
420
421static int
422profiler_callback(PyObject *self, PyFrameObject *frame, int what,
423 PyObject *arg)
424{
425 switch (what) {
426
427 /* the 'frame' of a called function is about to start its execution */
428 case PyTrace_CALL:
429 ptrace_enter_call(self, (void *)frame->f_code,
430 (PyObject *)frame->f_code);
431 break;
432
433 /* the 'frame' of a called function is about to finish
434 (either normally or with an exception) */
435 case PyTrace_RETURN:
436 ptrace_leave_call(self, (void *)frame->f_code);
437 break;
438
439 /* case PyTrace_EXCEPTION:
440 If the exception results in the function exiting, a
441 PyTrace_RETURN event will be generated, so we don't need to
442 handle it. */
443
444#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */
445 /* the Python function 'frame' is issuing a call to the built-in
446 function 'arg' */
447 case PyTrace_C_CALL:
448 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
449 && PyCFunction_Check(arg)) {
450 ptrace_enter_call(self,
451 ((PyCFunctionObject *)arg)->m_ml,
452 arg);
453 }
454 break;
455
456 /* the call to the built-in function 'arg' is returning into its
457 caller 'frame' */
458 case PyTrace_C_RETURN: /* ...normally */
459 case PyTrace_C_EXCEPTION: /* ...with an exception set */
460 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
461 && PyCFunction_Check(arg)) {
462 ptrace_leave_call(self,
463 ((PyCFunctionObject *)arg)->m_ml);
464 }
465 break;
466#endif
467
468 default:
469 break;
470 }
471 return 0;
472}
473
474static int
475pending_exception(ProfilerObject *pObj)
476{
477 if (pObj->flags & POF_NOMEMORY) {
478 pObj->flags -= POF_NOMEMORY;
479 PyErr_SetString(PyExc_MemoryError,
480 "memory was exhausted while profiling");
481 return -1;
482 }
483 return 0;
484}
485
486/************************************************************/
487
488static PyStructSequence_Field profiler_entry_fields[] = {
489 {"code", "code object or built-in function name"},
490 {"callcount", "how many times this was called"},
491 {"reccallcount", "how many times called recursively"},
492 {"totaltime", "total time in this entry"},
493 {"inlinetime", "inline time in this entry (not in subcalls)"},
494 {"calls", "details of the calls"},
495 {0}
496};
497
498static PyStructSequence_Field profiler_subentry_fields[] = {
499 {"code", "called code object or built-in function name"},
500 {"callcount", "how many times this is called"},
501 {"reccallcount", "how many times this is called recursively"},
502 {"totaltime", "total time spent in this call"},
503 {"inlinetime", "inline time (not in further subcalls)"},
504 {0}
505};
506
507static PyStructSequence_Desc profiler_entry_desc = {
508 "_lsprof.profiler_entry", /* name */
509 NULL, /* doc */
510 profiler_entry_fields,
511 6
512};
513
514static PyStructSequence_Desc profiler_subentry_desc = {
515 "_lsprof.profiler_subentry", /* name */
516 NULL, /* doc */
517 profiler_subentry_fields,
518 5
519};
520
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000521static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000522static PyTypeObject StatsEntryType;
523static PyTypeObject StatsSubEntryType;
524
525
526typedef struct {
527 PyObject *list;
528 PyObject *sublist;
529 double factor;
530} statscollector_t;
531
532static int statsForSubEntry(rotating_node_t *node, void *arg)
533{
534 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
535 statscollector_t *collect = (statscollector_t*) arg;
536 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
537 int err;
538 PyObject *sinfo;
539 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
540 "((Olldd))",
541 entry->userObj,
542 sentry->callcount,
543 sentry->recursivecallcount,
544 collect->factor * sentry->tt,
545 collect->factor * sentry->it);
546 if (sinfo == NULL)
547 return -1;
548 err = PyList_Append(collect->sublist, sinfo);
549 Py_DECREF(sinfo);
550 return err;
551}
552
553static int statsForEntry(rotating_node_t *node, void *arg)
554{
555 ProfilerEntry *entry = (ProfilerEntry*) node;
556 statscollector_t *collect = (statscollector_t*) arg;
557 PyObject *info;
558 int err;
559 if (entry->callcount == 0)
560 return 0; /* skip */
561
562 if (entry->calls != EMPTY_ROTATING_TREE) {
563 collect->sublist = PyList_New(0);
564 if (collect->sublist == NULL)
565 return -1;
566 if (RotatingTree_Enum(entry->calls,
567 statsForSubEntry, collect) != 0) {
568 Py_DECREF(collect->sublist);
569 return -1;
570 }
571 }
572 else {
573 Py_INCREF(Py_None);
574 collect->sublist = Py_None;
575 }
576
577 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
578 "((OllddO))",
579 entry->userObj,
580 entry->callcount,
581 entry->recursivecallcount,
582 collect->factor * entry->tt,
583 collect->factor * entry->it,
584 collect->sublist);
585 Py_DECREF(collect->sublist);
586 if (info == NULL)
587 return -1;
588 err = PyList_Append(collect->list, info);
589 Py_DECREF(info);
590 return err;
591}
592
593PyDoc_STRVAR(getstats_doc, "\
594getstats() -> list of profiler_entry objects\n\
595\n\
596Return all information collected by the profiler.\n\
597Each profiler_entry is a tuple-like object with the\n\
598following attributes:\n\
599\n\
600 code code object\n\
601 callcount how many times this was called\n\
602 reccallcount how many times called recursively\n\
603 totaltime total time in this entry\n\
604 inlinetime inline time in this entry (not in subcalls)\n\
605 calls details of the calls\n\
606\n\
607The calls attribute is either None or a list of\n\
608profiler_subentry objects:\n\
609\n\
610 code called code object\n\
611 callcount how many times this is called\n\
612 reccallcount how many times this is called recursively\n\
613 totaltime total time spent in this call\n\
614 inlinetime inline time (not in further subcalls)\n\
615");
616
617static PyObject*
618profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
619{
620 statscollector_t collect;
621 if (pending_exception(pObj))
622 return NULL;
623 if (!pObj->externalTimer)
624 collect.factor = hpTimerUnit();
625 else if (pObj->externalTimerUnit > 0.0)
626 collect.factor = pObj->externalTimerUnit;
627 else
628 collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
629 collect.list = PyList_New(0);
630 if (collect.list == NULL)
631 return NULL;
632 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
633 != 0) {
634 Py_DECREF(collect.list);
635 return NULL;
636 }
637 return collect.list;
638}
639
640static int
641setSubcalls(ProfilerObject *pObj, int nvalue)
642{
643 if (nvalue == 0)
644 pObj->flags &= ~POF_SUBCALLS;
645 else if (nvalue > 0)
646 pObj->flags |= POF_SUBCALLS;
647 return 0;
648}
649
650static int
651setBuiltins(ProfilerObject *pObj, int nvalue)
652{
653 if (nvalue == 0)
654 pObj->flags &= ~POF_BUILTINS;
655 else if (nvalue > 0) {
656#ifndef PyTrace_C_CALL
657 PyErr_SetString(PyExc_ValueError,
658 "builtins=True requires Python >= 2.4");
659 return -1;
660#else
661 pObj->flags |= POF_BUILTINS;
662#endif
663 }
664 return 0;
665}
666
667PyDoc_STRVAR(enable_doc, "\
668enable(subcalls=True, builtins=True)\n\
669\n\
670Start collecting profiling information.\n\
671If 'subcalls' is True, also records for each function\n\
672statistics separated according to its current caller.\n\
673If 'builtins' is True, records the time spent in\n\
674built-in functions separately from their caller.\n\
675");
676
677static PyObject*
678profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
679{
680 int subcalls = -1;
681 int builtins = -1;
Martin v. Löwis15e62742006-02-27 16:46:16 +0000682 static char *kwlist[] = {"subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000683 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
684 kwlist, &subcalls, &builtins))
685 return NULL;
686 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
687 return NULL;
688 PyEval_SetProfile(profiler_callback, (PyObject*)self);
689 self->flags |= POF_ENABLED;
690 Py_INCREF(Py_None);
691 return Py_None;
692}
693
694static void
695flush_unmatched(ProfilerObject *pObj)
696{
697 while (pObj->currentProfilerContext) {
698 ProfilerContext *pContext = pObj->currentProfilerContext;
699 ProfilerEntry *profEntry= pContext->ctxEntry;
700 if (profEntry)
701 Stop(pObj, pContext, profEntry);
702 else
703 pObj->currentProfilerContext = pContext->previous;
704 if (pContext)
705 free(pContext);
706 }
707
708}
709
710PyDoc_STRVAR(disable_doc, "\
711disable()\n\
712\n\
713Stop collecting profiling information.\n\
714");
715
716static PyObject*
717profiler_disable(ProfilerObject *self, PyObject* noarg)
718{
719 self->flags &= ~POF_ENABLED;
720 PyEval_SetProfile(NULL, NULL);
721 flush_unmatched(self);
722 if (pending_exception(self))
723 return NULL;
724 Py_INCREF(Py_None);
725 return Py_None;
726}
727
728PyDoc_STRVAR(clear_doc, "\
729clear()\n\
730\n\
731Clear all profiling information collected so far.\n\
732");
733
734static PyObject*
735profiler_clear(ProfilerObject *pObj, PyObject* noarg)
736{
737 clearEntries(pObj);
738 Py_INCREF(Py_None);
739 return Py_None;
740}
741
742static void
743profiler_dealloc(ProfilerObject *op)
744{
745 if (op->flags & POF_ENABLED)
746 PyEval_SetProfile(NULL, NULL);
747 flush_unmatched(op);
748 clearEntries(op);
749 Py_XDECREF(op->externalTimer);
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000750 Py_Type(op)->tp_free(op);
Armin Rigoa871ef22006-02-08 12:53:56 +0000751}
752
753static int
754profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
755{
756 PyObject *o;
757 PyObject *timer = NULL;
758 double timeunit = 0.0;
759 int subcalls = 1;
760#ifdef PyTrace_C_CALL
761 int builtins = 1;
762#else
763 int builtins = 0;
764#endif
Martin v. Löwis15e62742006-02-27 16:46:16 +0000765 static char *kwlist[] = {"timer", "timeunit",
Armin Rigoa871ef22006-02-08 12:53:56 +0000766 "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 o = pObj->externalTimer;
776 pObj->externalTimer = timer;
777 Py_XINCREF(timer);
778 Py_XDECREF(o);
779 pObj->externalTimerUnit = timeunit;
780 return 0;
781}
782
783static PyMethodDef profiler_methods[] = {
784 {"getstats", (PyCFunction)profiler_getstats,
785 METH_NOARGS, getstats_doc},
786 {"enable", (PyCFunction)profiler_enable,
787 METH_VARARGS | METH_KEYWORDS, enable_doc},
788 {"disable", (PyCFunction)profiler_disable,
789 METH_NOARGS, disable_doc},
790 {"clear", (PyCFunction)profiler_clear,
791 METH_NOARGS, clear_doc},
792 {NULL, NULL}
793};
794
795PyDoc_STRVAR(profiler_doc, "\
796Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
797\n\
798 Builds a profiler object using the specified timer function.\n\
799 The default timer is a fast built-in one based on real time.\n\
800 For custom timer functions returning integers, time_unit can\n\
801 be a float specifying a scale (i.e. how long each integer unit\n\
802 is, in seconds).\n\
803");
804
Neal Norwitz227b5332006-03-22 09:28:35 +0000805static PyTypeObject PyProfiler_Type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000806 PyVarObject_HEAD_INIT(NULL, 0)
Armin Rigoa871ef22006-02-08 12:53:56 +0000807 "_lsprof.Profiler", /* tp_name */
808 sizeof(ProfilerObject), /* tp_basicsize */
809 0, /* tp_itemsize */
810 (destructor)profiler_dealloc, /* tp_dealloc */
811 0, /* tp_print */
812 0, /* tp_getattr */
813 0, /* tp_setattr */
814 0, /* tp_compare */
815 0, /* tp_repr */
816 0, /* tp_as_number */
817 0, /* tp_as_sequence */
818 0, /* tp_as_mapping */
819 0, /* tp_hash */
820 0, /* tp_call */
821 0, /* tp_str */
822 0, /* tp_getattro */
823 0, /* tp_setattro */
824 0, /* tp_as_buffer */
825 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
826 profiler_doc, /* tp_doc */
827 0, /* tp_traverse */
828 0, /* tp_clear */
829 0, /* tp_richcompare */
830 0, /* tp_weaklistoffset */
831 0, /* tp_iter */
832 0, /* tp_iternext */
833 profiler_methods, /* tp_methods */
834 0, /* tp_members */
835 0, /* tp_getset */
836 0, /* tp_base */
837 0, /* tp_dict */
838 0, /* tp_descr_get */
839 0, /* tp_descr_set */
840 0, /* tp_dictoffset */
841 (initproc)profiler_init, /* tp_init */
842 PyType_GenericAlloc, /* tp_alloc */
843 PyType_GenericNew, /* tp_new */
844 PyObject_Del, /* tp_free */
845};
846
847static PyMethodDef moduleMethods[] = {
848 {NULL, NULL}
849};
850
851PyMODINIT_FUNC
852init_lsprof(void)
853{
854 PyObject *module, *d;
855 module = Py_InitModule3("_lsprof", moduleMethods, "Fast profiler");
Neal Norwitz60da3162006-03-07 04:48:24 +0000856 if (module == NULL)
857 return;
Armin Rigoa871ef22006-02-08 12:53:56 +0000858 d = PyModule_GetDict(module);
859 if (PyType_Ready(&PyProfiler_Type) < 0)
860 return;
861 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
862
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000863 if (!initialized) {
864 PyStructSequence_InitType(&StatsEntryType,
865 &profiler_entry_desc);
866 PyStructSequence_InitType(&StatsSubEntryType,
867 &profiler_subentry_desc);
868 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000869 Py_INCREF((PyObject*) &StatsEntryType);
870 Py_INCREF((PyObject*) &StatsSubEntryType);
871 PyModule_AddObject(module, "profiler_entry",
872 (PyObject*) &StatsEntryType);
873 PyModule_AddObject(module, "profiler_subentry",
874 (PyObject*) &StatsSubEntryType);
875 empty_tuple = PyTuple_New(0);
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000876 initialized = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000877}