blob: 69ecaf101bc08d7bd851b20a2dcfb21456fd59fa [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)
Christian Heimes90aa7642007-12-19 02:45:37 +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;
Neal Norwitzbed67842007-10-27 04:00:45 +0000182 if (mod && PyUnicode_Check(mod)) {
Guido van Rossum1c5a98a2007-07-16 23:36:05 +0000183 modname = PyUnicode_AsString(mod);
184 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000185 else if (mod && PyModule_Check(mod)) {
186 modname = PyModule_GetName(mod);
187 if (modname == NULL) {
188 PyErr_Clear();
Georg Brandl1a3284e2007-12-02 09:40:06 +0000189 modname = "builtins";
Armin Rigoa871ef22006-02-08 12:53:56 +0000190 }
191 }
192 else {
Georg Brandl1a3284e2007-12-02 09:40:06 +0000193 modname = "builtins";
Armin Rigoa871ef22006-02-08 12:53:56 +0000194 }
Georg Brandl1a3284e2007-12-02 09:40:06 +0000195 if (strcmp(modname, "builtins") != 0)
Neal Norwitze1188622007-08-26 02:22:30 +0000196 return PyUnicode_FromFormat("<%s.%s>",
197 modname,
198 fn->m_ml->ml_name);
Armin Rigoa871ef22006-02-08 12:53:56 +0000199 else
Neal Norwitze1188622007-08-26 02:22:30 +0000200 return PyUnicode_FromFormat("<%s>",
201 fn->m_ml->ml_name);
Armin Rigoa871ef22006-02-08 12:53:56 +0000202 }
203 else {
204 /* built-in method: try to return
205 repr(getattr(type(__self__), __name__))
206 */
207 PyObject *self = fn->m_self;
Neal Norwitze1188622007-08-26 02:22:30 +0000208 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
Armin Rigoa871ef22006-02-08 12:53:56 +0000209 if (name != NULL) {
Christian Heimes90aa7642007-12-19 02:45:37 +0000210 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
Armin Rigoa871ef22006-02-08 12:53:56 +0000211 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;
218 }
219 }
220 PyErr_Clear();
Neal Norwitze1188622007-08-26 02:22:30 +0000221 return PyUnicode_FromFormat("<built-in method %s>",
222 fn->m_ml->ml_name);
Armin Rigoa871ef22006-02-08 12:53:56 +0000223 }
224}
225
226static ProfilerEntry*
227newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
228{
229 ProfilerEntry *self;
230 self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry));
231 if (self == NULL) {
232 pObj->flags |= POF_NOMEMORY;
233 return NULL;
234 }
235 userObj = normalizeUserObj(userObj);
236 if (userObj == NULL) {
237 PyErr_Clear();
238 free(self);
239 pObj->flags |= POF_NOMEMORY;
240 return NULL;
241 }
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;
252}
253
254static ProfilerEntry*
255getEntry(ProfilerObject *pObj, void *key)
256{
257 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
258}
259
260static ProfilerSubEntry *
261getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
262{
263 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
264 (void *)entry);
265}
266
267static ProfilerSubEntry *
268newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
269{
270 ProfilerSubEntry *self;
271 self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry));
272 if (self == NULL) {
273 pObj->flags |= POF_NOMEMORY;
274 return NULL;
275 }
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;
284}
285
286static int freeSubEntry(rotating_node_t *header, void *arg)
287{
288 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
289 free(subentry);
290 return 0;
291}
292
293static int freeEntry(rotating_node_t *header, void *arg)
294{
295 ProfilerEntry *entry = (ProfilerEntry*) header;
296 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
297 Py_DECREF(entry->userObj);
298 free(entry);
299 return 0;
300}
301
302static void clearEntries(ProfilerObject *pObj)
303{
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);
311 }
312}
313
314static void
315initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
316{
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;
330 }
331 self->t0 = CALL_TIMER(pObj);
332}
333
334static void
335Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
336{
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;
359 }
360 }
361}
362
363static void
364ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
365{
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;
371
Thomas Wouters89d996e2007-09-08 17:39:28 +0000372 /* In the case of entering a generator expression frame via a
373 * throw (gen_send_ex(.., 1)), we may already have an
374 * Exception set here. We must not mess around with this
375 * exception, and some of the code under here assumes that
376 * PyErr_* is its own to mess around with, so we have to
377 * save and restore any current exception. */
378 PyObject *last_type, *last_value, *last_tb;
379 PyErr_Fetch(&last_type, &last_value, &last_tb);
380
Armin Rigoa871ef22006-02-08 12:53:56 +0000381 profEntry = getEntry(pObj, key);
382 if (profEntry == NULL) {
383 profEntry = newProfilerEntry(pObj, key, userObj);
384 if (profEntry == NULL)
Thomas Wouters89d996e2007-09-08 17:39:28 +0000385 goto restorePyerr;
Armin Rigoa871ef22006-02-08 12:53:56 +0000386 }
387 /* grab a ProfilerContext out of the free list */
388 pContext = pObj->freelistProfilerContext;
389 if (pContext) {
390 pObj->freelistProfilerContext = pContext->previous;
391 }
392 else {
393 /* free list exhausted, allocate a new one */
394 pContext = (ProfilerContext*)
395 malloc(sizeof(ProfilerContext));
396 if (pContext == NULL) {
397 pObj->flags |= POF_NOMEMORY;
Thomas Wouters89d996e2007-09-08 17:39:28 +0000398 goto restorePyerr;
Armin Rigoa871ef22006-02-08 12:53:56 +0000399 }
400 }
401 initContext(pObj, pContext, profEntry);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000402
403restorePyerr:
404 PyErr_Restore(last_type, last_value, last_tb);
Armin Rigoa871ef22006-02-08 12:53:56 +0000405}
406
407static void
408ptrace_leave_call(PyObject *self, void *key)
409{
410 /* leaving a call to the function identified by 'key' */
411 ProfilerObject *pObj = (ProfilerObject*)self;
412 ProfilerEntry *profEntry;
413 ProfilerContext *pContext;
414
415 pContext = pObj->currentProfilerContext;
416 if (pContext == NULL)
417 return;
418 profEntry = getEntry(pObj, key);
419 if (profEntry) {
420 Stop(pObj, pContext, profEntry);
421 }
422 else {
423 pObj->currentProfilerContext = pContext->previous;
424 }
425 /* put pContext into the free list */
426 pContext->previous = pObj->freelistProfilerContext;
427 pObj->freelistProfilerContext = pContext;
428}
429
430static int
431profiler_callback(PyObject *self, PyFrameObject *frame, int what,
432 PyObject *arg)
433{
434 switch (what) {
435
436 /* the 'frame' of a called function is about to start its execution */
437 case PyTrace_CALL:
438 ptrace_enter_call(self, (void *)frame->f_code,
439 (PyObject *)frame->f_code);
440 break;
441
442 /* the 'frame' of a called function is about to finish
443 (either normally or with an exception) */
444 case PyTrace_RETURN:
445 ptrace_leave_call(self, (void *)frame->f_code);
446 break;
447
448 /* case PyTrace_EXCEPTION:
449 If the exception results in the function exiting, a
450 PyTrace_RETURN event will be generated, so we don't need to
451 handle it. */
452
453#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */
454 /* the Python function 'frame' is issuing a call to the built-in
455 function 'arg' */
456 case PyTrace_C_CALL:
457 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
458 && PyCFunction_Check(arg)) {
459 ptrace_enter_call(self,
460 ((PyCFunctionObject *)arg)->m_ml,
461 arg);
462 }
463 break;
464
465 /* the call to the built-in function 'arg' is returning into its
466 caller 'frame' */
467 case PyTrace_C_RETURN: /* ...normally */
468 case PyTrace_C_EXCEPTION: /* ...with an exception set */
469 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
470 && PyCFunction_Check(arg)) {
471 ptrace_leave_call(self,
472 ((PyCFunctionObject *)arg)->m_ml);
473 }
474 break;
475#endif
476
477 default:
478 break;
479 }
480 return 0;
481}
482
483static int
484pending_exception(ProfilerObject *pObj)
485{
486 if (pObj->flags & POF_NOMEMORY) {
487 pObj->flags -= POF_NOMEMORY;
488 PyErr_SetString(PyExc_MemoryError,
489 "memory was exhausted while profiling");
490 return -1;
491 }
492 return 0;
493}
494
495/************************************************************/
496
497static PyStructSequence_Field profiler_entry_fields[] = {
498 {"code", "code object or built-in function name"},
499 {"callcount", "how many times this was called"},
500 {"reccallcount", "how many times called recursively"},
501 {"totaltime", "total time in this entry"},
502 {"inlinetime", "inline time in this entry (not in subcalls)"},
503 {"calls", "details of the calls"},
504 {0}
505};
506
507static PyStructSequence_Field profiler_subentry_fields[] = {
508 {"code", "called code object or built-in function name"},
509 {"callcount", "how many times this is called"},
510 {"reccallcount", "how many times this is called recursively"},
511 {"totaltime", "total time spent in this call"},
512 {"inlinetime", "inline time (not in further subcalls)"},
513 {0}
514};
515
516static PyStructSequence_Desc profiler_entry_desc = {
517 "_lsprof.profiler_entry", /* name */
518 NULL, /* doc */
519 profiler_entry_fields,
520 6
521};
522
523static PyStructSequence_Desc profiler_subentry_desc = {
524 "_lsprof.profiler_subentry", /* name */
525 NULL, /* doc */
526 profiler_subentry_fields,
527 5
528};
529
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000530static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000531static PyTypeObject StatsEntryType;
532static PyTypeObject StatsSubEntryType;
533
534
535typedef struct {
536 PyObject *list;
537 PyObject *sublist;
538 double factor;
539} statscollector_t;
540
541static int statsForSubEntry(rotating_node_t *node, void *arg)
542{
543 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
544 statscollector_t *collect = (statscollector_t*) arg;
545 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
546 int err;
547 PyObject *sinfo;
548 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
549 "((Olldd))",
550 entry->userObj,
551 sentry->callcount,
552 sentry->recursivecallcount,
553 collect->factor * sentry->tt,
554 collect->factor * sentry->it);
555 if (sinfo == NULL)
556 return -1;
557 err = PyList_Append(collect->sublist, sinfo);
558 Py_DECREF(sinfo);
559 return err;
560}
561
562static int statsForEntry(rotating_node_t *node, void *arg)
563{
564 ProfilerEntry *entry = (ProfilerEntry*) node;
565 statscollector_t *collect = (statscollector_t*) arg;
566 PyObject *info;
567 int err;
568 if (entry->callcount == 0)
569 return 0; /* skip */
570
571 if (entry->calls != EMPTY_ROTATING_TREE) {
572 collect->sublist = PyList_New(0);
573 if (collect->sublist == NULL)
574 return -1;
575 if (RotatingTree_Enum(entry->calls,
576 statsForSubEntry, collect) != 0) {
577 Py_DECREF(collect->sublist);
578 return -1;
579 }
580 }
581 else {
582 Py_INCREF(Py_None);
583 collect->sublist = Py_None;
584 }
585
586 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
587 "((OllddO))",
588 entry->userObj,
589 entry->callcount,
590 entry->recursivecallcount,
591 collect->factor * entry->tt,
592 collect->factor * entry->it,
593 collect->sublist);
594 Py_DECREF(collect->sublist);
595 if (info == NULL)
596 return -1;
597 err = PyList_Append(collect->list, info);
598 Py_DECREF(info);
599 return err;
600}
601
602PyDoc_STRVAR(getstats_doc, "\
603getstats() -> list of profiler_entry objects\n\
604\n\
605Return all information collected by the profiler.\n\
606Each profiler_entry is a tuple-like object with the\n\
607following attributes:\n\
608\n\
609 code code object\n\
610 callcount how many times this was called\n\
611 reccallcount how many times called recursively\n\
612 totaltime total time in this entry\n\
613 inlinetime inline time in this entry (not in subcalls)\n\
614 calls details of the calls\n\
615\n\
616The calls attribute is either None or a list of\n\
617profiler_subentry objects:\n\
618\n\
619 code called code object\n\
620 callcount how many times this is called\n\
621 reccallcount how many times this is called recursively\n\
622 totaltime total time spent in this call\n\
623 inlinetime inline time (not in further subcalls)\n\
624");
625
626static PyObject*
627profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
628{
629 statscollector_t collect;
630 if (pending_exception(pObj))
631 return NULL;
632 if (!pObj->externalTimer)
633 collect.factor = hpTimerUnit();
634 else if (pObj->externalTimerUnit > 0.0)
635 collect.factor = pObj->externalTimerUnit;
636 else
637 collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
638 collect.list = PyList_New(0);
639 if (collect.list == NULL)
640 return NULL;
641 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
642 != 0) {
643 Py_DECREF(collect.list);
644 return NULL;
645 }
646 return collect.list;
647}
648
649static int
650setSubcalls(ProfilerObject *pObj, int nvalue)
651{
652 if (nvalue == 0)
653 pObj->flags &= ~POF_SUBCALLS;
654 else if (nvalue > 0)
655 pObj->flags |= POF_SUBCALLS;
656 return 0;
657}
658
659static int
660setBuiltins(ProfilerObject *pObj, int nvalue)
661{
662 if (nvalue == 0)
663 pObj->flags &= ~POF_BUILTINS;
664 else if (nvalue > 0) {
665#ifndef PyTrace_C_CALL
666 PyErr_SetString(PyExc_ValueError,
667 "builtins=True requires Python >= 2.4");
668 return -1;
669#else
670 pObj->flags |= POF_BUILTINS;
671#endif
672 }
673 return 0;
674}
675
676PyDoc_STRVAR(enable_doc, "\
677enable(subcalls=True, builtins=True)\n\
678\n\
679Start collecting profiling information.\n\
680If 'subcalls' is True, also records for each function\n\
681statistics separated according to its current caller.\n\
682If 'builtins' is True, records the time spent in\n\
683built-in functions separately from their caller.\n\
684");
685
686static PyObject*
687profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
688{
689 int subcalls = -1;
690 int builtins = -1;
Martin v. Löwis15e62742006-02-27 16:46:16 +0000691 static char *kwlist[] = {"subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000692 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
693 kwlist, &subcalls, &builtins))
694 return NULL;
695 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
696 return NULL;
697 PyEval_SetProfile(profiler_callback, (PyObject*)self);
698 self->flags |= POF_ENABLED;
699 Py_INCREF(Py_None);
700 return Py_None;
701}
702
703static void
704flush_unmatched(ProfilerObject *pObj)
705{
706 while (pObj->currentProfilerContext) {
707 ProfilerContext *pContext = pObj->currentProfilerContext;
708 ProfilerEntry *profEntry= pContext->ctxEntry;
709 if (profEntry)
710 Stop(pObj, pContext, profEntry);
711 else
712 pObj->currentProfilerContext = pContext->previous;
713 if (pContext)
714 free(pContext);
715 }
716
717}
718
719PyDoc_STRVAR(disable_doc, "\
720disable()\n\
721\n\
722Stop collecting profiling information.\n\
723");
724
725static PyObject*
726profiler_disable(ProfilerObject *self, PyObject* noarg)
727{
728 self->flags &= ~POF_ENABLED;
729 PyEval_SetProfile(NULL, NULL);
730 flush_unmatched(self);
731 if (pending_exception(self))
732 return NULL;
733 Py_INCREF(Py_None);
734 return Py_None;
735}
736
737PyDoc_STRVAR(clear_doc, "\
738clear()\n\
739\n\
740Clear all profiling information collected so far.\n\
741");
742
743static PyObject*
744profiler_clear(ProfilerObject *pObj, PyObject* noarg)
745{
746 clearEntries(pObj);
747 Py_INCREF(Py_None);
748 return Py_None;
749}
750
751static void
752profiler_dealloc(ProfilerObject *op)
753{
754 if (op->flags & POF_ENABLED)
755 PyEval_SetProfile(NULL, NULL);
756 flush_unmatched(op);
757 clearEntries(op);
758 Py_XDECREF(op->externalTimer);
Christian Heimes90aa7642007-12-19 02:45:37 +0000759 Py_TYPE(op)->tp_free(op);
Armin Rigoa871ef22006-02-08 12:53:56 +0000760}
761
762static int
763profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
764{
765 PyObject *o;
766 PyObject *timer = NULL;
767 double timeunit = 0.0;
768 int subcalls = 1;
769#ifdef PyTrace_C_CALL
770 int builtins = 1;
771#else
772 int builtins = 0;
773#endif
Martin v. Löwis15e62742006-02-27 16:46:16 +0000774 static char *kwlist[] = {"timer", "timeunit",
Armin Rigoa871ef22006-02-08 12:53:56 +0000775 "subcalls", "builtins", 0};
776
777 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
778 &timer, &timeunit,
779 &subcalls, &builtins))
780 return -1;
781
782 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
783 return -1;
784 o = pObj->externalTimer;
785 pObj->externalTimer = timer;
786 Py_XINCREF(timer);
787 Py_XDECREF(o);
788 pObj->externalTimerUnit = timeunit;
789 return 0;
790}
791
792static PyMethodDef profiler_methods[] = {
793 {"getstats", (PyCFunction)profiler_getstats,
794 METH_NOARGS, getstats_doc},
795 {"enable", (PyCFunction)profiler_enable,
796 METH_VARARGS | METH_KEYWORDS, enable_doc},
797 {"disable", (PyCFunction)profiler_disable,
798 METH_NOARGS, disable_doc},
799 {"clear", (PyCFunction)profiler_clear,
800 METH_NOARGS, clear_doc},
801 {NULL, NULL}
802};
803
804PyDoc_STRVAR(profiler_doc, "\
805Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
806\n\
807 Builds a profiler object using the specified timer function.\n\
808 The default timer is a fast built-in one based on real time.\n\
809 For custom timer functions returning integers, time_unit can\n\
810 be a float specifying a scale (i.e. how long each integer unit\n\
811 is, in seconds).\n\
812");
813
Neal Norwitz227b5332006-03-22 09:28:35 +0000814static PyTypeObject PyProfiler_Type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000815 PyVarObject_HEAD_INIT(NULL, 0)
Armin Rigoa871ef22006-02-08 12:53:56 +0000816 "_lsprof.Profiler", /* tp_name */
817 sizeof(ProfilerObject), /* tp_basicsize */
818 0, /* tp_itemsize */
819 (destructor)profiler_dealloc, /* tp_dealloc */
820 0, /* tp_print */
821 0, /* tp_getattr */
822 0, /* tp_setattr */
823 0, /* tp_compare */
824 0, /* tp_repr */
825 0, /* tp_as_number */
826 0, /* tp_as_sequence */
827 0, /* tp_as_mapping */
828 0, /* tp_hash */
829 0, /* tp_call */
830 0, /* tp_str */
831 0, /* tp_getattro */
832 0, /* tp_setattro */
833 0, /* tp_as_buffer */
834 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
835 profiler_doc, /* tp_doc */
836 0, /* tp_traverse */
837 0, /* tp_clear */
838 0, /* tp_richcompare */
839 0, /* tp_weaklistoffset */
840 0, /* tp_iter */
841 0, /* tp_iternext */
842 profiler_methods, /* tp_methods */
843 0, /* tp_members */
844 0, /* tp_getset */
845 0, /* tp_base */
846 0, /* tp_dict */
847 0, /* tp_descr_get */
848 0, /* tp_descr_set */
849 0, /* tp_dictoffset */
850 (initproc)profiler_init, /* tp_init */
851 PyType_GenericAlloc, /* tp_alloc */
852 PyType_GenericNew, /* tp_new */
853 PyObject_Del, /* tp_free */
854};
855
856static PyMethodDef moduleMethods[] = {
857 {NULL, NULL}
858};
859
Martin v. Löwis1a214512008-06-11 05:26:20 +0000860
861static struct PyModuleDef _lsprofmodule = {
862 PyModuleDef_HEAD_INIT,
863 "_lsprof",
864 "Fast profiler",
865 -1,
866 moduleMethods,
867 NULL,
868 NULL,
869 NULL,
870 NULL
871};
872
Armin Rigoa871ef22006-02-08 12:53:56 +0000873PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000874PyInit__lsprof(void)
Armin Rigoa871ef22006-02-08 12:53:56 +0000875{
876 PyObject *module, *d;
Martin v. Löwis1a214512008-06-11 05:26:20 +0000877 module = PyModule_Create(&_lsprofmodule);
Neal Norwitz60da3162006-03-07 04:48:24 +0000878 if (module == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +0000879 return NULL;
Armin Rigoa871ef22006-02-08 12:53:56 +0000880 d = PyModule_GetDict(module);
881 if (PyType_Ready(&PyProfiler_Type) < 0)
Martin v. Löwis1a214512008-06-11 05:26:20 +0000882 return NULL;
Armin Rigoa871ef22006-02-08 12:53:56 +0000883 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
884
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000885 if (!initialized) {
886 PyStructSequence_InitType(&StatsEntryType,
887 &profiler_entry_desc);
888 PyStructSequence_InitType(&StatsSubEntryType,
889 &profiler_subentry_desc);
890 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000891 Py_INCREF((PyObject*) &StatsEntryType);
892 Py_INCREF((PyObject*) &StatsSubEntryType);
893 PyModule_AddObject(module, "profiler_entry",
894 (PyObject*) &StatsEntryType);
895 PyModule_AddObject(module, "profiler_subentry",
896 (PyObject*) &StatsSubEntryType);
897 empty_tuple = PyTuple_New(0);
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000898 initialized = 1;
Martin v. Löwis1a214512008-06-11 05:26:20 +0000899 return module;
Armin Rigoa871ef22006-02-08 12:53:56 +0000900}