blob: a5630c8cdb6e1853c66c8fb29fff38be6e08e357 [file] [log] [blame]
Armin Rigoa871ef22006-02-08 12:53:56 +00001#include "Python.h"
2#include "compile.h"
3#include "frameobject.h"
Armin Rigoa871ef22006-02-08 12:53:56 +00004#include "rotatingtree.h"
5
6#if !defined(HAVE_LONG_LONG)
7#error "This module requires long longs!"
8#endif
9
10/*** Selection of a high-precision timer ***/
11
12#ifdef MS_WINDOWS
13
14#include <windows.h>
15
16static PY_LONG_LONG
17hpTimer(void)
18{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000019 LARGE_INTEGER li;
20 QueryPerformanceCounter(&li);
21 return li.QuadPart;
Armin Rigoa871ef22006-02-08 12:53:56 +000022}
23
24static double
25hpTimerUnit(void)
26{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000027 LARGE_INTEGER li;
28 if (QueryPerformanceFrequency(&li))
29 return 1.0 / li.QuadPart;
30 else
31 return 0.000001; /* unlikely */
Armin Rigoa871ef22006-02-08 12:53:56 +000032}
33
34#else /* !MS_WINDOWS */
35
36#ifndef HAVE_GETTIMEOFDAY
37#error "This module requires gettimeofday() on non-Windows platforms!"
38#endif
39
40#if (defined(PYOS_OS2) && defined(PYCC_GCC))
41#include <sys/time.h>
42#else
43#include <sys/resource.h>
44#include <sys/times.h>
45#endif
46
47static PY_LONG_LONG
48hpTimer(void)
49{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000050 struct timeval tv;
51 PY_LONG_LONG ret;
Armin Rigoa871ef22006-02-08 12:53:56 +000052#ifdef GETTIMEOFDAY_NO_TZ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000053 gettimeofday(&tv);
Armin Rigoa871ef22006-02-08 12:53:56 +000054#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000055 gettimeofday(&tv, (struct timezone *)NULL);
Armin Rigoa871ef22006-02-08 12:53:56 +000056#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000057 ret = tv.tv_sec;
58 ret = ret * 1000000 + tv.tv_usec;
59 return ret;
Armin Rigoa871ef22006-02-08 12:53:56 +000060}
61
62static double
63hpTimerUnit(void)
64{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000065 return 0.000001;
Armin Rigoa871ef22006-02-08 12:53:56 +000066}
67
68#endif /* MS_WINDOWS */
69
70/************************************************************/
71/* Written by Brett Rosen and Ted Czotter */
72
73struct _ProfilerEntry;
74
75/* represents a function called from another function */
76typedef struct _ProfilerSubEntry {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000077 rotating_node_t header;
78 PY_LONG_LONG tt;
79 PY_LONG_LONG it;
80 long callcount;
81 long recursivecallcount;
82 long recursionLevel;
Armin Rigoa871ef22006-02-08 12:53:56 +000083} ProfilerSubEntry;
84
85/* represents a function or user defined block */
86typedef struct _ProfilerEntry {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000087 rotating_node_t header;
88 PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
89 PY_LONG_LONG tt; /* total time in this entry */
90 PY_LONG_LONG it; /* inline time in this entry (not in subcalls) */
91 long callcount; /* how many times this was called */
92 long recursivecallcount; /* how many times called recursively */
93 long recursionLevel;
94 rotating_node_t *calls;
Armin Rigoa871ef22006-02-08 12:53:56 +000095} ProfilerEntry;
96
97typedef struct _ProfilerContext {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000098 PY_LONG_LONG t0;
99 PY_LONG_LONG subt;
100 struct _ProfilerContext *previous;
101 ProfilerEntry *ctxEntry;
Armin Rigoa871ef22006-02-08 12:53:56 +0000102} ProfilerContext;
103
104typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000105 PyObject_HEAD
106 rotating_node_t *profilerEntries;
107 ProfilerContext *currentProfilerContext;
108 ProfilerContext *freelistProfilerContext;
109 int flags;
110 PyObject *externalTimer;
111 double externalTimerUnit;
Armin Rigoa871ef22006-02-08 12:53:56 +0000112} ProfilerObject;
113
114#define POF_ENABLED 0x001
115#define POF_SUBCALLS 0x002
116#define POF_BUILTINS 0x004
117#define POF_NOMEMORY 0x100
118
Neal Norwitz227b5332006-03-22 09:28:35 +0000119static PyTypeObject PyProfiler_Type;
Armin Rigoa871ef22006-02-08 12:53:56 +0000120
121#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
Christian Heimes90aa7642007-12-19 02:45:37 +0000122#define PyProfiler_CheckExact(op) (Py_TYPE(op) == &PyProfiler_Type)
Armin Rigoa871ef22006-02-08 12:53:56 +0000123
124/*** External Timers ***/
125
126#define DOUBLE_TIMER_PRECISION 4294967296.0
127static PyObject *empty_tuple;
128
129static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj)
130{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000131 PY_LONG_LONG result;
132 PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL);
133 if (o == NULL) {
134 PyErr_WriteUnraisable(pObj->externalTimer);
135 return 0;
136 }
137 if (pObj->externalTimerUnit > 0.0) {
138 /* interpret the result as an integer that will be scaled
139 in profiler_getstats() */
140 result = PyLong_AsLongLong(o);
141 }
142 else {
143 /* interpret the result as a double measured in seconds.
144 As the profiler works with PY_LONG_LONG internally
145 we convert it to a large integer */
146 double val = PyFloat_AsDouble(o);
147 /* error handling delayed to the code below */
148 result = (PY_LONG_LONG) (val * DOUBLE_TIMER_PRECISION);
149 }
150 Py_DECREF(o);
151 if (PyErr_Occurred()) {
152 PyErr_WriteUnraisable(pObj->externalTimer);
153 return 0;
154 }
155 return result;
Armin Rigoa871ef22006-02-08 12:53:56 +0000156}
157
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158#define CALL_TIMER(pObj) ((pObj)->externalTimer ? \
159 CallExternalTimer(pObj) : \
160 hpTimer())
Armin Rigoa871ef22006-02-08 12:53:56 +0000161
162/*** ProfilerObject ***/
163
164static PyObject *
165normalizeUserObj(PyObject *obj)
166{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000167 PyCFunctionObject *fn;
168 if (!PyCFunction_Check(obj)) {
169 Py_INCREF(obj);
170 return obj;
171 }
172 /* Replace built-in function objects with a descriptive string
173 because of built-in methods -- keeping a reference to
174 __self__ is probably not a good idea. */
175 fn = (PyCFunctionObject *)obj;
Armin Rigoa871ef22006-02-08 12:53:56 +0000176
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000177 if (fn->m_self == NULL) {
178 /* built-in function: look up the module name */
179 PyObject *mod = fn->m_module;
180 const char *modname;
181 if (mod && PyUnicode_Check(mod)) {
182 modname = _PyUnicode_AsString(mod);
183 }
184 else if (mod && PyModule_Check(mod)) {
185 modname = PyModule_GetName(mod);
186 if (modname == NULL) {
187 PyErr_Clear();
188 modname = "builtins";
189 }
190 }
191 else {
192 modname = "builtins";
193 }
194 if (strcmp(modname, "builtins") != 0)
195 return PyUnicode_FromFormat("<%s.%s>",
196 modname,
197 fn->m_ml->ml_name);
198 else
199 return PyUnicode_FromFormat("<%s>",
200 fn->m_ml->ml_name);
201 }
202 else {
203 /* built-in method: try to return
204 repr(getattr(type(__self__), __name__))
205 */
206 PyObject *self = fn->m_self;
207 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
208 if (name != NULL) {
209 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
210 Py_XINCREF(mo);
211 Py_DECREF(name);
212 if (mo != NULL) {
213 PyObject *res = PyObject_Repr(mo);
214 Py_DECREF(mo);
215 if (res != NULL)
216 return res;
217 }
218 }
219 PyErr_Clear();
220 return PyUnicode_FromFormat("<built-in method %s>",
221 fn->m_ml->ml_name);
222 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000223}
224
225static ProfilerEntry*
226newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
227{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000228 ProfilerEntry *self;
229 self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry));
230 if (self == NULL) {
231 pObj->flags |= POF_NOMEMORY;
232 return NULL;
233 }
234 userObj = normalizeUserObj(userObj);
235 if (userObj == NULL) {
236 PyErr_Clear();
237 free(self);
238 pObj->flags |= POF_NOMEMORY;
239 return NULL;
240 }
241 self->header.key = key;
242 self->userObj = userObj;
243 self->tt = 0;
244 self->it = 0;
245 self->callcount = 0;
246 self->recursivecallcount = 0;
247 self->recursionLevel = 0;
248 self->calls = EMPTY_ROTATING_TREE;
249 RotatingTree_Add(&pObj->profilerEntries, &self->header);
250 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000251}
252
253static ProfilerEntry*
254getEntry(ProfilerObject *pObj, void *key)
255{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000256 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
Armin Rigoa871ef22006-02-08 12:53:56 +0000257}
258
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000259static ProfilerSubEntry *
Armin Rigoa871ef22006-02-08 12:53:56 +0000260getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
261{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000262 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
263 (void *)entry);
Armin Rigoa871ef22006-02-08 12:53:56 +0000264}
265
266static ProfilerSubEntry *
267newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
268{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000269 ProfilerSubEntry *self;
270 self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry));
271 if (self == NULL) {
272 pObj->flags |= POF_NOMEMORY;
273 return NULL;
274 }
275 self->header.key = (void *)entry;
276 self->tt = 0;
277 self->it = 0;
278 self->callcount = 0;
279 self->recursivecallcount = 0;
280 self->recursionLevel = 0;
281 RotatingTree_Add(&caller->calls, &self->header);
282 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000283}
284
285static int freeSubEntry(rotating_node_t *header, void *arg)
286{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000287 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
288 free(subentry);
289 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000290}
291
292static int freeEntry(rotating_node_t *header, void *arg)
293{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000294 ProfilerEntry *entry = (ProfilerEntry*) header;
295 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
296 Py_DECREF(entry->userObj);
297 free(entry);
298 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000299}
300
301static void clearEntries(ProfilerObject *pObj)
302{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
304 pObj->profilerEntries = EMPTY_ROTATING_TREE;
305 /* release the memory hold by the ProfilerContexts */
306 if (pObj->currentProfilerContext) {
307 free(pObj->currentProfilerContext);
308 pObj->currentProfilerContext = NULL;
309 }
310 while (pObj->freelistProfilerContext) {
311 ProfilerContext *c = pObj->freelistProfilerContext;
312 pObj->freelistProfilerContext = c->previous;
313 free(c);
314 }
315 pObj->freelistProfilerContext = NULL;
Armin Rigoa871ef22006-02-08 12:53:56 +0000316}
317
318static void
319initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
320{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000321 self->ctxEntry = entry;
322 self->subt = 0;
323 self->previous = pObj->currentProfilerContext;
324 pObj->currentProfilerContext = self;
325 ++entry->recursionLevel;
326 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
327 /* find or create an entry for me in my caller's entry */
328 ProfilerEntry *caller = self->previous->ctxEntry;
329 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
330 if (subentry == NULL)
331 subentry = newSubEntry(pObj, caller, entry);
332 if (subentry)
333 ++subentry->recursionLevel;
334 }
335 self->t0 = CALL_TIMER(pObj);
Armin Rigoa871ef22006-02-08 12:53:56 +0000336}
337
338static void
339Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
340{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000341 PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0;
342 PY_LONG_LONG it = tt - self->subt;
343 if (self->previous)
344 self->previous->subt += tt;
345 pObj->currentProfilerContext = self->previous;
346 if (--entry->recursionLevel == 0)
347 entry->tt += tt;
348 else
349 ++entry->recursivecallcount;
350 entry->it += it;
351 entry->callcount++;
352 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
353 /* find or create an entry for me in my caller's entry */
354 ProfilerEntry *caller = self->previous->ctxEntry;
355 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
356 if (subentry) {
357 if (--subentry->recursionLevel == 0)
358 subentry->tt += tt;
359 else
360 ++subentry->recursivecallcount;
361 subentry->it += it;
362 ++subentry->callcount;
363 }
364 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000365}
366
367static void
368ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
369{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000370 /* entering a call to the function identified by 'key'
371 (which can be a PyCodeObject or a PyMethodDef pointer) */
372 ProfilerObject *pObj = (ProfilerObject*)self;
373 ProfilerEntry *profEntry;
374 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000375
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000376 /* In the case of entering a generator expression frame via a
377 * throw (gen_send_ex(.., 1)), we may already have an
378 * Exception set here. We must not mess around with this
379 * exception, and some of the code under here assumes that
380 * PyErr_* is its own to mess around with, so we have to
381 * save and restore any current exception. */
382 PyObject *last_type, *last_value, *last_tb;
383 PyErr_Fetch(&last_type, &last_value, &last_tb);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000384
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000385 profEntry = getEntry(pObj, key);
386 if (profEntry == NULL) {
387 profEntry = newProfilerEntry(pObj, key, userObj);
388 if (profEntry == NULL)
389 goto restorePyerr;
390 }
391 /* grab a ProfilerContext out of the free list */
392 pContext = pObj->freelistProfilerContext;
393 if (pContext) {
394 pObj->freelistProfilerContext = pContext->previous;
395 }
396 else {
397 /* free list exhausted, allocate a new one */
398 pContext = (ProfilerContext*)
399 malloc(sizeof(ProfilerContext));
400 if (pContext == NULL) {
401 pObj->flags |= POF_NOMEMORY;
402 goto restorePyerr;
403 }
404 }
405 initContext(pObj, pContext, profEntry);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000406
407restorePyerr:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000408 PyErr_Restore(last_type, last_value, last_tb);
Armin Rigoa871ef22006-02-08 12:53:56 +0000409}
410
411static void
412ptrace_leave_call(PyObject *self, void *key)
413{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000414 /* leaving a call to the function identified by 'key' */
415 ProfilerObject *pObj = (ProfilerObject*)self;
416 ProfilerEntry *profEntry;
417 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000418
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000419 pContext = pObj->currentProfilerContext;
420 if (pContext == NULL)
421 return;
422 profEntry = getEntry(pObj, key);
423 if (profEntry) {
424 Stop(pObj, pContext, profEntry);
425 }
426 else {
427 pObj->currentProfilerContext = pContext->previous;
428 }
429 /* put pContext into the free list */
430 pContext->previous = pObj->freelistProfilerContext;
431 pObj->freelistProfilerContext = pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000432}
433
434static int
435profiler_callback(PyObject *self, PyFrameObject *frame, int what,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000436 PyObject *arg)
Armin Rigoa871ef22006-02-08 12:53:56 +0000437{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000438 switch (what) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000439
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000440 /* the 'frame' of a called function is about to start its execution */
441 case PyTrace_CALL:
442 ptrace_enter_call(self, (void *)frame->f_code,
443 (PyObject *)frame->f_code);
444 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000445
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000446 /* the 'frame' of a called function is about to finish
447 (either normally or with an exception) */
448 case PyTrace_RETURN:
449 ptrace_leave_call(self, (void *)frame->f_code);
450 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000451
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000452 /* case PyTrace_EXCEPTION:
453 If the exception results in the function exiting, a
454 PyTrace_RETURN event will be generated, so we don't need to
455 handle it. */
Armin Rigoa871ef22006-02-08 12:53:56 +0000456
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000457#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */
458 /* the Python function 'frame' is issuing a call to the built-in
459 function 'arg' */
460 case PyTrace_C_CALL:
461 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
462 && PyCFunction_Check(arg)) {
463 ptrace_enter_call(self,
464 ((PyCFunctionObject *)arg)->m_ml,
465 arg);
466 }
467 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000468
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000469 /* the call to the built-in function 'arg' is returning into its
470 caller 'frame' */
471 case PyTrace_C_RETURN: /* ...normally */
472 case PyTrace_C_EXCEPTION: /* ...with an exception set */
473 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
474 && PyCFunction_Check(arg)) {
475 ptrace_leave_call(self,
476 ((PyCFunctionObject *)arg)->m_ml);
477 }
478 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000479#endif
480
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000481 default:
482 break;
483 }
484 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000485}
486
487static int
488pending_exception(ProfilerObject *pObj)
489{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000490 if (pObj->flags & POF_NOMEMORY) {
491 pObj->flags -= POF_NOMEMORY;
492 PyErr_SetString(PyExc_MemoryError,
493 "memory was exhausted while profiling");
494 return -1;
495 }
496 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000497}
498
499/************************************************************/
500
501static PyStructSequence_Field profiler_entry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000502 {"code", "code object or built-in function name"},
503 {"callcount", "how many times this was called"},
504 {"reccallcount", "how many times called recursively"},
505 {"totaltime", "total time in this entry"},
506 {"inlinetime", "inline time in this entry (not in subcalls)"},
507 {"calls", "details of the calls"},
508 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000509};
510
511static PyStructSequence_Field profiler_subentry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000512 {"code", "called code object or built-in function name"},
513 {"callcount", "how many times this is called"},
514 {"reccallcount", "how many times this is called recursively"},
515 {"totaltime", "total time spent in this call"},
516 {"inlinetime", "inline time (not in further subcalls)"},
517 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000518};
519
520static PyStructSequence_Desc profiler_entry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000521 "_lsprof.profiler_entry", /* name */
522 NULL, /* doc */
523 profiler_entry_fields,
524 6
Armin Rigoa871ef22006-02-08 12:53:56 +0000525};
526
527static PyStructSequence_Desc profiler_subentry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000528 "_lsprof.profiler_subentry", /* name */
529 NULL, /* doc */
530 profiler_subentry_fields,
531 5
Armin Rigoa871ef22006-02-08 12:53:56 +0000532};
533
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000534static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000535static PyTypeObject StatsEntryType;
536static PyTypeObject StatsSubEntryType;
537
538
539typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000540 PyObject *list;
541 PyObject *sublist;
542 double factor;
Armin Rigoa871ef22006-02-08 12:53:56 +0000543} statscollector_t;
544
545static int statsForSubEntry(rotating_node_t *node, void *arg)
546{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000547 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
548 statscollector_t *collect = (statscollector_t*) arg;
549 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
550 int err;
551 PyObject *sinfo;
552 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
553 "((Olldd))",
554 entry->userObj,
555 sentry->callcount,
556 sentry->recursivecallcount,
557 collect->factor * sentry->tt,
558 collect->factor * sentry->it);
559 if (sinfo == NULL)
560 return -1;
561 err = PyList_Append(collect->sublist, sinfo);
562 Py_DECREF(sinfo);
563 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000564}
565
566static int statsForEntry(rotating_node_t *node, void *arg)
567{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000568 ProfilerEntry *entry = (ProfilerEntry*) node;
569 statscollector_t *collect = (statscollector_t*) arg;
570 PyObject *info;
571 int err;
572 if (entry->callcount == 0)
573 return 0; /* skip */
Armin Rigoa871ef22006-02-08 12:53:56 +0000574
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000575 if (entry->calls != EMPTY_ROTATING_TREE) {
576 collect->sublist = PyList_New(0);
577 if (collect->sublist == NULL)
578 return -1;
579 if (RotatingTree_Enum(entry->calls,
580 statsForSubEntry, collect) != 0) {
581 Py_DECREF(collect->sublist);
582 return -1;
583 }
584 }
585 else {
586 Py_INCREF(Py_None);
587 collect->sublist = Py_None;
588 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000589
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000590 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
591 "((OllddO))",
592 entry->userObj,
593 entry->callcount,
594 entry->recursivecallcount,
595 collect->factor * entry->tt,
596 collect->factor * entry->it,
597 collect->sublist);
598 Py_DECREF(collect->sublist);
599 if (info == NULL)
600 return -1;
601 err = PyList_Append(collect->list, info);
602 Py_DECREF(info);
603 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000604}
605
606PyDoc_STRVAR(getstats_doc, "\
607getstats() -> list of profiler_entry objects\n\
608\n\
609Return all information collected by the profiler.\n\
610Each profiler_entry is a tuple-like object with the\n\
611following attributes:\n\
612\n\
613 code code object\n\
614 callcount how many times this was called\n\
615 reccallcount how many times called recursively\n\
616 totaltime total time in this entry\n\
617 inlinetime inline time in this entry (not in subcalls)\n\
618 calls details of the calls\n\
619\n\
620The calls attribute is either None or a list of\n\
621profiler_subentry objects:\n\
622\n\
623 code called code object\n\
624 callcount how many times this is called\n\
625 reccallcount how many times this is called recursively\n\
626 totaltime total time spent in this call\n\
627 inlinetime inline time (not in further subcalls)\n\
628");
629
630static PyObject*
631profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
632{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000633 statscollector_t collect;
634 if (pending_exception(pObj))
635 return NULL;
636 if (!pObj->externalTimer)
637 collect.factor = hpTimerUnit();
638 else if (pObj->externalTimerUnit > 0.0)
639 collect.factor = pObj->externalTimerUnit;
640 else
641 collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
642 collect.list = PyList_New(0);
643 if (collect.list == NULL)
644 return NULL;
645 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
646 != 0) {
647 Py_DECREF(collect.list);
648 return NULL;
649 }
650 return collect.list;
Armin Rigoa871ef22006-02-08 12:53:56 +0000651}
652
653static int
654setSubcalls(ProfilerObject *pObj, int nvalue)
655{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000656 if (nvalue == 0)
657 pObj->flags &= ~POF_SUBCALLS;
658 else if (nvalue > 0)
659 pObj->flags |= POF_SUBCALLS;
660 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000661}
662
663static int
664setBuiltins(ProfilerObject *pObj, int nvalue)
665{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000666 if (nvalue == 0)
667 pObj->flags &= ~POF_BUILTINS;
668 else if (nvalue > 0) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000669#ifndef PyTrace_C_CALL
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000670 PyErr_SetString(PyExc_ValueError,
671 "builtins=True requires Python >= 2.4");
672 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000673#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000674 pObj->flags |= POF_BUILTINS;
Armin Rigoa871ef22006-02-08 12:53:56 +0000675#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000676 }
677 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000678}
679
680PyDoc_STRVAR(enable_doc, "\
681enable(subcalls=True, builtins=True)\n\
682\n\
683Start collecting profiling information.\n\
684If 'subcalls' is True, also records for each function\n\
685statistics separated according to its current caller.\n\
686If 'builtins' is True, records the time spent in\n\
687built-in functions separately from their caller.\n\
688");
689
690static PyObject*
691profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
692{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000693 int subcalls = -1;
694 int builtins = -1;
695 static char *kwlist[] = {"subcalls", "builtins", 0};
696 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
697 kwlist, &subcalls, &builtins))
698 return NULL;
699 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
700 return NULL;
701 PyEval_SetProfile(profiler_callback, (PyObject*)self);
702 self->flags |= POF_ENABLED;
703 Py_INCREF(Py_None);
704 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000705}
706
707static void
708flush_unmatched(ProfilerObject *pObj)
709{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000710 while (pObj->currentProfilerContext) {
711 ProfilerContext *pContext = pObj->currentProfilerContext;
712 ProfilerEntry *profEntry= pContext->ctxEntry;
713 if (profEntry)
714 Stop(pObj, pContext, profEntry);
715 else
716 pObj->currentProfilerContext = pContext->previous;
717 if (pContext)
718 free(pContext);
719 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000720
721}
722
723PyDoc_STRVAR(disable_doc, "\
724disable()\n\
725\n\
726Stop collecting profiling information.\n\
727");
728
729static PyObject*
730profiler_disable(ProfilerObject *self, PyObject* noarg)
731{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000732 self->flags &= ~POF_ENABLED;
733 PyEval_SetProfile(NULL, NULL);
734 flush_unmatched(self);
735 if (pending_exception(self))
736 return NULL;
737 Py_INCREF(Py_None);
738 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000739}
740
741PyDoc_STRVAR(clear_doc, "\
742clear()\n\
743\n\
744Clear all profiling information collected so far.\n\
745");
746
747static PyObject*
748profiler_clear(ProfilerObject *pObj, PyObject* noarg)
749{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000750 clearEntries(pObj);
751 Py_INCREF(Py_None);
752 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000753}
754
755static void
756profiler_dealloc(ProfilerObject *op)
757{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000758 if (op->flags & POF_ENABLED)
759 PyEval_SetProfile(NULL, NULL);
760 flush_unmatched(op);
761 clearEntries(op);
762 Py_XDECREF(op->externalTimer);
763 Py_TYPE(op)->tp_free(op);
Armin Rigoa871ef22006-02-08 12:53:56 +0000764}
765
766static int
767profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
768{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000769 PyObject *o;
770 PyObject *timer = NULL;
771 double timeunit = 0.0;
772 int subcalls = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000773#ifdef PyTrace_C_CALL
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000774 int builtins = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000775#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000776 int builtins = 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000777#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000778 static char *kwlist[] = {"timer", "timeunit",
779 "subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000780
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000781 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
782 &timer, &timeunit,
783 &subcalls, &builtins))
784 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000785
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000786 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
787 return -1;
788 o = pObj->externalTimer;
789 pObj->externalTimer = timer;
790 Py_XINCREF(timer);
791 Py_XDECREF(o);
792 pObj->externalTimerUnit = timeunit;
793 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000794}
795
796static PyMethodDef profiler_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000797 {"getstats", (PyCFunction)profiler_getstats,
798 METH_NOARGS, getstats_doc},
799 {"enable", (PyCFunction)profiler_enable,
800 METH_VARARGS | METH_KEYWORDS, enable_doc},
801 {"disable", (PyCFunction)profiler_disable,
802 METH_NOARGS, disable_doc},
803 {"clear", (PyCFunction)profiler_clear,
804 METH_NOARGS, clear_doc},
805 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000806};
807
808PyDoc_STRVAR(profiler_doc, "\
809Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
810\n\
811 Builds a profiler object using the specified timer function.\n\
812 The default timer is a fast built-in one based on real time.\n\
813 For custom timer functions returning integers, time_unit can\n\
814 be a float specifying a scale (i.e. how long each integer unit\n\
815 is, in seconds).\n\
816");
817
Neal Norwitz227b5332006-03-22 09:28:35 +0000818static PyTypeObject PyProfiler_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000819 PyVarObject_HEAD_INIT(NULL, 0)
820 "_lsprof.Profiler", /* tp_name */
821 sizeof(ProfilerObject), /* tp_basicsize */
822 0, /* tp_itemsize */
823 (destructor)profiler_dealloc, /* tp_dealloc */
824 0, /* tp_print */
825 0, /* tp_getattr */
826 0, /* tp_setattr */
827 0, /* tp_reserved */
828 0, /* tp_repr */
829 0, /* tp_as_number */
830 0, /* tp_as_sequence */
831 0, /* tp_as_mapping */
832 0, /* tp_hash */
833 0, /* tp_call */
834 0, /* tp_str */
835 0, /* tp_getattro */
836 0, /* tp_setattro */
837 0, /* tp_as_buffer */
838 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
839 profiler_doc, /* tp_doc */
840 0, /* tp_traverse */
841 0, /* tp_clear */
842 0, /* tp_richcompare */
843 0, /* tp_weaklistoffset */
844 0, /* tp_iter */
845 0, /* tp_iternext */
846 profiler_methods, /* tp_methods */
847 0, /* tp_members */
848 0, /* tp_getset */
849 0, /* tp_base */
850 0, /* tp_dict */
851 0, /* tp_descr_get */
852 0, /* tp_descr_set */
853 0, /* tp_dictoffset */
854 (initproc)profiler_init, /* tp_init */
855 PyType_GenericAlloc, /* tp_alloc */
856 PyType_GenericNew, /* tp_new */
857 PyObject_Del, /* tp_free */
Armin Rigoa871ef22006-02-08 12:53:56 +0000858};
859
860static PyMethodDef moduleMethods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000861 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000862};
863
Martin v. Löwis1a214512008-06-11 05:26:20 +0000864
865static struct PyModuleDef _lsprofmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000866 PyModuleDef_HEAD_INIT,
867 "_lsprof",
868 "Fast profiler",
869 -1,
870 moduleMethods,
871 NULL,
872 NULL,
873 NULL,
874 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000875};
876
Armin Rigoa871ef22006-02-08 12:53:56 +0000877PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000878PyInit__lsprof(void)
Armin Rigoa871ef22006-02-08 12:53:56 +0000879{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000880 PyObject *module, *d;
881 module = PyModule_Create(&_lsprofmodule);
882 if (module == NULL)
883 return NULL;
884 d = PyModule_GetDict(module);
885 if (PyType_Ready(&PyProfiler_Type) < 0)
886 return NULL;
887 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
Armin Rigoa871ef22006-02-08 12:53:56 +0000888
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000889 if (!initialized) {
890 PyStructSequence_InitType(&StatsEntryType,
891 &profiler_entry_desc);
892 PyStructSequence_InitType(&StatsSubEntryType,
893 &profiler_subentry_desc);
894 }
895 Py_INCREF((PyObject*) &StatsEntryType);
896 Py_INCREF((PyObject*) &StatsSubEntryType);
897 PyModule_AddObject(module, "profiler_entry",
898 (PyObject*) &StatsEntryType);
899 PyModule_AddObject(module, "profiler_subentry",
900 (PyObject*) &StatsSubEntryType);
901 empty_tuple = PyTuple_New(0);
902 initialized = 1;
903 return module;
Armin Rigoa871ef22006-02-08 12:53:56 +0000904}