blob: cc412bfc23283b3340ce9c5ad9ee7060f2177b1c [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;
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000179 const char *modname;
180 if (mod && PyUnicode_Check(mod)) {
181 /* XXX: The following will truncate module names with embedded
182 * null-characters. It is unlikely that this can happen in
183 * practice and the concequences are not serious enough to
184 * introduce extra checks here.
185 */
186 modname = _PyUnicode_AsString(mod);
187 if (modname == NULL) {
188 modname = "<encoding error>";
189 PyErr_Clear();
Alexander Belopolskye239d232010-12-08 23:31:48 +0000190 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000191 }
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000192 else if (mod && PyModule_Check(mod)) {
193 modname = PyModule_GetName(mod);
194 if (modname == NULL) {
195 PyErr_Clear();
196 modname = "builtins";
197 }
198 }
199 else {
200 modname = "builtins";
201 }
202 if (strcmp(modname, "builtins") != 0)
203 return PyUnicode_FromFormat("<%s.%s>",
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000204 modname,
205 fn->m_ml->ml_name);
206 else
207 return PyUnicode_FromFormat("<%s>",
208 fn->m_ml->ml_name);
209 }
210 else {
211 /* built-in method: try to return
212 repr(getattr(type(__self__), __name__))
213 */
214 PyObject *self = fn->m_self;
215 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
216 if (name != NULL) {
217 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
218 Py_XINCREF(mo);
219 Py_DECREF(name);
220 if (mo != NULL) {
221 PyObject *res = PyObject_Repr(mo);
222 Py_DECREF(mo);
223 if (res != NULL)
224 return res;
225 }
226 }
227 PyErr_Clear();
228 return PyUnicode_FromFormat("<built-in method %s>",
229 fn->m_ml->ml_name);
230 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000231}
232
233static ProfilerEntry*
234newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
235{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000236 ProfilerEntry *self;
237 self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry));
238 if (self == NULL) {
239 pObj->flags |= POF_NOMEMORY;
240 return NULL;
241 }
242 userObj = normalizeUserObj(userObj);
243 if (userObj == NULL) {
244 PyErr_Clear();
245 free(self);
246 pObj->flags |= POF_NOMEMORY;
247 return NULL;
248 }
249 self->header.key = key;
250 self->userObj = userObj;
251 self->tt = 0;
252 self->it = 0;
253 self->callcount = 0;
254 self->recursivecallcount = 0;
255 self->recursionLevel = 0;
256 self->calls = EMPTY_ROTATING_TREE;
257 RotatingTree_Add(&pObj->profilerEntries, &self->header);
258 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000259}
260
261static ProfilerEntry*
262getEntry(ProfilerObject *pObj, void *key)
263{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000264 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
Armin Rigoa871ef22006-02-08 12:53:56 +0000265}
266
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000267static ProfilerSubEntry *
Armin Rigoa871ef22006-02-08 12:53:56 +0000268getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
269{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000270 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
271 (void *)entry);
Armin Rigoa871ef22006-02-08 12:53:56 +0000272}
273
274static ProfilerSubEntry *
275newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
276{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000277 ProfilerSubEntry *self;
278 self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry));
279 if (self == NULL) {
280 pObj->flags |= POF_NOMEMORY;
281 return NULL;
282 }
283 self->header.key = (void *)entry;
284 self->tt = 0;
285 self->it = 0;
286 self->callcount = 0;
287 self->recursivecallcount = 0;
288 self->recursionLevel = 0;
289 RotatingTree_Add(&caller->calls, &self->header);
290 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000291}
292
293static int freeSubEntry(rotating_node_t *header, void *arg)
294{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000295 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
296 free(subentry);
297 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000298}
299
300static int freeEntry(rotating_node_t *header, void *arg)
301{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000302 ProfilerEntry *entry = (ProfilerEntry*) header;
303 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
304 Py_DECREF(entry->userObj);
305 free(entry);
306 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000307}
308
309static void clearEntries(ProfilerObject *pObj)
310{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000311 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
312 pObj->profilerEntries = EMPTY_ROTATING_TREE;
313 /* release the memory hold by the ProfilerContexts */
314 if (pObj->currentProfilerContext) {
315 free(pObj->currentProfilerContext);
316 pObj->currentProfilerContext = NULL;
317 }
318 while (pObj->freelistProfilerContext) {
319 ProfilerContext *c = pObj->freelistProfilerContext;
320 pObj->freelistProfilerContext = c->previous;
321 free(c);
322 }
323 pObj->freelistProfilerContext = NULL;
Armin Rigoa871ef22006-02-08 12:53:56 +0000324}
325
326static void
327initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
328{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000329 self->ctxEntry = entry;
330 self->subt = 0;
331 self->previous = pObj->currentProfilerContext;
332 pObj->currentProfilerContext = self;
333 ++entry->recursionLevel;
334 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
335 /* find or create an entry for me in my caller's entry */
336 ProfilerEntry *caller = self->previous->ctxEntry;
337 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
338 if (subentry == NULL)
339 subentry = newSubEntry(pObj, caller, entry);
340 if (subentry)
341 ++subentry->recursionLevel;
342 }
343 self->t0 = CALL_TIMER(pObj);
Armin Rigoa871ef22006-02-08 12:53:56 +0000344}
345
346static void
347Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
348{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000349 PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0;
350 PY_LONG_LONG it = tt - self->subt;
351 if (self->previous)
352 self->previous->subt += tt;
353 pObj->currentProfilerContext = self->previous;
354 if (--entry->recursionLevel == 0)
355 entry->tt += tt;
356 else
357 ++entry->recursivecallcount;
358 entry->it += it;
359 entry->callcount++;
360 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
361 /* find or create an entry for me in my caller's entry */
362 ProfilerEntry *caller = self->previous->ctxEntry;
363 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
364 if (subentry) {
365 if (--subentry->recursionLevel == 0)
366 subentry->tt += tt;
367 else
368 ++subentry->recursivecallcount;
369 subentry->it += it;
370 ++subentry->callcount;
371 }
372 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000373}
374
375static void
376ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
377{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000378 /* entering a call to the function identified by 'key'
379 (which can be a PyCodeObject or a PyMethodDef pointer) */
380 ProfilerObject *pObj = (ProfilerObject*)self;
381 ProfilerEntry *profEntry;
382 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000383
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 /* In the case of entering a generator expression frame via a
385 * throw (gen_send_ex(.., 1)), we may already have an
386 * Exception set here. We must not mess around with this
387 * exception, and some of the code under here assumes that
388 * PyErr_* is its own to mess around with, so we have to
389 * save and restore any current exception. */
390 PyObject *last_type, *last_value, *last_tb;
391 PyErr_Fetch(&last_type, &last_value, &last_tb);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000392
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000393 profEntry = getEntry(pObj, key);
394 if (profEntry == NULL) {
395 profEntry = newProfilerEntry(pObj, key, userObj);
396 if (profEntry == NULL)
397 goto restorePyerr;
398 }
399 /* grab a ProfilerContext out of the free list */
400 pContext = pObj->freelistProfilerContext;
401 if (pContext) {
402 pObj->freelistProfilerContext = pContext->previous;
403 }
404 else {
405 /* free list exhausted, allocate a new one */
406 pContext = (ProfilerContext*)
407 malloc(sizeof(ProfilerContext));
408 if (pContext == NULL) {
409 pObj->flags |= POF_NOMEMORY;
410 goto restorePyerr;
411 }
412 }
413 initContext(pObj, pContext, profEntry);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000414
415restorePyerr:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000416 PyErr_Restore(last_type, last_value, last_tb);
Armin Rigoa871ef22006-02-08 12:53:56 +0000417}
418
419static void
420ptrace_leave_call(PyObject *self, void *key)
421{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000422 /* leaving a call to the function identified by 'key' */
423 ProfilerObject *pObj = (ProfilerObject*)self;
424 ProfilerEntry *profEntry;
425 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000426
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000427 pContext = pObj->currentProfilerContext;
428 if (pContext == NULL)
429 return;
430 profEntry = getEntry(pObj, key);
431 if (profEntry) {
432 Stop(pObj, pContext, profEntry);
433 }
434 else {
435 pObj->currentProfilerContext = pContext->previous;
436 }
437 /* put pContext into the free list */
438 pContext->previous = pObj->freelistProfilerContext;
439 pObj->freelistProfilerContext = pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000440}
441
442static int
443profiler_callback(PyObject *self, PyFrameObject *frame, int what,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000444 PyObject *arg)
Armin Rigoa871ef22006-02-08 12:53:56 +0000445{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000446 switch (what) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000447
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000448 /* the 'frame' of a called function is about to start its execution */
449 case PyTrace_CALL:
450 ptrace_enter_call(self, (void *)frame->f_code,
451 (PyObject *)frame->f_code);
452 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000453
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000454 /* the 'frame' of a called function is about to finish
455 (either normally or with an exception) */
456 case PyTrace_RETURN:
457 ptrace_leave_call(self, (void *)frame->f_code);
458 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000459
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000460 /* case PyTrace_EXCEPTION:
461 If the exception results in the function exiting, a
462 PyTrace_RETURN event will be generated, so we don't need to
463 handle it. */
Armin Rigoa871ef22006-02-08 12:53:56 +0000464
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000465#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */
466 /* the Python function 'frame' is issuing a call to the built-in
467 function 'arg' */
468 case PyTrace_C_CALL:
469 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
470 && PyCFunction_Check(arg)) {
471 ptrace_enter_call(self,
472 ((PyCFunctionObject *)arg)->m_ml,
473 arg);
474 }
475 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000476
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000477 /* the call to the built-in function 'arg' is returning into its
478 caller 'frame' */
479 case PyTrace_C_RETURN: /* ...normally */
480 case PyTrace_C_EXCEPTION: /* ...with an exception set */
481 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
482 && PyCFunction_Check(arg)) {
483 ptrace_leave_call(self,
484 ((PyCFunctionObject *)arg)->m_ml);
485 }
486 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000487#endif
488
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000489 default:
490 break;
491 }
492 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000493}
494
495static int
496pending_exception(ProfilerObject *pObj)
497{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000498 if (pObj->flags & POF_NOMEMORY) {
499 pObj->flags -= POF_NOMEMORY;
500 PyErr_SetString(PyExc_MemoryError,
501 "memory was exhausted while profiling");
502 return -1;
503 }
504 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000505}
506
507/************************************************************/
508
509static PyStructSequence_Field profiler_entry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000510 {"code", "code object or built-in function name"},
511 {"callcount", "how many times this was called"},
512 {"reccallcount", "how many times called recursively"},
513 {"totaltime", "total time in this entry"},
514 {"inlinetime", "inline time in this entry (not in subcalls)"},
515 {"calls", "details of the calls"},
516 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000517};
518
519static PyStructSequence_Field profiler_subentry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000520 {"code", "called code object or built-in function name"},
521 {"callcount", "how many times this is called"},
522 {"reccallcount", "how many times this is called recursively"},
523 {"totaltime", "total time spent in this call"},
524 {"inlinetime", "inline time (not in further subcalls)"},
525 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000526};
527
528static PyStructSequence_Desc profiler_entry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000529 "_lsprof.profiler_entry", /* name */
530 NULL, /* doc */
531 profiler_entry_fields,
532 6
Armin Rigoa871ef22006-02-08 12:53:56 +0000533};
534
535static PyStructSequence_Desc profiler_subentry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000536 "_lsprof.profiler_subentry", /* name */
537 NULL, /* doc */
538 profiler_subentry_fields,
539 5
Armin Rigoa871ef22006-02-08 12:53:56 +0000540};
541
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000542static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000543static PyTypeObject StatsEntryType;
544static PyTypeObject StatsSubEntryType;
545
546
547typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000548 PyObject *list;
549 PyObject *sublist;
550 double factor;
Armin Rigoa871ef22006-02-08 12:53:56 +0000551} statscollector_t;
552
553static int statsForSubEntry(rotating_node_t *node, void *arg)
554{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000555 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
556 statscollector_t *collect = (statscollector_t*) arg;
557 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
558 int err;
559 PyObject *sinfo;
560 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
561 "((Olldd))",
562 entry->userObj,
563 sentry->callcount,
564 sentry->recursivecallcount,
565 collect->factor * sentry->tt,
566 collect->factor * sentry->it);
567 if (sinfo == NULL)
568 return -1;
569 err = PyList_Append(collect->sublist, sinfo);
570 Py_DECREF(sinfo);
571 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000572}
573
574static int statsForEntry(rotating_node_t *node, void *arg)
575{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000576 ProfilerEntry *entry = (ProfilerEntry*) node;
577 statscollector_t *collect = (statscollector_t*) arg;
578 PyObject *info;
579 int err;
580 if (entry->callcount == 0)
581 return 0; /* skip */
Armin Rigoa871ef22006-02-08 12:53:56 +0000582
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000583 if (entry->calls != EMPTY_ROTATING_TREE) {
584 collect->sublist = PyList_New(0);
585 if (collect->sublist == NULL)
586 return -1;
587 if (RotatingTree_Enum(entry->calls,
588 statsForSubEntry, collect) != 0) {
589 Py_DECREF(collect->sublist);
590 return -1;
591 }
592 }
593 else {
594 Py_INCREF(Py_None);
595 collect->sublist = Py_None;
596 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000597
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000598 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
599 "((OllddO))",
600 entry->userObj,
601 entry->callcount,
602 entry->recursivecallcount,
603 collect->factor * entry->tt,
604 collect->factor * entry->it,
605 collect->sublist);
606 Py_DECREF(collect->sublist);
607 if (info == NULL)
608 return -1;
609 err = PyList_Append(collect->list, info);
610 Py_DECREF(info);
611 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000612}
613
614PyDoc_STRVAR(getstats_doc, "\
615getstats() -> list of profiler_entry objects\n\
616\n\
617Return all information collected by the profiler.\n\
618Each profiler_entry is a tuple-like object with the\n\
619following attributes:\n\
620\n\
621 code code object\n\
622 callcount how many times this was called\n\
623 reccallcount how many times called recursively\n\
624 totaltime total time in this entry\n\
625 inlinetime inline time in this entry (not in subcalls)\n\
626 calls details of the calls\n\
627\n\
628The calls attribute is either None or a list of\n\
629profiler_subentry objects:\n\
630\n\
631 code called code object\n\
632 callcount how many times this is called\n\
633 reccallcount how many times this is called recursively\n\
634 totaltime total time spent in this call\n\
635 inlinetime inline time (not in further subcalls)\n\
636");
637
638static PyObject*
639profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
640{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000641 statscollector_t collect;
642 if (pending_exception(pObj))
643 return NULL;
644 if (!pObj->externalTimer)
645 collect.factor = hpTimerUnit();
646 else if (pObj->externalTimerUnit > 0.0)
647 collect.factor = pObj->externalTimerUnit;
648 else
649 collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
650 collect.list = PyList_New(0);
651 if (collect.list == NULL)
652 return NULL;
653 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
654 != 0) {
655 Py_DECREF(collect.list);
656 return NULL;
657 }
658 return collect.list;
Armin Rigoa871ef22006-02-08 12:53:56 +0000659}
660
661static int
662setSubcalls(ProfilerObject *pObj, int nvalue)
663{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000664 if (nvalue == 0)
665 pObj->flags &= ~POF_SUBCALLS;
666 else if (nvalue > 0)
667 pObj->flags |= POF_SUBCALLS;
668 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000669}
670
671static int
672setBuiltins(ProfilerObject *pObj, int nvalue)
673{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000674 if (nvalue == 0)
675 pObj->flags &= ~POF_BUILTINS;
676 else if (nvalue > 0) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000677#ifndef PyTrace_C_CALL
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000678 PyErr_SetString(PyExc_ValueError,
679 "builtins=True requires Python >= 2.4");
680 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000681#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000682 pObj->flags |= POF_BUILTINS;
Armin Rigoa871ef22006-02-08 12:53:56 +0000683#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000684 }
685 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000686}
687
688PyDoc_STRVAR(enable_doc, "\
689enable(subcalls=True, builtins=True)\n\
690\n\
691Start collecting profiling information.\n\
692If 'subcalls' is True, also records for each function\n\
693statistics separated according to its current caller.\n\
694If 'builtins' is True, records the time spent in\n\
695built-in functions separately from their caller.\n\
696");
697
698static PyObject*
699profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
700{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000701 int subcalls = -1;
702 int builtins = -1;
703 static char *kwlist[] = {"subcalls", "builtins", 0};
704 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
705 kwlist, &subcalls, &builtins))
706 return NULL;
707 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
708 return NULL;
709 PyEval_SetProfile(profiler_callback, (PyObject*)self);
710 self->flags |= POF_ENABLED;
711 Py_INCREF(Py_None);
712 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000713}
714
715static void
716flush_unmatched(ProfilerObject *pObj)
717{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000718 while (pObj->currentProfilerContext) {
719 ProfilerContext *pContext = pObj->currentProfilerContext;
720 ProfilerEntry *profEntry= pContext->ctxEntry;
721 if (profEntry)
722 Stop(pObj, pContext, profEntry);
723 else
724 pObj->currentProfilerContext = pContext->previous;
725 if (pContext)
726 free(pContext);
727 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000728
729}
730
731PyDoc_STRVAR(disable_doc, "\
732disable()\n\
733\n\
734Stop collecting profiling information.\n\
735");
736
737static PyObject*
738profiler_disable(ProfilerObject *self, PyObject* noarg)
739{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000740 self->flags &= ~POF_ENABLED;
741 PyEval_SetProfile(NULL, NULL);
742 flush_unmatched(self);
743 if (pending_exception(self))
744 return NULL;
745 Py_INCREF(Py_None);
746 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000747}
748
749PyDoc_STRVAR(clear_doc, "\
750clear()\n\
751\n\
752Clear all profiling information collected so far.\n\
753");
754
755static PyObject*
756profiler_clear(ProfilerObject *pObj, PyObject* noarg)
757{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000758 clearEntries(pObj);
759 Py_INCREF(Py_None);
760 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000761}
762
763static void
764profiler_dealloc(ProfilerObject *op)
765{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000766 if (op->flags & POF_ENABLED)
767 PyEval_SetProfile(NULL, NULL);
768 flush_unmatched(op);
769 clearEntries(op);
770 Py_XDECREF(op->externalTimer);
771 Py_TYPE(op)->tp_free(op);
Armin Rigoa871ef22006-02-08 12:53:56 +0000772}
773
774static int
775profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
776{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000777 PyObject *o;
778 PyObject *timer = NULL;
779 double timeunit = 0.0;
780 int subcalls = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000781#ifdef PyTrace_C_CALL
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000782 int builtins = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000783#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000784 int builtins = 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000785#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000786 static char *kwlist[] = {"timer", "timeunit",
787 "subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000788
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000789 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
790 &timer, &timeunit,
791 &subcalls, &builtins))
792 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000793
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000794 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
795 return -1;
796 o = pObj->externalTimer;
797 pObj->externalTimer = timer;
798 Py_XINCREF(timer);
799 Py_XDECREF(o);
800 pObj->externalTimerUnit = timeunit;
801 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000802}
803
804static PyMethodDef profiler_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000805 {"getstats", (PyCFunction)profiler_getstats,
806 METH_NOARGS, getstats_doc},
807 {"enable", (PyCFunction)profiler_enable,
808 METH_VARARGS | METH_KEYWORDS, enable_doc},
809 {"disable", (PyCFunction)profiler_disable,
810 METH_NOARGS, disable_doc},
811 {"clear", (PyCFunction)profiler_clear,
812 METH_NOARGS, clear_doc},
813 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000814};
815
816PyDoc_STRVAR(profiler_doc, "\
817Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
818\n\
819 Builds a profiler object using the specified timer function.\n\
820 The default timer is a fast built-in one based on real time.\n\
821 For custom timer functions returning integers, time_unit can\n\
822 be a float specifying a scale (i.e. how long each integer unit\n\
823 is, in seconds).\n\
824");
825
Neal Norwitz227b5332006-03-22 09:28:35 +0000826static PyTypeObject PyProfiler_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000827 PyVarObject_HEAD_INIT(NULL, 0)
828 "_lsprof.Profiler", /* tp_name */
829 sizeof(ProfilerObject), /* tp_basicsize */
830 0, /* tp_itemsize */
831 (destructor)profiler_dealloc, /* tp_dealloc */
832 0, /* tp_print */
833 0, /* tp_getattr */
834 0, /* tp_setattr */
835 0, /* tp_reserved */
836 0, /* tp_repr */
837 0, /* tp_as_number */
838 0, /* tp_as_sequence */
839 0, /* tp_as_mapping */
840 0, /* tp_hash */
841 0, /* tp_call */
842 0, /* tp_str */
843 0, /* tp_getattro */
844 0, /* tp_setattro */
845 0, /* tp_as_buffer */
846 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
847 profiler_doc, /* tp_doc */
848 0, /* tp_traverse */
849 0, /* tp_clear */
850 0, /* tp_richcompare */
851 0, /* tp_weaklistoffset */
852 0, /* tp_iter */
853 0, /* tp_iternext */
854 profiler_methods, /* tp_methods */
855 0, /* tp_members */
856 0, /* tp_getset */
857 0, /* tp_base */
858 0, /* tp_dict */
859 0, /* tp_descr_get */
860 0, /* tp_descr_set */
861 0, /* tp_dictoffset */
862 (initproc)profiler_init, /* tp_init */
863 PyType_GenericAlloc, /* tp_alloc */
864 PyType_GenericNew, /* tp_new */
865 PyObject_Del, /* tp_free */
Armin Rigoa871ef22006-02-08 12:53:56 +0000866};
867
868static PyMethodDef moduleMethods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000869 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000870};
871
Martin v. Löwis1a214512008-06-11 05:26:20 +0000872
873static struct PyModuleDef _lsprofmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000874 PyModuleDef_HEAD_INIT,
875 "_lsprof",
876 "Fast profiler",
877 -1,
878 moduleMethods,
879 NULL,
880 NULL,
881 NULL,
882 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000883};
884
Armin Rigoa871ef22006-02-08 12:53:56 +0000885PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000886PyInit__lsprof(void)
Armin Rigoa871ef22006-02-08 12:53:56 +0000887{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000888 PyObject *module, *d;
889 module = PyModule_Create(&_lsprofmodule);
890 if (module == NULL)
891 return NULL;
892 d = PyModule_GetDict(module);
893 if (PyType_Ready(&PyProfiler_Type) < 0)
894 return NULL;
895 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
Armin Rigoa871ef22006-02-08 12:53:56 +0000896
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000897 if (!initialized) {
898 PyStructSequence_InitType(&StatsEntryType,
899 &profiler_entry_desc);
900 PyStructSequence_InitType(&StatsSubEntryType,
901 &profiler_subentry_desc);
902 }
903 Py_INCREF((PyObject*) &StatsEntryType);
904 Py_INCREF((PyObject*) &StatsSubEntryType);
905 PyModule_AddObject(module, "profiler_entry",
906 (PyObject*) &StatsEntryType);
907 PyModule_AddObject(module, "profiler_subentry",
908 (PyObject*) &StatsSubEntryType);
909 empty_tuple = PyTuple_New(0);
910 initialized = 1;
911 return module;
Armin Rigoa871ef22006-02-08 12:53:56 +0000912}