blob: b0a226bfebeb252a8cdb2d3e2d9ac7294f21f9a1 [file] [log] [blame]
Armin Rigoa871ef22006-02-08 12:53:56 +00001#include "Python.h"
Armin Rigoa871ef22006-02-08 12:53:56 +00002#include "frameobject.h"
Armin Rigoa871ef22006-02-08 12:53:56 +00003#include "rotatingtree.h"
4
5#if !defined(HAVE_LONG_LONG)
6#error "This module requires long longs!"
7#endif
8
9/*** Selection of a high-precision timer ***/
10
11#ifdef MS_WINDOWS
12
13#include <windows.h>
14
15static PY_LONG_LONG
16hpTimer(void)
17{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000018 LARGE_INTEGER li;
19 QueryPerformanceCounter(&li);
20 return li.QuadPart;
Armin Rigoa871ef22006-02-08 12:53:56 +000021}
22
23static double
24hpTimerUnit(void)
25{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000026 LARGE_INTEGER li;
27 if (QueryPerformanceFrequency(&li))
28 return 1.0 / li.QuadPart;
29 else
30 return 0.000001; /* unlikely */
Armin Rigoa871ef22006-02-08 12:53:56 +000031}
32
33#else /* !MS_WINDOWS */
34
35#ifndef HAVE_GETTIMEOFDAY
36#error "This module requires gettimeofday() on non-Windows platforms!"
37#endif
38
39#if (defined(PYOS_OS2) && defined(PYCC_GCC))
40#include <sys/time.h>
41#else
42#include <sys/resource.h>
43#include <sys/times.h>
44#endif
45
46static PY_LONG_LONG
47hpTimer(void)
48{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000049 struct timeval tv;
50 PY_LONG_LONG ret;
Armin Rigoa871ef22006-02-08 12:53:56 +000051#ifdef GETTIMEOFDAY_NO_TZ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000052 gettimeofday(&tv);
Armin Rigoa871ef22006-02-08 12:53:56 +000053#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000054 gettimeofday(&tv, (struct timezone *)NULL);
Armin Rigoa871ef22006-02-08 12:53:56 +000055#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000056 ret = tv.tv_sec;
57 ret = ret * 1000000 + tv.tv_usec;
58 return ret;
Armin Rigoa871ef22006-02-08 12:53:56 +000059}
60
61static double
62hpTimerUnit(void)
63{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000064 return 0.000001;
Armin Rigoa871ef22006-02-08 12:53:56 +000065}
66
67#endif /* MS_WINDOWS */
68
69/************************************************************/
70/* Written by Brett Rosen and Ted Czotter */
71
72struct _ProfilerEntry;
73
74/* represents a function called from another function */
75typedef struct _ProfilerSubEntry {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000076 rotating_node_t header;
77 PY_LONG_LONG tt;
78 PY_LONG_LONG it;
79 long callcount;
80 long recursivecallcount;
81 long recursionLevel;
Armin Rigoa871ef22006-02-08 12:53:56 +000082} ProfilerSubEntry;
83
84/* represents a function or user defined block */
85typedef struct _ProfilerEntry {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000086 rotating_node_t header;
87 PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
88 PY_LONG_LONG tt; /* total time in this entry */
89 PY_LONG_LONG it; /* inline time in this entry (not in subcalls) */
90 long callcount; /* how many times this was called */
91 long recursivecallcount; /* how many times called recursively */
92 long recursionLevel;
93 rotating_node_t *calls;
Armin Rigoa871ef22006-02-08 12:53:56 +000094} ProfilerEntry;
95
96typedef struct _ProfilerContext {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000097 PY_LONG_LONG t0;
98 PY_LONG_LONG subt;
99 struct _ProfilerContext *previous;
100 ProfilerEntry *ctxEntry;
Armin Rigoa871ef22006-02-08 12:53:56 +0000101} ProfilerContext;
102
103typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 PyObject_HEAD
105 rotating_node_t *profilerEntries;
106 ProfilerContext *currentProfilerContext;
107 ProfilerContext *freelistProfilerContext;
108 int flags;
109 PyObject *externalTimer;
110 double externalTimerUnit;
Armin Rigoa871ef22006-02-08 12:53:56 +0000111} ProfilerObject;
112
113#define POF_ENABLED 0x001
114#define POF_SUBCALLS 0x002
115#define POF_BUILTINS 0x004
116#define POF_NOMEMORY 0x100
117
Neal Norwitz227b5332006-03-22 09:28:35 +0000118static PyTypeObject PyProfiler_Type;
Armin Rigoa871ef22006-02-08 12:53:56 +0000119
120#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
Christian Heimes90aa7642007-12-19 02:45:37 +0000121#define PyProfiler_CheckExact(op) (Py_TYPE(op) == &PyProfiler_Type)
Armin Rigoa871ef22006-02-08 12:53:56 +0000122
123/*** External Timers ***/
124
125#define DOUBLE_TIMER_PRECISION 4294967296.0
126static PyObject *empty_tuple;
127
128static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj)
129{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000130 PY_LONG_LONG result;
131 PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL);
132 if (o == NULL) {
133 PyErr_WriteUnraisable(pObj->externalTimer);
134 return 0;
135 }
136 if (pObj->externalTimerUnit > 0.0) {
137 /* interpret the result as an integer that will be scaled
138 in profiler_getstats() */
139 result = PyLong_AsLongLong(o);
140 }
141 else {
142 /* interpret the result as a double measured in seconds.
143 As the profiler works with PY_LONG_LONG internally
144 we convert it to a large integer */
145 double val = PyFloat_AsDouble(o);
146 /* error handling delayed to the code below */
147 result = (PY_LONG_LONG) (val * DOUBLE_TIMER_PRECISION);
148 }
149 Py_DECREF(o);
150 if (PyErr_Occurred()) {
151 PyErr_WriteUnraisable(pObj->externalTimer);
152 return 0;
153 }
154 return result;
Armin Rigoa871ef22006-02-08 12:53:56 +0000155}
156
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000157#define CALL_TIMER(pObj) ((pObj)->externalTimer ? \
158 CallExternalTimer(pObj) : \
159 hpTimer())
Armin Rigoa871ef22006-02-08 12:53:56 +0000160
161/*** ProfilerObject ***/
162
163static PyObject *
164normalizeUserObj(PyObject *obj)
165{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000166 PyCFunctionObject *fn;
167 if (!PyCFunction_Check(obj)) {
168 Py_INCREF(obj);
169 return obj;
170 }
171 /* Replace built-in function objects with a descriptive string
172 because of built-in methods -- keeping a reference to
173 __self__ is probably not a good idea. */
174 fn = (PyCFunctionObject *)obj;
Armin Rigoa871ef22006-02-08 12:53:56 +0000175
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000176 if (fn->m_self == NULL) {
177 /* built-in function: look up the module name */
178 PyObject *mod = fn->m_module;
Victor Stinner7edb5df2011-06-20 14:59:53 +0200179 PyObject *modname = NULL;
180 if (mod != NULL) {
181 if (PyUnicode_Check(mod)) {
182 modname = mod;
183 Py_INCREF(modname);
184 }
185 else if (PyModule_Check(mod)) {
186 modname = PyModule_GetNameObject(mod);
187 if (modname == NULL)
188 PyErr_Clear();
Alexander Belopolskye239d232010-12-08 23:31:48 +0000189 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000190 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200191 if (modname != NULL) {
192 if (PyUnicode_CompareWithASCIIString(modname, "builtins") != 0) {
193 PyObject *result;
194 result = PyUnicode_FromFormat("<%U.%s>", modname,
195 fn->m_ml->ml_name);
196 Py_DECREF(modname);
197 return result;
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000198 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200199 Py_DECREF(modname);
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000200 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200201 return PyUnicode_FromFormat("<%s>", fn->m_ml->ml_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000202 }
203 else {
204 /* built-in method: try to return
205 repr(getattr(type(__self__), __name__))
206 */
207 PyObject *self = fn->m_self;
208 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
209 if (name != NULL) {
210 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
211 Py_XINCREF(mo);
212 Py_DECREF(name);
213 if (mo != NULL) {
214 PyObject *res = PyObject_Repr(mo);
215 Py_DECREF(mo);
216 if (res != NULL)
217 return res;
218 }
219 }
220 PyErr_Clear();
221 return PyUnicode_FromFormat("<built-in method %s>",
222 fn->m_ml->ml_name);
223 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000224}
225
226static ProfilerEntry*
227newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
228{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000229 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000252}
253
254static ProfilerEntry*
255getEntry(ProfilerObject *pObj, void *key)
256{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000257 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
Armin Rigoa871ef22006-02-08 12:53:56 +0000258}
259
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000260static ProfilerSubEntry *
Armin Rigoa871ef22006-02-08 12:53:56 +0000261getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
262{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
264 (void *)entry);
Armin Rigoa871ef22006-02-08 12:53:56 +0000265}
266
267static ProfilerSubEntry *
268newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
269{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000270 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000284}
285
286static int freeSubEntry(rotating_node_t *header, void *arg)
287{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000288 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
289 free(subentry);
290 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000291}
292
293static int freeEntry(rotating_node_t *header, void *arg)
294{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000295 ProfilerEntry *entry = (ProfilerEntry*) header;
296 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
297 Py_DECREF(entry->userObj);
298 free(entry);
299 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000300}
301
302static void clearEntries(ProfilerObject *pObj)
303{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000304 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
305 pObj->profilerEntries = EMPTY_ROTATING_TREE;
306 /* release the memory hold by the ProfilerContexts */
307 if (pObj->currentProfilerContext) {
308 free(pObj->currentProfilerContext);
309 pObj->currentProfilerContext = NULL;
310 }
311 while (pObj->freelistProfilerContext) {
312 ProfilerContext *c = pObj->freelistProfilerContext;
313 pObj->freelistProfilerContext = c->previous;
314 free(c);
315 }
316 pObj->freelistProfilerContext = NULL;
Armin Rigoa871ef22006-02-08 12:53:56 +0000317}
318
319static void
320initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
321{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000322 self->ctxEntry = entry;
323 self->subt = 0;
324 self->previous = pObj->currentProfilerContext;
325 pObj->currentProfilerContext = self;
326 ++entry->recursionLevel;
327 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
328 /* find or create an entry for me in my caller's entry */
329 ProfilerEntry *caller = self->previous->ctxEntry;
330 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
331 if (subentry == NULL)
332 subentry = newSubEntry(pObj, caller, entry);
333 if (subentry)
334 ++subentry->recursionLevel;
335 }
336 self->t0 = CALL_TIMER(pObj);
Armin Rigoa871ef22006-02-08 12:53:56 +0000337}
338
339static void
340Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
341{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000342 PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0;
343 PY_LONG_LONG it = tt - self->subt;
344 if (self->previous)
345 self->previous->subt += tt;
346 pObj->currentProfilerContext = self->previous;
347 if (--entry->recursionLevel == 0)
348 entry->tt += tt;
349 else
350 ++entry->recursivecallcount;
351 entry->it += it;
352 entry->callcount++;
353 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
354 /* find or create an entry for me in my caller's entry */
355 ProfilerEntry *caller = self->previous->ctxEntry;
356 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
357 if (subentry) {
358 if (--subentry->recursionLevel == 0)
359 subentry->tt += tt;
360 else
361 ++subentry->recursivecallcount;
362 subentry->it += it;
363 ++subentry->callcount;
364 }
365 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000366}
367
368static void
369ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
370{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000371 /* entering a call to the function identified by 'key'
372 (which can be a PyCodeObject or a PyMethodDef pointer) */
373 ProfilerObject *pObj = (ProfilerObject*)self;
374 ProfilerEntry *profEntry;
375 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000376
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000377 /* In the case of entering a generator expression frame via a
378 * throw (gen_send_ex(.., 1)), we may already have an
379 * Exception set here. We must not mess around with this
380 * exception, and some of the code under here assumes that
381 * PyErr_* is its own to mess around with, so we have to
382 * save and restore any current exception. */
383 PyObject *last_type, *last_value, *last_tb;
384 PyErr_Fetch(&last_type, &last_value, &last_tb);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000385
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000386 profEntry = getEntry(pObj, key);
387 if (profEntry == NULL) {
388 profEntry = newProfilerEntry(pObj, key, userObj);
389 if (profEntry == NULL)
390 goto restorePyerr;
391 }
392 /* grab a ProfilerContext out of the free list */
393 pContext = pObj->freelistProfilerContext;
394 if (pContext) {
395 pObj->freelistProfilerContext = pContext->previous;
396 }
397 else {
398 /* free list exhausted, allocate a new one */
399 pContext = (ProfilerContext*)
400 malloc(sizeof(ProfilerContext));
401 if (pContext == NULL) {
402 pObj->flags |= POF_NOMEMORY;
403 goto restorePyerr;
404 }
405 }
406 initContext(pObj, pContext, profEntry);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000407
408restorePyerr:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000409 PyErr_Restore(last_type, last_value, last_tb);
Armin Rigoa871ef22006-02-08 12:53:56 +0000410}
411
412static void
413ptrace_leave_call(PyObject *self, void *key)
414{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000415 /* leaving a call to the function identified by 'key' */
416 ProfilerObject *pObj = (ProfilerObject*)self;
417 ProfilerEntry *profEntry;
418 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000419
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000420 pContext = pObj->currentProfilerContext;
421 if (pContext == NULL)
422 return;
423 profEntry = getEntry(pObj, key);
424 if (profEntry) {
425 Stop(pObj, pContext, profEntry);
426 }
427 else {
428 pObj->currentProfilerContext = pContext->previous;
429 }
430 /* put pContext into the free list */
431 pContext->previous = pObj->freelistProfilerContext;
432 pObj->freelistProfilerContext = pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000433}
434
435static int
436profiler_callback(PyObject *self, PyFrameObject *frame, int what,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000437 PyObject *arg)
Armin Rigoa871ef22006-02-08 12:53:56 +0000438{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000439 switch (what) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000440
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000441 /* the 'frame' of a called function is about to start its execution */
442 case PyTrace_CALL:
443 ptrace_enter_call(self, (void *)frame->f_code,
444 (PyObject *)frame->f_code);
445 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000446
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000447 /* the 'frame' of a called function is about to finish
448 (either normally or with an exception) */
449 case PyTrace_RETURN:
450 ptrace_leave_call(self, (void *)frame->f_code);
451 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000452
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000453 /* case PyTrace_EXCEPTION:
454 If the exception results in the function exiting, a
455 PyTrace_RETURN event will be generated, so we don't need to
456 handle it. */
Armin Rigoa871ef22006-02-08 12:53:56 +0000457
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000458#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */
459 /* the Python function 'frame' is issuing a call to the built-in
460 function 'arg' */
461 case PyTrace_C_CALL:
462 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
463 && PyCFunction_Check(arg)) {
464 ptrace_enter_call(self,
465 ((PyCFunctionObject *)arg)->m_ml,
466 arg);
467 }
468 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000469
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000470 /* the call to the built-in function 'arg' is returning into its
471 caller 'frame' */
472 case PyTrace_C_RETURN: /* ...normally */
473 case PyTrace_C_EXCEPTION: /* ...with an exception set */
474 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
475 && PyCFunction_Check(arg)) {
476 ptrace_leave_call(self,
477 ((PyCFunctionObject *)arg)->m_ml);
478 }
479 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000480#endif
481
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000482 default:
483 break;
484 }
485 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000486}
487
488static int
489pending_exception(ProfilerObject *pObj)
490{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000491 if (pObj->flags & POF_NOMEMORY) {
492 pObj->flags -= POF_NOMEMORY;
493 PyErr_SetString(PyExc_MemoryError,
494 "memory was exhausted while profiling");
495 return -1;
496 }
497 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000498}
499
500/************************************************************/
501
502static PyStructSequence_Field profiler_entry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000503 {"code", "code object or built-in function name"},
504 {"callcount", "how many times this was called"},
505 {"reccallcount", "how many times called recursively"},
506 {"totaltime", "total time in this entry"},
507 {"inlinetime", "inline time in this entry (not in subcalls)"},
508 {"calls", "details of the calls"},
509 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000510};
511
512static PyStructSequence_Field profiler_subentry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000513 {"code", "called code object or built-in function name"},
514 {"callcount", "how many times this is called"},
515 {"reccallcount", "how many times this is called recursively"},
516 {"totaltime", "total time spent in this call"},
517 {"inlinetime", "inline time (not in further subcalls)"},
518 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000519};
520
521static PyStructSequence_Desc profiler_entry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000522 "_lsprof.profiler_entry", /* name */
523 NULL, /* doc */
524 profiler_entry_fields,
525 6
Armin Rigoa871ef22006-02-08 12:53:56 +0000526};
527
528static PyStructSequence_Desc profiler_subentry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000529 "_lsprof.profiler_subentry", /* name */
530 NULL, /* doc */
531 profiler_subentry_fields,
532 5
Armin Rigoa871ef22006-02-08 12:53:56 +0000533};
534
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000535static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000536static PyTypeObject StatsEntryType;
537static PyTypeObject StatsSubEntryType;
538
539
540typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000541 PyObject *list;
542 PyObject *sublist;
543 double factor;
Armin Rigoa871ef22006-02-08 12:53:56 +0000544} statscollector_t;
545
546static int statsForSubEntry(rotating_node_t *node, void *arg)
547{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000548 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
549 statscollector_t *collect = (statscollector_t*) arg;
550 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
551 int err;
552 PyObject *sinfo;
553 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
554 "((Olldd))",
555 entry->userObj,
556 sentry->callcount,
557 sentry->recursivecallcount,
558 collect->factor * sentry->tt,
559 collect->factor * sentry->it);
560 if (sinfo == NULL)
561 return -1;
562 err = PyList_Append(collect->sublist, sinfo);
563 Py_DECREF(sinfo);
564 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000565}
566
567static int statsForEntry(rotating_node_t *node, void *arg)
568{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000569 ProfilerEntry *entry = (ProfilerEntry*) node;
570 statscollector_t *collect = (statscollector_t*) arg;
571 PyObject *info;
572 int err;
573 if (entry->callcount == 0)
574 return 0; /* skip */
Armin Rigoa871ef22006-02-08 12:53:56 +0000575
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000576 if (entry->calls != EMPTY_ROTATING_TREE) {
577 collect->sublist = PyList_New(0);
578 if (collect->sublist == NULL)
579 return -1;
580 if (RotatingTree_Enum(entry->calls,
581 statsForSubEntry, collect) != 0) {
582 Py_DECREF(collect->sublist);
583 return -1;
584 }
585 }
586 else {
587 Py_INCREF(Py_None);
588 collect->sublist = Py_None;
589 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000590
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000591 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
592 "((OllddO))",
593 entry->userObj,
594 entry->callcount,
595 entry->recursivecallcount,
596 collect->factor * entry->tt,
597 collect->factor * entry->it,
598 collect->sublist);
599 Py_DECREF(collect->sublist);
600 if (info == NULL)
601 return -1;
602 err = PyList_Append(collect->list, info);
603 Py_DECREF(info);
604 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000605}
606
607PyDoc_STRVAR(getstats_doc, "\
608getstats() -> list of profiler_entry objects\n\
609\n\
610Return all information collected by the profiler.\n\
611Each profiler_entry is a tuple-like object with the\n\
612following attributes:\n\
613\n\
614 code code object\n\
615 callcount how many times this was called\n\
616 reccallcount how many times called recursively\n\
617 totaltime total time in this entry\n\
618 inlinetime inline time in this entry (not in subcalls)\n\
619 calls details of the calls\n\
620\n\
621The calls attribute is either None or a list of\n\
622profiler_subentry objects:\n\
623\n\
624 code called code object\n\
625 callcount how many times this is called\n\
626 reccallcount how many times this is called recursively\n\
627 totaltime total time spent in this call\n\
628 inlinetime inline time (not in further subcalls)\n\
629");
630
631static PyObject*
632profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
633{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000634 statscollector_t collect;
635 if (pending_exception(pObj))
636 return NULL;
637 if (!pObj->externalTimer)
638 collect.factor = hpTimerUnit();
639 else if (pObj->externalTimerUnit > 0.0)
640 collect.factor = pObj->externalTimerUnit;
641 else
642 collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
643 collect.list = PyList_New(0);
644 if (collect.list == NULL)
645 return NULL;
646 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
647 != 0) {
648 Py_DECREF(collect.list);
649 return NULL;
650 }
651 return collect.list;
Armin Rigoa871ef22006-02-08 12:53:56 +0000652}
653
654static int
655setSubcalls(ProfilerObject *pObj, int nvalue)
656{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000657 if (nvalue == 0)
658 pObj->flags &= ~POF_SUBCALLS;
659 else if (nvalue > 0)
660 pObj->flags |= POF_SUBCALLS;
661 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000662}
663
664static int
665setBuiltins(ProfilerObject *pObj, int nvalue)
666{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000667 if (nvalue == 0)
668 pObj->flags &= ~POF_BUILTINS;
669 else if (nvalue > 0) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000670#ifndef PyTrace_C_CALL
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000671 PyErr_SetString(PyExc_ValueError,
672 "builtins=True requires Python >= 2.4");
673 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000674#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000675 pObj->flags |= POF_BUILTINS;
Armin Rigoa871ef22006-02-08 12:53:56 +0000676#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000677 }
678 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000679}
680
681PyDoc_STRVAR(enable_doc, "\
682enable(subcalls=True, builtins=True)\n\
683\n\
684Start collecting profiling information.\n\
685If 'subcalls' is True, also records for each function\n\
686statistics separated according to its current caller.\n\
687If 'builtins' is True, records the time spent in\n\
688built-in functions separately from their caller.\n\
689");
690
691static PyObject*
692profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
693{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000694 int subcalls = -1;
695 int builtins = -1;
696 static char *kwlist[] = {"subcalls", "builtins", 0};
697 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
698 kwlist, &subcalls, &builtins))
699 return NULL;
700 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
701 return NULL;
702 PyEval_SetProfile(profiler_callback, (PyObject*)self);
703 self->flags |= POF_ENABLED;
704 Py_INCREF(Py_None);
705 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000706}
707
708static void
709flush_unmatched(ProfilerObject *pObj)
710{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000711 while (pObj->currentProfilerContext) {
712 ProfilerContext *pContext = pObj->currentProfilerContext;
713 ProfilerEntry *profEntry= pContext->ctxEntry;
714 if (profEntry)
715 Stop(pObj, pContext, profEntry);
716 else
717 pObj->currentProfilerContext = pContext->previous;
718 if (pContext)
719 free(pContext);
720 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000721
722}
723
724PyDoc_STRVAR(disable_doc, "\
725disable()\n\
726\n\
727Stop collecting profiling information.\n\
728");
729
730static PyObject*
731profiler_disable(ProfilerObject *self, PyObject* noarg)
732{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000733 self->flags &= ~POF_ENABLED;
734 PyEval_SetProfile(NULL, NULL);
735 flush_unmatched(self);
736 if (pending_exception(self))
737 return NULL;
738 Py_INCREF(Py_None);
739 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000740}
741
742PyDoc_STRVAR(clear_doc, "\
743clear()\n\
744\n\
745Clear all profiling information collected so far.\n\
746");
747
748static PyObject*
749profiler_clear(ProfilerObject *pObj, PyObject* noarg)
750{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000751 clearEntries(pObj);
752 Py_INCREF(Py_None);
753 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000754}
755
756static void
757profiler_dealloc(ProfilerObject *op)
758{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000759 if (op->flags & POF_ENABLED)
760 PyEval_SetProfile(NULL, NULL);
761 flush_unmatched(op);
762 clearEntries(op);
763 Py_XDECREF(op->externalTimer);
764 Py_TYPE(op)->tp_free(op);
Armin Rigoa871ef22006-02-08 12:53:56 +0000765}
766
767static int
768profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
769{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000770 PyObject *o;
771 PyObject *timer = NULL;
772 double timeunit = 0.0;
773 int subcalls = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000774#ifdef PyTrace_C_CALL
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000775 int builtins = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000776#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000777 int builtins = 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000778#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000779 static char *kwlist[] = {"timer", "timeunit",
780 "subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000781
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000782 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
783 &timer, &timeunit,
784 &subcalls, &builtins))
785 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000786
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000787 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
788 return -1;
789 o = pObj->externalTimer;
790 pObj->externalTimer = timer;
791 Py_XINCREF(timer);
792 Py_XDECREF(o);
793 pObj->externalTimerUnit = timeunit;
794 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000795}
796
797static PyMethodDef profiler_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000798 {"getstats", (PyCFunction)profiler_getstats,
799 METH_NOARGS, getstats_doc},
800 {"enable", (PyCFunction)profiler_enable,
801 METH_VARARGS | METH_KEYWORDS, enable_doc},
802 {"disable", (PyCFunction)profiler_disable,
803 METH_NOARGS, disable_doc},
804 {"clear", (PyCFunction)profiler_clear,
805 METH_NOARGS, clear_doc},
806 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000807};
808
809PyDoc_STRVAR(profiler_doc, "\
810Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
811\n\
812 Builds a profiler object using the specified timer function.\n\
813 The default timer is a fast built-in one based on real time.\n\
814 For custom timer functions returning integers, time_unit can\n\
815 be a float specifying a scale (i.e. how long each integer unit\n\
816 is, in seconds).\n\
817");
818
Neal Norwitz227b5332006-03-22 09:28:35 +0000819static PyTypeObject PyProfiler_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000820 PyVarObject_HEAD_INIT(NULL, 0)
821 "_lsprof.Profiler", /* tp_name */
822 sizeof(ProfilerObject), /* tp_basicsize */
823 0, /* tp_itemsize */
824 (destructor)profiler_dealloc, /* tp_dealloc */
825 0, /* tp_print */
826 0, /* tp_getattr */
827 0, /* tp_setattr */
828 0, /* tp_reserved */
829 0, /* tp_repr */
830 0, /* tp_as_number */
831 0, /* tp_as_sequence */
832 0, /* tp_as_mapping */
833 0, /* tp_hash */
834 0, /* tp_call */
835 0, /* tp_str */
836 0, /* tp_getattro */
837 0, /* tp_setattro */
838 0, /* tp_as_buffer */
839 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
840 profiler_doc, /* tp_doc */
841 0, /* tp_traverse */
842 0, /* tp_clear */
843 0, /* tp_richcompare */
844 0, /* tp_weaklistoffset */
845 0, /* tp_iter */
846 0, /* tp_iternext */
847 profiler_methods, /* tp_methods */
848 0, /* tp_members */
849 0, /* tp_getset */
850 0, /* tp_base */
851 0, /* tp_dict */
852 0, /* tp_descr_get */
853 0, /* tp_descr_set */
854 0, /* tp_dictoffset */
855 (initproc)profiler_init, /* tp_init */
856 PyType_GenericAlloc, /* tp_alloc */
857 PyType_GenericNew, /* tp_new */
858 PyObject_Del, /* tp_free */
Armin Rigoa871ef22006-02-08 12:53:56 +0000859};
860
861static PyMethodDef moduleMethods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000862 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000863};
864
Martin v. Löwis1a214512008-06-11 05:26:20 +0000865
866static struct PyModuleDef _lsprofmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000867 PyModuleDef_HEAD_INIT,
868 "_lsprof",
869 "Fast profiler",
870 -1,
871 moduleMethods,
872 NULL,
873 NULL,
874 NULL,
875 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000876};
877
Armin Rigoa871ef22006-02-08 12:53:56 +0000878PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000879PyInit__lsprof(void)
Armin Rigoa871ef22006-02-08 12:53:56 +0000880{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000881 PyObject *module, *d;
882 module = PyModule_Create(&_lsprofmodule);
883 if (module == NULL)
884 return NULL;
885 d = PyModule_GetDict(module);
886 if (PyType_Ready(&PyProfiler_Type) < 0)
887 return NULL;
888 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
Armin Rigoa871ef22006-02-08 12:53:56 +0000889
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000890 if (!initialized) {
891 PyStructSequence_InitType(&StatsEntryType,
892 &profiler_entry_desc);
893 PyStructSequence_InitType(&StatsSubEntryType,
894 &profiler_subentry_desc);
895 }
896 Py_INCREF((PyObject*) &StatsEntryType);
897 Py_INCREF((PyObject*) &StatsSubEntryType);
898 PyModule_AddObject(module, "profiler_entry",
899 (PyObject*) &StatsEntryType);
900 PyModule_AddObject(module, "profiler_subentry",
901 (PyObject*) &StatsSubEntryType);
902 empty_tuple = PyTuple_New(0);
903 initialized = 1;
904 return module;
Armin Rigoa871ef22006-02-08 12:53:56 +0000905}