blob: a5740e79d7e3228f7f7996f30c9f21709aa001a9 [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
Thomas Wouters89d996e2007-09-08 17:39:28 +0000375 /* In the case of entering a generator expression frame via a
376 * throw (gen_send_ex(.., 1)), we may already have an
377 * Exception set here. We must not mess around with this
378 * exception, and some of the code under here assumes that
379 * PyErr_* is its own to mess around with, so we have to
380 * save and restore any current exception. */
381 PyObject *last_type, *last_value, *last_tb;
382 PyErr_Fetch(&last_type, &last_value, &last_tb);
383
Armin Rigoa871ef22006-02-08 12:53:56 +0000384 profEntry = getEntry(pObj, key);
385 if (profEntry == NULL) {
386 profEntry = newProfilerEntry(pObj, key, userObj);
387 if (profEntry == NULL)
Thomas Wouters89d996e2007-09-08 17:39:28 +0000388 goto restorePyerr;
Armin Rigoa871ef22006-02-08 12:53:56 +0000389 }
390 /* grab a ProfilerContext out of the free list */
391 pContext = pObj->freelistProfilerContext;
392 if (pContext) {
393 pObj->freelistProfilerContext = pContext->previous;
394 }
395 else {
396 /* free list exhausted, allocate a new one */
397 pContext = (ProfilerContext*)
398 malloc(sizeof(ProfilerContext));
399 if (pContext == NULL) {
400 pObj->flags |= POF_NOMEMORY;
Thomas Wouters89d996e2007-09-08 17:39:28 +0000401 goto restorePyerr;
Armin Rigoa871ef22006-02-08 12:53:56 +0000402 }
403 }
404 initContext(pObj, pContext, profEntry);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000405
406restorePyerr:
407 PyErr_Restore(last_type, last_value, last_tb);
Armin Rigoa871ef22006-02-08 12:53:56 +0000408}
409
410static void
411ptrace_leave_call(PyObject *self, void *key)
412{
413 /* leaving a call to the function identified by 'key' */
414 ProfilerObject *pObj = (ProfilerObject*)self;
415 ProfilerEntry *profEntry;
416 ProfilerContext *pContext;
417
418 pContext = pObj->currentProfilerContext;
419 if (pContext == NULL)
420 return;
421 profEntry = getEntry(pObj, key);
422 if (profEntry) {
423 Stop(pObj, pContext, profEntry);
424 }
425 else {
426 pObj->currentProfilerContext = pContext->previous;
427 }
428 /* put pContext into the free list */
429 pContext->previous = pObj->freelistProfilerContext;
430 pObj->freelistProfilerContext = pContext;
431}
432
433static int
434profiler_callback(PyObject *self, PyFrameObject *frame, int what,
435 PyObject *arg)
436{
437 switch (what) {
438
439 /* the 'frame' of a called function is about to start its execution */
440 case PyTrace_CALL:
441 ptrace_enter_call(self, (void *)frame->f_code,
442 (PyObject *)frame->f_code);
443 break;
444
445 /* the 'frame' of a called function is about to finish
446 (either normally or with an exception) */
447 case PyTrace_RETURN:
448 ptrace_leave_call(self, (void *)frame->f_code);
449 break;
450
451 /* case PyTrace_EXCEPTION:
452 If the exception results in the function exiting, a
453 PyTrace_RETURN event will be generated, so we don't need to
454 handle it. */
455
456#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */
457 /* the Python function 'frame' is issuing a call to the built-in
458 function 'arg' */
459 case PyTrace_C_CALL:
460 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
461 && PyCFunction_Check(arg)) {
462 ptrace_enter_call(self,
463 ((PyCFunctionObject *)arg)->m_ml,
464 arg);
465 }
466 break;
467
468 /* the call to the built-in function 'arg' is returning into its
469 caller 'frame' */
470 case PyTrace_C_RETURN: /* ...normally */
471 case PyTrace_C_EXCEPTION: /* ...with an exception set */
472 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
473 && PyCFunction_Check(arg)) {
474 ptrace_leave_call(self,
475 ((PyCFunctionObject *)arg)->m_ml);
476 }
477 break;
478#endif
479
480 default:
481 break;
482 }
483 return 0;
484}
485
486static int
487pending_exception(ProfilerObject *pObj)
488{
489 if (pObj->flags & POF_NOMEMORY) {
490 pObj->flags -= POF_NOMEMORY;
491 PyErr_SetString(PyExc_MemoryError,
492 "memory was exhausted while profiling");
493 return -1;
494 }
495 return 0;
496}
497
498/************************************************************/
499
500static PyStructSequence_Field profiler_entry_fields[] = {
501 {"code", "code object or built-in function name"},
502 {"callcount", "how many times this was called"},
503 {"reccallcount", "how many times called recursively"},
504 {"totaltime", "total time in this entry"},
505 {"inlinetime", "inline time in this entry (not in subcalls)"},
506 {"calls", "details of the calls"},
507 {0}
508};
509
510static PyStructSequence_Field profiler_subentry_fields[] = {
511 {"code", "called code object or built-in function name"},
512 {"callcount", "how many times this is called"},
513 {"reccallcount", "how many times this is called recursively"},
514 {"totaltime", "total time spent in this call"},
515 {"inlinetime", "inline time (not in further subcalls)"},
516 {0}
517};
518
519static PyStructSequence_Desc profiler_entry_desc = {
520 "_lsprof.profiler_entry", /* name */
521 NULL, /* doc */
522 profiler_entry_fields,
523 6
524};
525
526static PyStructSequence_Desc profiler_subentry_desc = {
527 "_lsprof.profiler_subentry", /* name */
528 NULL, /* doc */
529 profiler_subentry_fields,
530 5
531};
532
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000533static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000534static PyTypeObject StatsEntryType;
535static PyTypeObject StatsSubEntryType;
536
537
538typedef struct {
539 PyObject *list;
540 PyObject *sublist;
541 double factor;
542} statscollector_t;
543
544static int statsForSubEntry(rotating_node_t *node, void *arg)
545{
546 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
547 statscollector_t *collect = (statscollector_t*) arg;
548 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
549 int err;
550 PyObject *sinfo;
551 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
552 "((Olldd))",
553 entry->userObj,
554 sentry->callcount,
555 sentry->recursivecallcount,
556 collect->factor * sentry->tt,
557 collect->factor * sentry->it);
558 if (sinfo == NULL)
559 return -1;
560 err = PyList_Append(collect->sublist, sinfo);
561 Py_DECREF(sinfo);
562 return err;
563}
564
565static int statsForEntry(rotating_node_t *node, void *arg)
566{
567 ProfilerEntry *entry = (ProfilerEntry*) node;
568 statscollector_t *collect = (statscollector_t*) arg;
569 PyObject *info;
570 int err;
571 if (entry->callcount == 0)
572 return 0; /* skip */
573
574 if (entry->calls != EMPTY_ROTATING_TREE) {
575 collect->sublist = PyList_New(0);
576 if (collect->sublist == NULL)
577 return -1;
578 if (RotatingTree_Enum(entry->calls,
579 statsForSubEntry, collect) != 0) {
580 Py_DECREF(collect->sublist);
581 return -1;
582 }
583 }
584 else {
585 Py_INCREF(Py_None);
586 collect->sublist = Py_None;
587 }
588
589 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
590 "((OllddO))",
591 entry->userObj,
592 entry->callcount,
593 entry->recursivecallcount,
594 collect->factor * entry->tt,
595 collect->factor * entry->it,
596 collect->sublist);
597 Py_DECREF(collect->sublist);
598 if (info == NULL)
599 return -1;
600 err = PyList_Append(collect->list, info);
601 Py_DECREF(info);
602 return err;
603}
604
605PyDoc_STRVAR(getstats_doc, "\
606getstats() -> list of profiler_entry objects\n\
607\n\
608Return all information collected by the profiler.\n\
609Each profiler_entry is a tuple-like object with the\n\
610following attributes:\n\
611\n\
612 code code object\n\
613 callcount how many times this was called\n\
614 reccallcount how many times called recursively\n\
615 totaltime total time in this entry\n\
616 inlinetime inline time in this entry (not in subcalls)\n\
617 calls details of the calls\n\
618\n\
619The calls attribute is either None or a list of\n\
620profiler_subentry objects:\n\
621\n\
622 code called code object\n\
623 callcount how many times this is called\n\
624 reccallcount how many times this is called recursively\n\
625 totaltime total time spent in this call\n\
626 inlinetime inline time (not in further subcalls)\n\
627");
628
629static PyObject*
630profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
631{
632 statscollector_t collect;
633 if (pending_exception(pObj))
634 return NULL;
635 if (!pObj->externalTimer)
636 collect.factor = hpTimerUnit();
637 else if (pObj->externalTimerUnit > 0.0)
638 collect.factor = pObj->externalTimerUnit;
639 else
640 collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
641 collect.list = PyList_New(0);
642 if (collect.list == NULL)
643 return NULL;
644 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
645 != 0) {
646 Py_DECREF(collect.list);
647 return NULL;
648 }
649 return collect.list;
650}
651
652static int
653setSubcalls(ProfilerObject *pObj, int nvalue)
654{
655 if (nvalue == 0)
656 pObj->flags &= ~POF_SUBCALLS;
657 else if (nvalue > 0)
658 pObj->flags |= POF_SUBCALLS;
659 return 0;
660}
661
662static int
663setBuiltins(ProfilerObject *pObj, int nvalue)
664{
665 if (nvalue == 0)
666 pObj->flags &= ~POF_BUILTINS;
667 else if (nvalue > 0) {
668#ifndef PyTrace_C_CALL
669 PyErr_SetString(PyExc_ValueError,
670 "builtins=True requires Python >= 2.4");
671 return -1;
672#else
673 pObj->flags |= POF_BUILTINS;
674#endif
675 }
676 return 0;
677}
678
679PyDoc_STRVAR(enable_doc, "\
680enable(subcalls=True, builtins=True)\n\
681\n\
682Start collecting profiling information.\n\
683If 'subcalls' is True, also records for each function\n\
684statistics separated according to its current caller.\n\
685If 'builtins' is True, records the time spent in\n\
686built-in functions separately from their caller.\n\
687");
688
689static PyObject*
690profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
691{
692 int subcalls = -1;
693 int builtins = -1;
Martin v. Löwis15e62742006-02-27 16:46:16 +0000694 static char *kwlist[] = {"subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000695 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
696 kwlist, &subcalls, &builtins))
697 return NULL;
698 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
699 return NULL;
700 PyEval_SetProfile(profiler_callback, (PyObject*)self);
701 self->flags |= POF_ENABLED;
702 Py_INCREF(Py_None);
703 return Py_None;
704}
705
706static void
707flush_unmatched(ProfilerObject *pObj)
708{
709 while (pObj->currentProfilerContext) {
710 ProfilerContext *pContext = pObj->currentProfilerContext;
711 ProfilerEntry *profEntry= pContext->ctxEntry;
712 if (profEntry)
713 Stop(pObj, pContext, profEntry);
714 else
715 pObj->currentProfilerContext = pContext->previous;
716 if (pContext)
717 free(pContext);
718 }
719
720}
721
722PyDoc_STRVAR(disable_doc, "\
723disable()\n\
724\n\
725Stop collecting profiling information.\n\
726");
727
728static PyObject*
729profiler_disable(ProfilerObject *self, PyObject* noarg)
730{
731 self->flags &= ~POF_ENABLED;
732 PyEval_SetProfile(NULL, NULL);
733 flush_unmatched(self);
734 if (pending_exception(self))
735 return NULL;
736 Py_INCREF(Py_None);
737 return Py_None;
738}
739
740PyDoc_STRVAR(clear_doc, "\
741clear()\n\
742\n\
743Clear all profiling information collected so far.\n\
744");
745
746static PyObject*
747profiler_clear(ProfilerObject *pObj, PyObject* noarg)
748{
749 clearEntries(pObj);
750 Py_INCREF(Py_None);
751 return Py_None;
752}
753
754static void
755profiler_dealloc(ProfilerObject *op)
756{
757 if (op->flags & POF_ENABLED)
758 PyEval_SetProfile(NULL, NULL);
759 flush_unmatched(op);
760 clearEntries(op);
761 Py_XDECREF(op->externalTimer);
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000762 Py_Type(op)->tp_free(op);
Armin Rigoa871ef22006-02-08 12:53:56 +0000763}
764
765static int
766profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
767{
768 PyObject *o;
769 PyObject *timer = NULL;
770 double timeunit = 0.0;
771 int subcalls = 1;
772#ifdef PyTrace_C_CALL
773 int builtins = 1;
774#else
775 int builtins = 0;
776#endif
Martin v. Löwis15e62742006-02-27 16:46:16 +0000777 static char *kwlist[] = {"timer", "timeunit",
Armin Rigoa871ef22006-02-08 12:53:56 +0000778 "subcalls", "builtins", 0};
779
780 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
781 &timer, &timeunit,
782 &subcalls, &builtins))
783 return -1;
784
785 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
786 return -1;
787 o = pObj->externalTimer;
788 pObj->externalTimer = timer;
789 Py_XINCREF(timer);
790 Py_XDECREF(o);
791 pObj->externalTimerUnit = timeunit;
792 return 0;
793}
794
795static PyMethodDef profiler_methods[] = {
796 {"getstats", (PyCFunction)profiler_getstats,
797 METH_NOARGS, getstats_doc},
798 {"enable", (PyCFunction)profiler_enable,
799 METH_VARARGS | METH_KEYWORDS, enable_doc},
800 {"disable", (PyCFunction)profiler_disable,
801 METH_NOARGS, disable_doc},
802 {"clear", (PyCFunction)profiler_clear,
803 METH_NOARGS, clear_doc},
804 {NULL, NULL}
805};
806
807PyDoc_STRVAR(profiler_doc, "\
808Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
809\n\
810 Builds a profiler object using the specified timer function.\n\
811 The default timer is a fast built-in one based on real time.\n\
812 For custom timer functions returning integers, time_unit can\n\
813 be a float specifying a scale (i.e. how long each integer unit\n\
814 is, in seconds).\n\
815");
816
Neal Norwitz227b5332006-03-22 09:28:35 +0000817static PyTypeObject PyProfiler_Type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000818 PyVarObject_HEAD_INIT(NULL, 0)
Armin Rigoa871ef22006-02-08 12:53:56 +0000819 "_lsprof.Profiler", /* tp_name */
820 sizeof(ProfilerObject), /* tp_basicsize */
821 0, /* tp_itemsize */
822 (destructor)profiler_dealloc, /* tp_dealloc */
823 0, /* tp_print */
824 0, /* tp_getattr */
825 0, /* tp_setattr */
826 0, /* tp_compare */
827 0, /* tp_repr */
828 0, /* tp_as_number */
829 0, /* tp_as_sequence */
830 0, /* tp_as_mapping */
831 0, /* tp_hash */
832 0, /* tp_call */
833 0, /* tp_str */
834 0, /* tp_getattro */
835 0, /* tp_setattro */
836 0, /* tp_as_buffer */
837 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
838 profiler_doc, /* tp_doc */
839 0, /* tp_traverse */
840 0, /* tp_clear */
841 0, /* tp_richcompare */
842 0, /* tp_weaklistoffset */
843 0, /* tp_iter */
844 0, /* tp_iternext */
845 profiler_methods, /* tp_methods */
846 0, /* tp_members */
847 0, /* tp_getset */
848 0, /* tp_base */
849 0, /* tp_dict */
850 0, /* tp_descr_get */
851 0, /* tp_descr_set */
852 0, /* tp_dictoffset */
853 (initproc)profiler_init, /* tp_init */
854 PyType_GenericAlloc, /* tp_alloc */
855 PyType_GenericNew, /* tp_new */
856 PyObject_Del, /* tp_free */
857};
858
859static PyMethodDef moduleMethods[] = {
860 {NULL, NULL}
861};
862
863PyMODINIT_FUNC
864init_lsprof(void)
865{
866 PyObject *module, *d;
867 module = Py_InitModule3("_lsprof", moduleMethods, "Fast profiler");
Neal Norwitz60da3162006-03-07 04:48:24 +0000868 if (module == NULL)
869 return;
Armin Rigoa871ef22006-02-08 12:53:56 +0000870 d = PyModule_GetDict(module);
871 if (PyType_Ready(&PyProfiler_Type) < 0)
872 return;
873 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
874
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000875 if (!initialized) {
876 PyStructSequence_InitType(&StatsEntryType,
877 &profiler_entry_desc);
878 PyStructSequence_InitType(&StatsSubEntryType,
879 &profiler_subentry_desc);
880 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000881 Py_INCREF((PyObject*) &StatsEntryType);
882 Py_INCREF((PyObject*) &StatsSubEntryType);
883 PyModule_AddObject(module, "profiler_entry",
884 (PyObject*) &StatsEntryType);
885 PyModule_AddObject(module, "profiler_subentry",
886 (PyObject*) &StatsSubEntryType);
887 empty_tuple = PyTuple_New(0);
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000888 initialized = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000889}