blob: 41c477e388c21571eb8af4ec7d8d2324b66f1a41 [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
120staticforward PyTypeObject PyProfiler_Type;
121
122#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
Christian Heimese93237d2007-12-19 02:37:44 +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()) {
Brett Cannonb2d61bd2008-09-29 03:41:21 +0000153 PyObject *context = (PyObject *)pObj;
154 /* May have been called by profiler_dealloc(). */
155 if (Py_REFCNT(context) < 1) {
156 context = PyString_FromString("profiler calling an "
157 "external timer");
158 if (context == NULL) {
159 return 0;
160 }
161 }
162 PyErr_WriteUnraisable(context);
Armin Rigoa871ef22006-02-08 12:53:56 +0000163 return 0;
164 }
165 return result;
166}
167
168#define CALL_TIMER(pObj) ((pObj)->externalTimer ? \
169 CallExternalTimer(pObj) : \
170 hpTimer())
171
172/*** ProfilerObject ***/
173
174static PyObject *
175normalizeUserObj(PyObject *obj)
176{
177 PyCFunctionObject *fn;
178 if (!PyCFunction_Check(obj)) {
179 Py_INCREF(obj);
180 return obj;
181 }
182 /* Replace built-in function objects with a descriptive string
183 because of built-in methods -- keeping a reference to
184 __self__ is probably not a good idea. */
185 fn = (PyCFunctionObject *)obj;
186
187 if (fn->m_self == NULL) {
188 /* built-in function: look up the module name */
189 PyObject *mod = fn->m_module;
190 char *modname;
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000191 if (mod && PyString_Check(mod)) {
192 modname = PyString_AS_STRING(mod);
Armin Rigoa871ef22006-02-08 12:53:56 +0000193 }
194 else if (mod && PyModule_Check(mod)) {
195 modname = PyModule_GetName(mod);
196 if (modname == NULL) {
197 PyErr_Clear();
198 modname = "__builtin__";
199 }
200 }
201 else {
202 modname = "__builtin__";
203 }
204 if (strcmp(modname, "__builtin__") != 0)
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000205 return PyString_FromFormat("<%s.%s>",
Armin Rigoa871ef22006-02-08 12:53:56 +0000206 modname,
207 fn->m_ml->ml_name);
208 else
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000209 return PyString_FromFormat("<%s>",
Armin Rigoa871ef22006-02-08 12:53:56 +0000210 fn->m_ml->ml_name);
211 }
212 else {
213 /* built-in method: try to return
214 repr(getattr(type(__self__), __name__))
215 */
216 PyObject *self = fn->m_self;
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000217 PyObject *name = PyString_FromString(fn->m_ml->ml_name);
Armin Rigoa871ef22006-02-08 12:53:56 +0000218 if (name != NULL) {
Christian Heimese93237d2007-12-19 02:37:44 +0000219 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
Armin Rigoa871ef22006-02-08 12:53:56 +0000220 Py_XINCREF(mo);
221 Py_DECREF(name);
222 if (mo != NULL) {
223 PyObject *res = PyObject_Repr(mo);
224 Py_DECREF(mo);
225 if (res != NULL)
226 return res;
227 }
228 }
229 PyErr_Clear();
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000230 return PyString_FromFormat("<built-in method %s>",
Armin Rigoa871ef22006-02-08 12:53:56 +0000231 fn->m_ml->ml_name);
232 }
233}
234
235static ProfilerEntry*
236newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
237{
238 ProfilerEntry *self;
239 self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry));
240 if (self == NULL) {
241 pObj->flags |= POF_NOMEMORY;
242 return NULL;
243 }
244 userObj = normalizeUserObj(userObj);
245 if (userObj == NULL) {
246 PyErr_Clear();
247 free(self);
248 pObj->flags |= POF_NOMEMORY;
249 return NULL;
250 }
251 self->header.key = key;
252 self->userObj = userObj;
253 self->tt = 0;
254 self->it = 0;
255 self->callcount = 0;
256 self->recursivecallcount = 0;
257 self->recursionLevel = 0;
258 self->calls = EMPTY_ROTATING_TREE;
259 RotatingTree_Add(&pObj->profilerEntries, &self->header);
260 return self;
261}
262
263static ProfilerEntry*
264getEntry(ProfilerObject *pObj, void *key)
265{
266 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
267}
268
269static ProfilerSubEntry *
270getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
271{
272 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
273 (void *)entry);
274}
275
276static ProfilerSubEntry *
277newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
278{
279 ProfilerSubEntry *self;
280 self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry));
281 if (self == NULL) {
282 pObj->flags |= POF_NOMEMORY;
283 return NULL;
284 }
285 self->header.key = (void *)entry;
286 self->tt = 0;
287 self->it = 0;
288 self->callcount = 0;
289 self->recursivecallcount = 0;
290 self->recursionLevel = 0;
291 RotatingTree_Add(&caller->calls, &self->header);
292 return self;
293}
294
295static int freeSubEntry(rotating_node_t *header, void *arg)
296{
297 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
298 free(subentry);
299 return 0;
300}
301
302static int freeEntry(rotating_node_t *header, void *arg)
303{
304 ProfilerEntry *entry = (ProfilerEntry*) header;
305 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
306 Py_DECREF(entry->userObj);
307 free(entry);
308 return 0;
309}
310
311static void clearEntries(ProfilerObject *pObj)
312{
313 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
314 pObj->profilerEntries = EMPTY_ROTATING_TREE;
315 /* release the memory hold by the free list of ProfilerContexts */
316 while (pObj->freelistProfilerContext) {
317 ProfilerContext *c = pObj->freelistProfilerContext;
318 pObj->freelistProfilerContext = c->previous;
319 free(c);
320 }
321}
322
323static void
324initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
325{
326 self->ctxEntry = entry;
327 self->subt = 0;
328 self->previous = pObj->currentProfilerContext;
329 pObj->currentProfilerContext = self;
330 ++entry->recursionLevel;
331 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
332 /* find or create an entry for me in my caller's entry */
333 ProfilerEntry *caller = self->previous->ctxEntry;
334 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
335 if (subentry == NULL)
336 subentry = newSubEntry(pObj, caller, entry);
337 if (subentry)
338 ++subentry->recursionLevel;
339 }
340 self->t0 = CALL_TIMER(pObj);
341}
342
343static void
344Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
345{
346 PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0;
347 PY_LONG_LONG it = tt - self->subt;
348 if (self->previous)
349 self->previous->subt += tt;
350 pObj->currentProfilerContext = self->previous;
351 if (--entry->recursionLevel == 0)
352 entry->tt += tt;
353 else
354 ++entry->recursivecallcount;
355 entry->it += it;
356 entry->callcount++;
357 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
358 /* find or create an entry for me in my caller's entry */
359 ProfilerEntry *caller = self->previous->ctxEntry;
360 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
361 if (subentry) {
362 if (--subentry->recursionLevel == 0)
363 subentry->tt += tt;
364 else
365 ++subentry->recursivecallcount;
366 subentry->it += it;
367 ++subentry->callcount;
368 }
369 }
370}
371
372static void
373ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
374{
375 /* entering a call to the function identified by 'key'
376 (which can be a PyCodeObject or a PyMethodDef pointer) */
377 ProfilerObject *pObj = (ProfilerObject*)self;
378 ProfilerEntry *profEntry;
379 ProfilerContext *pContext;
380
Armin Rigobddc3412007-09-06 08:30:51 +0000381 /* In the case of entering a generator expression frame via a
382 * throw (gen_send_ex(.., 1)), we may already have an
383 * Exception set here. We must not mess around with this
384 * exception, and some of the code under here assumes that
385 * PyErr_* is its own to mess around with, so we have to
386 * save and restore any current exception. */
387 PyObject *last_type, *last_value, *last_tb;
388 PyErr_Fetch(&last_type, &last_value, &last_tb);
389
Armin Rigoa871ef22006-02-08 12:53:56 +0000390 profEntry = getEntry(pObj, key);
391 if (profEntry == NULL) {
392 profEntry = newProfilerEntry(pObj, key, userObj);
393 if (profEntry == NULL)
Armin Rigobddc3412007-09-06 08:30:51 +0000394 goto restorePyerr;
Armin Rigoa871ef22006-02-08 12:53:56 +0000395 }
396 /* grab a ProfilerContext out of the free list */
397 pContext = pObj->freelistProfilerContext;
398 if (pContext) {
399 pObj->freelistProfilerContext = pContext->previous;
400 }
401 else {
402 /* free list exhausted, allocate a new one */
403 pContext = (ProfilerContext*)
404 malloc(sizeof(ProfilerContext));
405 if (pContext == NULL) {
406 pObj->flags |= POF_NOMEMORY;
Armin Rigobddc3412007-09-06 08:30:51 +0000407 goto restorePyerr;
Armin Rigoa871ef22006-02-08 12:53:56 +0000408 }
409 }
410 initContext(pObj, pContext, profEntry);
Armin Rigobddc3412007-09-06 08:30:51 +0000411
412restorePyerr:
413 PyErr_Restore(last_type, last_value, last_tb);
Armin Rigoa871ef22006-02-08 12:53:56 +0000414}
415
416static void
417ptrace_leave_call(PyObject *self, void *key)
418{
419 /* leaving a call to the function identified by 'key' */
420 ProfilerObject *pObj = (ProfilerObject*)self;
421 ProfilerEntry *profEntry;
422 ProfilerContext *pContext;
423
424 pContext = pObj->currentProfilerContext;
425 if (pContext == NULL)
426 return;
427 profEntry = getEntry(pObj, key);
428 if (profEntry) {
429 Stop(pObj, pContext, profEntry);
430 }
431 else {
432 pObj->currentProfilerContext = pContext->previous;
433 }
434 /* put pContext into the free list */
435 pContext->previous = pObj->freelistProfilerContext;
436 pObj->freelistProfilerContext = pContext;
437}
438
439static int
440profiler_callback(PyObject *self, PyFrameObject *frame, int what,
441 PyObject *arg)
442{
443 switch (what) {
444
445 /* the 'frame' of a called function is about to start its execution */
446 case PyTrace_CALL:
447 ptrace_enter_call(self, (void *)frame->f_code,
448 (PyObject *)frame->f_code);
449 break;
450
451 /* the 'frame' of a called function is about to finish
452 (either normally or with an exception) */
453 case PyTrace_RETURN:
454 ptrace_leave_call(self, (void *)frame->f_code);
455 break;
456
457 /* case PyTrace_EXCEPTION:
458 If the exception results in the function exiting, a
459 PyTrace_RETURN event will be generated, so we don't need to
460 handle it. */
461
462#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */
463 /* the Python function 'frame' is issuing a call to the built-in
464 function 'arg' */
465 case PyTrace_C_CALL:
466 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
467 && PyCFunction_Check(arg)) {
468 ptrace_enter_call(self,
469 ((PyCFunctionObject *)arg)->m_ml,
470 arg);
471 }
472 break;
473
474 /* the call to the built-in function 'arg' is returning into its
475 caller 'frame' */
476 case PyTrace_C_RETURN: /* ...normally */
477 case PyTrace_C_EXCEPTION: /* ...with an exception set */
478 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
479 && PyCFunction_Check(arg)) {
480 ptrace_leave_call(self,
481 ((PyCFunctionObject *)arg)->m_ml);
482 }
483 break;
484#endif
485
486 default:
487 break;
488 }
489 return 0;
490}
491
492static int
493pending_exception(ProfilerObject *pObj)
494{
495 if (pObj->flags & POF_NOMEMORY) {
496 pObj->flags -= POF_NOMEMORY;
497 PyErr_SetString(PyExc_MemoryError,
498 "memory was exhausted while profiling");
499 return -1;
500 }
501 return 0;
502}
503
504/************************************************************/
505
506static PyStructSequence_Field profiler_entry_fields[] = {
507 {"code", "code object or built-in function name"},
508 {"callcount", "how many times this was called"},
509 {"reccallcount", "how many times called recursively"},
510 {"totaltime", "total time in this entry"},
511 {"inlinetime", "inline time in this entry (not in subcalls)"},
512 {"calls", "details of the calls"},
513 {0}
514};
515
516static PyStructSequence_Field profiler_subentry_fields[] = {
517 {"code", "called code object or built-in function name"},
518 {"callcount", "how many times this is called"},
519 {"reccallcount", "how many times this is called recursively"},
520 {"totaltime", "total time spent in this call"},
521 {"inlinetime", "inline time (not in further subcalls)"},
522 {0}
523};
524
525static PyStructSequence_Desc profiler_entry_desc = {
526 "_lsprof.profiler_entry", /* name */
527 NULL, /* doc */
528 profiler_entry_fields,
529 6
530};
531
532static PyStructSequence_Desc profiler_subentry_desc = {
533 "_lsprof.profiler_subentry", /* name */
534 NULL, /* doc */
535 profiler_subentry_fields,
536 5
537};
538
Martin v. Löwis19ab6c92006-04-16 18:55:50 +0000539static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000540static PyTypeObject StatsEntryType;
541static PyTypeObject StatsSubEntryType;
542
543
544typedef struct {
545 PyObject *list;
546 PyObject *sublist;
547 double factor;
548} statscollector_t;
549
550static int statsForSubEntry(rotating_node_t *node, void *arg)
551{
552 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
553 statscollector_t *collect = (statscollector_t*) arg;
554 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
555 int err;
556 PyObject *sinfo;
557 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
558 "((Olldd))",
559 entry->userObj,
560 sentry->callcount,
561 sentry->recursivecallcount,
562 collect->factor * sentry->tt,
563 collect->factor * sentry->it);
564 if (sinfo == NULL)
565 return -1;
566 err = PyList_Append(collect->sublist, sinfo);
567 Py_DECREF(sinfo);
568 return err;
569}
570
571static int statsForEntry(rotating_node_t *node, void *arg)
572{
573 ProfilerEntry *entry = (ProfilerEntry*) node;
574 statscollector_t *collect = (statscollector_t*) arg;
575 PyObject *info;
576 int err;
577 if (entry->callcount == 0)
578 return 0; /* skip */
579
580 if (entry->calls != EMPTY_ROTATING_TREE) {
581 collect->sublist = PyList_New(0);
582 if (collect->sublist == NULL)
583 return -1;
584 if (RotatingTree_Enum(entry->calls,
585 statsForSubEntry, collect) != 0) {
586 Py_DECREF(collect->sublist);
587 return -1;
588 }
589 }
590 else {
591 Py_INCREF(Py_None);
592 collect->sublist = Py_None;
593 }
594
595 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
596 "((OllddO))",
597 entry->userObj,
598 entry->callcount,
599 entry->recursivecallcount,
600 collect->factor * entry->tt,
601 collect->factor * entry->it,
602 collect->sublist);
603 Py_DECREF(collect->sublist);
604 if (info == NULL)
605 return -1;
606 err = PyList_Append(collect->list, info);
607 Py_DECREF(info);
608 return err;
609}
610
611PyDoc_STRVAR(getstats_doc, "\
612getstats() -> list of profiler_entry objects\n\
613\n\
614Return all information collected by the profiler.\n\
615Each profiler_entry is a tuple-like object with the\n\
616following attributes:\n\
617\n\
618 code code object\n\
619 callcount how many times this was called\n\
620 reccallcount how many times called recursively\n\
621 totaltime total time in this entry\n\
622 inlinetime inline time in this entry (not in subcalls)\n\
623 calls details of the calls\n\
624\n\
625The calls attribute is either None or a list of\n\
626profiler_subentry objects:\n\
627\n\
628 code called code object\n\
629 callcount how many times this is called\n\
630 reccallcount how many times this is called recursively\n\
631 totaltime total time spent in this call\n\
632 inlinetime inline time (not in further subcalls)\n\
633");
634
635static PyObject*
636profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
637{
638 statscollector_t collect;
639 if (pending_exception(pObj))
640 return NULL;
641 if (!pObj->externalTimer)
642 collect.factor = hpTimerUnit();
643 else if (pObj->externalTimerUnit > 0.0)
644 collect.factor = pObj->externalTimerUnit;
645 else
646 collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
647 collect.list = PyList_New(0);
648 if (collect.list == NULL)
649 return NULL;
650 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
651 != 0) {
652 Py_DECREF(collect.list);
653 return NULL;
654 }
655 return collect.list;
656}
657
658static int
659setSubcalls(ProfilerObject *pObj, int nvalue)
660{
661 if (nvalue == 0)
662 pObj->flags &= ~POF_SUBCALLS;
663 else if (nvalue > 0)
664 pObj->flags |= POF_SUBCALLS;
665 return 0;
666}
667
668static int
669setBuiltins(ProfilerObject *pObj, int nvalue)
670{
671 if (nvalue == 0)
672 pObj->flags &= ~POF_BUILTINS;
673 else if (nvalue > 0) {
674#ifndef PyTrace_C_CALL
675 PyErr_SetString(PyExc_ValueError,
676 "builtins=True requires Python >= 2.4");
677 return -1;
678#else
679 pObj->flags |= POF_BUILTINS;
680#endif
681 }
682 return 0;
683}
684
685PyDoc_STRVAR(enable_doc, "\
686enable(subcalls=True, builtins=True)\n\
687\n\
688Start collecting profiling information.\n\
689If 'subcalls' is True, also records for each function\n\
690statistics separated according to its current caller.\n\
691If 'builtins' is True, records the time spent in\n\
692built-in functions separately from their caller.\n\
693");
694
695static PyObject*
696profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
697{
698 int subcalls = -1;
699 int builtins = -1;
Martin v. Löwis15e62742006-02-27 16:46:16 +0000700 static char *kwlist[] = {"subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000701 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
702 kwlist, &subcalls, &builtins))
703 return NULL;
704 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
705 return NULL;
706 PyEval_SetProfile(profiler_callback, (PyObject*)self);
707 self->flags |= POF_ENABLED;
708 Py_INCREF(Py_None);
709 return Py_None;
710}
711
712static void
713flush_unmatched(ProfilerObject *pObj)
714{
715 while (pObj->currentProfilerContext) {
716 ProfilerContext *pContext = pObj->currentProfilerContext;
717 ProfilerEntry *profEntry= pContext->ctxEntry;
718 if (profEntry)
719 Stop(pObj, pContext, profEntry);
720 else
721 pObj->currentProfilerContext = pContext->previous;
722 if (pContext)
723 free(pContext);
724 }
725
726}
727
728PyDoc_STRVAR(disable_doc, "\
729disable()\n\
730\n\
731Stop collecting profiling information.\n\
732");
733
734static PyObject*
735profiler_disable(ProfilerObject *self, PyObject* noarg)
736{
737 self->flags &= ~POF_ENABLED;
738 PyEval_SetProfile(NULL, NULL);
739 flush_unmatched(self);
740 if (pending_exception(self))
741 return NULL;
742 Py_INCREF(Py_None);
743 return Py_None;
744}
745
746PyDoc_STRVAR(clear_doc, "\
747clear()\n\
748\n\
749Clear all profiling information collected so far.\n\
750");
751
752static PyObject*
753profiler_clear(ProfilerObject *pObj, PyObject* noarg)
754{
755 clearEntries(pObj);
756 Py_INCREF(Py_None);
757 return Py_None;
758}
759
760static void
761profiler_dealloc(ProfilerObject *op)
762{
763 if (op->flags & POF_ENABLED)
764 PyEval_SetProfile(NULL, NULL);
765 flush_unmatched(op);
766 clearEntries(op);
767 Py_XDECREF(op->externalTimer);
Christian Heimese93237d2007-12-19 02:37:44 +0000768 Py_TYPE(op)->tp_free(op);
Armin Rigoa871ef22006-02-08 12:53:56 +0000769}
770
771static int
772profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
773{
774 PyObject *o;
775 PyObject *timer = NULL;
776 double timeunit = 0.0;
777 int subcalls = 1;
778#ifdef PyTrace_C_CALL
779 int builtins = 1;
780#else
781 int builtins = 0;
782#endif
Martin v. Löwis15e62742006-02-27 16:46:16 +0000783 static char *kwlist[] = {"timer", "timeunit",
Armin Rigoa871ef22006-02-08 12:53:56 +0000784 "subcalls", "builtins", 0};
785
786 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
787 &timer, &timeunit,
788 &subcalls, &builtins))
789 return -1;
790
791 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
792 return -1;
793 o = pObj->externalTimer;
794 pObj->externalTimer = timer;
795 Py_XINCREF(timer);
796 Py_XDECREF(o);
797 pObj->externalTimerUnit = timeunit;
798 return 0;
799}
800
801static PyMethodDef profiler_methods[] = {
802 {"getstats", (PyCFunction)profiler_getstats,
803 METH_NOARGS, getstats_doc},
804 {"enable", (PyCFunction)profiler_enable,
805 METH_VARARGS | METH_KEYWORDS, enable_doc},
806 {"disable", (PyCFunction)profiler_disable,
807 METH_NOARGS, disable_doc},
808 {"clear", (PyCFunction)profiler_clear,
809 METH_NOARGS, clear_doc},
810 {NULL, NULL}
811};
812
813PyDoc_STRVAR(profiler_doc, "\
814Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
815\n\
816 Builds a profiler object using the specified timer function.\n\
817 The default timer is a fast built-in one based on real time.\n\
818 For custom timer functions returning integers, time_unit can\n\
819 be a float specifying a scale (i.e. how long each integer unit\n\
820 is, in seconds).\n\
821");
822
823statichere PyTypeObject PyProfiler_Type = {
824 PyObject_HEAD_INIT(NULL)
825 0, /* ob_size */
826 "_lsprof.Profiler", /* tp_name */
827 sizeof(ProfilerObject), /* tp_basicsize */
828 0, /* tp_itemsize */
829 (destructor)profiler_dealloc, /* tp_dealloc */
830 0, /* tp_print */
831 0, /* tp_getattr */
832 0, /* tp_setattr */
833 0, /* tp_compare */
834 0, /* tp_repr */
835 0, /* tp_as_number */
836 0, /* tp_as_sequence */
837 0, /* tp_as_mapping */
838 0, /* tp_hash */
839 0, /* tp_call */
840 0, /* tp_str */
841 0, /* tp_getattro */
842 0, /* tp_setattro */
843 0, /* tp_as_buffer */
844 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
845 profiler_doc, /* tp_doc */
846 0, /* tp_traverse */
847 0, /* tp_clear */
848 0, /* tp_richcompare */
849 0, /* tp_weaklistoffset */
850 0, /* tp_iter */
851 0, /* tp_iternext */
852 profiler_methods, /* tp_methods */
853 0, /* tp_members */
854 0, /* tp_getset */
855 0, /* tp_base */
856 0, /* tp_dict */
857 0, /* tp_descr_get */
858 0, /* tp_descr_set */
859 0, /* tp_dictoffset */
860 (initproc)profiler_init, /* tp_init */
861 PyType_GenericAlloc, /* tp_alloc */
862 PyType_GenericNew, /* tp_new */
863 PyObject_Del, /* tp_free */
864};
865
866static PyMethodDef moduleMethods[] = {
867 {NULL, NULL}
868};
869
870PyMODINIT_FUNC
871init_lsprof(void)
872{
873 PyObject *module, *d;
874 module = Py_InitModule3("_lsprof", moduleMethods, "Fast profiler");
Neal Norwitz60da3162006-03-07 04:48:24 +0000875 if (module == NULL)
876 return;
Armin Rigoa871ef22006-02-08 12:53:56 +0000877 d = PyModule_GetDict(module);
878 if (PyType_Ready(&PyProfiler_Type) < 0)
879 return;
880 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
881
Martin v. Löwis19ab6c92006-04-16 18:55:50 +0000882 if (!initialized) {
883 PyStructSequence_InitType(&StatsEntryType,
884 &profiler_entry_desc);
885 PyStructSequence_InitType(&StatsSubEntryType,
886 &profiler_subentry_desc);
887 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000888 Py_INCREF((PyObject*) &StatsEntryType);
889 Py_INCREF((PyObject*) &StatsSubEntryType);
890 PyModule_AddObject(module, "profiler_entry",
891 (PyObject*) &StatsEntryType);
892 PyModule_AddObject(module, "profiler_subentry",
893 (PyObject*) &StatsSubEntryType);
894 empty_tuple = PyTuple_New(0);
Martin v. Löwis19ab6c92006-04-16 18:55:50 +0000895 initialized = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000896}