blob: 048cfc8b74b6012e631f042a6adac5a7a8182635 [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;
179 const char *modname;
180 if (mod && PyUnicode_Check(mod)) {
181 modname = _PyUnicode_AsString(mod);
182 }
183 else if (mod && PyModule_Check(mod)) {
184 modname = PyModule_GetName(mod);
185 if (modname == NULL) {
186 PyErr_Clear();
187 modname = "builtins";
188 }
189 }
190 else {
191 modname = "builtins";
192 }
193 if (strcmp(modname, "builtins") != 0)
194 return PyUnicode_FromFormat("<%s.%s>",
195 modname,
196 fn->m_ml->ml_name);
197 else
198 return PyUnicode_FromFormat("<%s>",
199 fn->m_ml->ml_name);
200 }
201 else {
202 /* built-in method: try to return
203 repr(getattr(type(__self__), __name__))
204 */
205 PyObject *self = fn->m_self;
206 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
207 if (name != NULL) {
208 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
209 Py_XINCREF(mo);
210 Py_DECREF(name);
211 if (mo != NULL) {
212 PyObject *res = PyObject_Repr(mo);
213 Py_DECREF(mo);
214 if (res != NULL)
215 return res;
216 }
217 }
218 PyErr_Clear();
219 return PyUnicode_FromFormat("<built-in method %s>",
220 fn->m_ml->ml_name);
221 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000222}
223
224static ProfilerEntry*
225newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
226{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000227 ProfilerEntry *self;
228 self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry));
229 if (self == NULL) {
230 pObj->flags |= POF_NOMEMORY;
231 return NULL;
232 }
233 userObj = normalizeUserObj(userObj);
234 if (userObj == NULL) {
235 PyErr_Clear();
236 free(self);
237 pObj->flags |= POF_NOMEMORY;
238 return NULL;
239 }
240 self->header.key = key;
241 self->userObj = userObj;
242 self->tt = 0;
243 self->it = 0;
244 self->callcount = 0;
245 self->recursivecallcount = 0;
246 self->recursionLevel = 0;
247 self->calls = EMPTY_ROTATING_TREE;
248 RotatingTree_Add(&pObj->profilerEntries, &self->header);
249 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000250}
251
252static ProfilerEntry*
253getEntry(ProfilerObject *pObj, void *key)
254{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000255 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
Armin Rigoa871ef22006-02-08 12:53:56 +0000256}
257
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000258static ProfilerSubEntry *
Armin Rigoa871ef22006-02-08 12:53:56 +0000259getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
260{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000261 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
262 (void *)entry);
Armin Rigoa871ef22006-02-08 12:53:56 +0000263}
264
265static ProfilerSubEntry *
266newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
267{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000268 ProfilerSubEntry *self;
269 self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry));
270 if (self == NULL) {
271 pObj->flags |= POF_NOMEMORY;
272 return NULL;
273 }
274 self->header.key = (void *)entry;
275 self->tt = 0;
276 self->it = 0;
277 self->callcount = 0;
278 self->recursivecallcount = 0;
279 self->recursionLevel = 0;
280 RotatingTree_Add(&caller->calls, &self->header);
281 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000282}
283
284static int freeSubEntry(rotating_node_t *header, void *arg)
285{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000286 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
287 free(subentry);
288 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000289}
290
291static int freeEntry(rotating_node_t *header, void *arg)
292{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000293 ProfilerEntry *entry = (ProfilerEntry*) header;
294 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
295 Py_DECREF(entry->userObj);
296 free(entry);
297 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000298}
299
300static void clearEntries(ProfilerObject *pObj)
301{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000302 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
303 pObj->profilerEntries = EMPTY_ROTATING_TREE;
304 /* release the memory hold by the ProfilerContexts */
305 if (pObj->currentProfilerContext) {
306 free(pObj->currentProfilerContext);
307 pObj->currentProfilerContext = NULL;
308 }
309 while (pObj->freelistProfilerContext) {
310 ProfilerContext *c = pObj->freelistProfilerContext;
311 pObj->freelistProfilerContext = c->previous;
312 free(c);
313 }
314 pObj->freelistProfilerContext = NULL;
Armin Rigoa871ef22006-02-08 12:53:56 +0000315}
316
317static void
318initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
319{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000320 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);
Armin Rigoa871ef22006-02-08 12:53:56 +0000335}
336
337static void
338Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
339{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000340 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 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000364}
365
366static void
367ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
368{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000369 /* 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000374
Antoine Pitrouf95a1b32010-05-09 15:52:27 +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);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000383
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 profEntry = getEntry(pObj, key);
385 if (profEntry == NULL) {
386 profEntry = newProfilerEntry(pObj, key, userObj);
387 if (profEntry == NULL)
388 goto restorePyerr;
389 }
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;
401 goto restorePyerr;
402 }
403 }
404 initContext(pObj, pContext, profEntry);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000405
406restorePyerr:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000407 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{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000413 /* leaving a call to the function identified by 'key' */
414 ProfilerObject *pObj = (ProfilerObject*)self;
415 ProfilerEntry *profEntry;
416 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000417
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000418 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000431}
432
433static int
434profiler_callback(PyObject *self, PyFrameObject *frame, int what,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000435 PyObject *arg)
Armin Rigoa871ef22006-02-08 12:53:56 +0000436{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000437 switch (what) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000438
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000439 /* 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000444
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000445 /* 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000450
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000451 /* 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. */
Armin Rigoa871ef22006-02-08 12:53:56 +0000455
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000456#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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000467
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000468 /* 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000478#endif
479
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000480 default:
481 break;
482 }
483 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000484}
485
486static int
487pending_exception(ProfilerObject *pObj)
488{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000489 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000496}
497
498/************************************************************/
499
500static PyStructSequence_Field profiler_entry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000501 {"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}
Armin Rigoa871ef22006-02-08 12:53:56 +0000508};
509
510static PyStructSequence_Field profiler_subentry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000511 {"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}
Armin Rigoa871ef22006-02-08 12:53:56 +0000517};
518
519static PyStructSequence_Desc profiler_entry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000520 "_lsprof.profiler_entry", /* name */
521 NULL, /* doc */
522 profiler_entry_fields,
523 6
Armin Rigoa871ef22006-02-08 12:53:56 +0000524};
525
526static PyStructSequence_Desc profiler_subentry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000527 "_lsprof.profiler_subentry", /* name */
528 NULL, /* doc */
529 profiler_subentry_fields,
530 5
Armin Rigoa871ef22006-02-08 12:53:56 +0000531};
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 {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000539 PyObject *list;
540 PyObject *sublist;
541 double factor;
Armin Rigoa871ef22006-02-08 12:53:56 +0000542} statscollector_t;
543
544static int statsForSubEntry(rotating_node_t *node, void *arg)
545{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000546 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000563}
564
565static int statsForEntry(rotating_node_t *node, void *arg)
566{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000567 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 */
Armin Rigoa871ef22006-02-08 12:53:56 +0000573
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000574 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 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000588
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000589 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000603}
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{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000632 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000650}
651
652static int
653setSubcalls(ProfilerObject *pObj, int nvalue)
654{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000655 if (nvalue == 0)
656 pObj->flags &= ~POF_SUBCALLS;
657 else if (nvalue > 0)
658 pObj->flags |= POF_SUBCALLS;
659 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000660}
661
662static int
663setBuiltins(ProfilerObject *pObj, int nvalue)
664{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000665 if (nvalue == 0)
666 pObj->flags &= ~POF_BUILTINS;
667 else if (nvalue > 0) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000668#ifndef PyTrace_C_CALL
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000669 PyErr_SetString(PyExc_ValueError,
670 "builtins=True requires Python >= 2.4");
671 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000672#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000673 pObj->flags |= POF_BUILTINS;
Armin Rigoa871ef22006-02-08 12:53:56 +0000674#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000675 }
676 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000677}
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{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000692 int subcalls = -1;
693 int builtins = -1;
694 static char *kwlist[] = {"subcalls", "builtins", 0};
695 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000704}
705
706static void
707flush_unmatched(ProfilerObject *pObj)
708{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000709 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 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000719
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{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000731 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000738}
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{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000749 clearEntries(pObj);
750 Py_INCREF(Py_None);
751 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000752}
753
754static void
755profiler_dealloc(ProfilerObject *op)
756{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000757 if (op->flags & POF_ENABLED)
758 PyEval_SetProfile(NULL, NULL);
759 flush_unmatched(op);
760 clearEntries(op);
761 Py_XDECREF(op->externalTimer);
762 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{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000768 PyObject *o;
769 PyObject *timer = NULL;
770 double timeunit = 0.0;
771 int subcalls = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000772#ifdef PyTrace_C_CALL
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000773 int builtins = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000774#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000775 int builtins = 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000776#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000777 static char *kwlist[] = {"timer", "timeunit",
778 "subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000779
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000780 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
781 &timer, &timeunit,
782 &subcalls, &builtins))
783 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000784
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000785 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;
Armin Rigoa871ef22006-02-08 12:53:56 +0000793}
794
795static PyMethodDef profiler_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000796 {"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}
Armin Rigoa871ef22006-02-08 12:53:56 +0000805};
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 = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000818 PyVarObject_HEAD_INIT(NULL, 0)
819 "_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_reserved */
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 */
Armin Rigoa871ef22006-02-08 12:53:56 +0000857};
858
859static PyMethodDef moduleMethods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000860 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000861};
862
Martin v. Löwis1a214512008-06-11 05:26:20 +0000863
864static struct PyModuleDef _lsprofmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000865 PyModuleDef_HEAD_INIT,
866 "_lsprof",
867 "Fast profiler",
868 -1,
869 moduleMethods,
870 NULL,
871 NULL,
872 NULL,
873 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000874};
875
Armin Rigoa871ef22006-02-08 12:53:56 +0000876PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000877PyInit__lsprof(void)
Armin Rigoa871ef22006-02-08 12:53:56 +0000878{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000879 PyObject *module, *d;
880 module = PyModule_Create(&_lsprofmodule);
881 if (module == NULL)
882 return NULL;
883 d = PyModule_GetDict(module);
884 if (PyType_Ready(&PyProfiler_Type) < 0)
885 return NULL;
886 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
Armin Rigoa871ef22006-02-08 12:53:56 +0000887
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000888 if (!initialized) {
889 PyStructSequence_InitType(&StatsEntryType,
890 &profiler_entry_desc);
891 PyStructSequence_InitType(&StatsSubEntryType,
892 &profiler_subentry_desc);
893 }
894 Py_INCREF((PyObject*) &StatsEntryType);
895 Py_INCREF((PyObject*) &StatsSubEntryType);
896 PyModule_AddObject(module, "profiler_entry",
897 (PyObject*) &StatsEntryType);
898 PyModule_AddObject(module, "profiler_subentry",
899 (PyObject*) &StatsSubEntryType);
900 empty_tuple = PyTuple_New(0);
901 initialized = 1;
902 return module;
Armin Rigoa871ef22006-02-08 12:53:56 +0000903}