blob: fef255fdf5441ea6fbcf533a2448c1eae133bb21 [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
Armin Rigoa871ef22006-02-08 12:53:56 +000039#include <sys/resource.h>
40#include <sys/times.h>
Armin Rigoa871ef22006-02-08 12:53:56 +000041
42static PY_LONG_LONG
43hpTimer(void)
44{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000045 struct timeval tv;
46 PY_LONG_LONG ret;
Armin Rigoa871ef22006-02-08 12:53:56 +000047#ifdef GETTIMEOFDAY_NO_TZ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000048 gettimeofday(&tv);
Armin Rigoa871ef22006-02-08 12:53:56 +000049#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000050 gettimeofday(&tv, (struct timezone *)NULL);
Armin Rigoa871ef22006-02-08 12:53:56 +000051#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000052 ret = tv.tv_sec;
53 ret = ret * 1000000 + tv.tv_usec;
54 return ret;
Armin Rigoa871ef22006-02-08 12:53:56 +000055}
56
57static double
58hpTimerUnit(void)
59{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000060 return 0.000001;
Armin Rigoa871ef22006-02-08 12:53:56 +000061}
62
63#endif /* MS_WINDOWS */
64
65/************************************************************/
66/* Written by Brett Rosen and Ted Czotter */
67
68struct _ProfilerEntry;
69
70/* represents a function called from another function */
71typedef struct _ProfilerSubEntry {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000072 rotating_node_t header;
73 PY_LONG_LONG tt;
74 PY_LONG_LONG it;
75 long callcount;
76 long recursivecallcount;
77 long recursionLevel;
Armin Rigoa871ef22006-02-08 12:53:56 +000078} ProfilerSubEntry;
79
80/* represents a function or user defined block */
81typedef struct _ProfilerEntry {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000082 rotating_node_t header;
83 PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
84 PY_LONG_LONG tt; /* total time in this entry */
85 PY_LONG_LONG it; /* inline time in this entry (not in subcalls) */
86 long callcount; /* how many times this was called */
87 long recursivecallcount; /* how many times called recursively */
88 long recursionLevel;
89 rotating_node_t *calls;
Armin Rigoa871ef22006-02-08 12:53:56 +000090} ProfilerEntry;
91
92typedef struct _ProfilerContext {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000093 PY_LONG_LONG t0;
94 PY_LONG_LONG subt;
95 struct _ProfilerContext *previous;
96 ProfilerEntry *ctxEntry;
Armin Rigoa871ef22006-02-08 12:53:56 +000097} ProfilerContext;
98
99typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000100 PyObject_HEAD
101 rotating_node_t *profilerEntries;
102 ProfilerContext *currentProfilerContext;
103 ProfilerContext *freelistProfilerContext;
104 int flags;
105 PyObject *externalTimer;
106 double externalTimerUnit;
Armin Rigoa871ef22006-02-08 12:53:56 +0000107} ProfilerObject;
108
109#define POF_ENABLED 0x001
110#define POF_SUBCALLS 0x002
111#define POF_BUILTINS 0x004
112#define POF_NOMEMORY 0x100
113
Neal Norwitz227b5332006-03-22 09:28:35 +0000114static PyTypeObject PyProfiler_Type;
Armin Rigoa871ef22006-02-08 12:53:56 +0000115
116#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
Christian Heimes90aa7642007-12-19 02:45:37 +0000117#define PyProfiler_CheckExact(op) (Py_TYPE(op) == &PyProfiler_Type)
Armin Rigoa871ef22006-02-08 12:53:56 +0000118
119/*** External Timers ***/
120
121#define DOUBLE_TIMER_PRECISION 4294967296.0
122static PyObject *empty_tuple;
123
124static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj)
125{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000126 PY_LONG_LONG result;
127 PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL);
128 if (o == NULL) {
129 PyErr_WriteUnraisable(pObj->externalTimer);
130 return 0;
131 }
132 if (pObj->externalTimerUnit > 0.0) {
133 /* interpret the result as an integer that will be scaled
134 in profiler_getstats() */
135 result = PyLong_AsLongLong(o);
136 }
137 else {
138 /* interpret the result as a double measured in seconds.
139 As the profiler works with PY_LONG_LONG internally
140 we convert it to a large integer */
141 double val = PyFloat_AsDouble(o);
142 /* error handling delayed to the code below */
143 result = (PY_LONG_LONG) (val * DOUBLE_TIMER_PRECISION);
144 }
145 Py_DECREF(o);
146 if (PyErr_Occurred()) {
147 PyErr_WriteUnraisable(pObj->externalTimer);
148 return 0;
149 }
150 return result;
Armin Rigoa871ef22006-02-08 12:53:56 +0000151}
152
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000153#define CALL_TIMER(pObj) ((pObj)->externalTimer ? \
154 CallExternalTimer(pObj) : \
155 hpTimer())
Armin Rigoa871ef22006-02-08 12:53:56 +0000156
157/*** ProfilerObject ***/
158
159static PyObject *
160normalizeUserObj(PyObject *obj)
161{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000162 PyCFunctionObject *fn;
163 if (!PyCFunction_Check(obj)) {
164 Py_INCREF(obj);
165 return obj;
166 }
167 /* Replace built-in function objects with a descriptive string
168 because of built-in methods -- keeping a reference to
169 __self__ is probably not a good idea. */
170 fn = (PyCFunctionObject *)obj;
Armin Rigoa871ef22006-02-08 12:53:56 +0000171
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000172 if (fn->m_self == NULL) {
173 /* built-in function: look up the module name */
174 PyObject *mod = fn->m_module;
Victor Stinner7edb5df2011-06-20 14:59:53 +0200175 PyObject *modname = NULL;
176 if (mod != NULL) {
177 if (PyUnicode_Check(mod)) {
178 modname = mod;
179 Py_INCREF(modname);
180 }
181 else if (PyModule_Check(mod)) {
182 modname = PyModule_GetNameObject(mod);
183 if (modname == NULL)
184 PyErr_Clear();
Alexander Belopolskye239d232010-12-08 23:31:48 +0000185 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000186 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200187 if (modname != NULL) {
188 if (PyUnicode_CompareWithASCIIString(modname, "builtins") != 0) {
189 PyObject *result;
190 result = PyUnicode_FromFormat("<%U.%s>", modname,
191 fn->m_ml->ml_name);
192 Py_DECREF(modname);
193 return result;
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000194 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200195 Py_DECREF(modname);
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000196 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200197 return PyUnicode_FromFormat("<%s>", fn->m_ml->ml_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000198 }
199 else {
200 /* built-in method: try to return
201 repr(getattr(type(__self__), __name__))
202 */
203 PyObject *self = fn->m_self;
204 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
205 if (name != NULL) {
206 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
207 Py_XINCREF(mo);
208 Py_DECREF(name);
209 if (mo != NULL) {
210 PyObject *res = PyObject_Repr(mo);
211 Py_DECREF(mo);
212 if (res != NULL)
213 return res;
214 }
215 }
216 PyErr_Clear();
217 return PyUnicode_FromFormat("<built-in method %s>",
218 fn->m_ml->ml_name);
219 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000220}
221
222static ProfilerEntry*
223newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
224{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000225 ProfilerEntry *self;
Victor Stinnerb6404912013-07-07 16:21:41 +0200226 self = (ProfilerEntry*) PyMem_Malloc(sizeof(ProfilerEntry));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000227 if (self == NULL) {
228 pObj->flags |= POF_NOMEMORY;
229 return NULL;
230 }
231 userObj = normalizeUserObj(userObj);
232 if (userObj == NULL) {
233 PyErr_Clear();
Victor Stinnerb6404912013-07-07 16:21:41 +0200234 PyMem_Free(self);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000235 pObj->flags |= POF_NOMEMORY;
236 return NULL;
237 }
238 self->header.key = key;
239 self->userObj = userObj;
240 self->tt = 0;
241 self->it = 0;
242 self->callcount = 0;
243 self->recursivecallcount = 0;
244 self->recursionLevel = 0;
245 self->calls = EMPTY_ROTATING_TREE;
246 RotatingTree_Add(&pObj->profilerEntries, &self->header);
247 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000248}
249
250static ProfilerEntry*
251getEntry(ProfilerObject *pObj, void *key)
252{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000253 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
Armin Rigoa871ef22006-02-08 12:53:56 +0000254}
255
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000256static ProfilerSubEntry *
Armin Rigoa871ef22006-02-08 12:53:56 +0000257getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
258{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000259 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
260 (void *)entry);
Armin Rigoa871ef22006-02-08 12:53:56 +0000261}
262
263static ProfilerSubEntry *
264newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
265{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000266 ProfilerSubEntry *self;
Victor Stinnerb6404912013-07-07 16:21:41 +0200267 self = (ProfilerSubEntry*) PyMem_Malloc(sizeof(ProfilerSubEntry));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000268 if (self == NULL) {
269 pObj->flags |= POF_NOMEMORY;
270 return NULL;
271 }
272 self->header.key = (void *)entry;
273 self->tt = 0;
274 self->it = 0;
275 self->callcount = 0;
276 self->recursivecallcount = 0;
277 self->recursionLevel = 0;
278 RotatingTree_Add(&caller->calls, &self->header);
279 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000280}
281
282static int freeSubEntry(rotating_node_t *header, void *arg)
283{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000284 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
Victor Stinnerb6404912013-07-07 16:21:41 +0200285 PyMem_Free(subentry);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000286 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000287}
288
289static int freeEntry(rotating_node_t *header, void *arg)
290{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 ProfilerEntry *entry = (ProfilerEntry*) header;
292 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
293 Py_DECREF(entry->userObj);
Victor Stinnerb6404912013-07-07 16:21:41 +0200294 PyMem_Free(entry);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000295 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000296}
297
298static void clearEntries(ProfilerObject *pObj)
299{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000300 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
301 pObj->profilerEntries = EMPTY_ROTATING_TREE;
302 /* release the memory hold by the ProfilerContexts */
303 if (pObj->currentProfilerContext) {
Victor Stinnerb6404912013-07-07 16:21:41 +0200304 PyMem_Free(pObj->currentProfilerContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000305 pObj->currentProfilerContext = NULL;
306 }
307 while (pObj->freelistProfilerContext) {
308 ProfilerContext *c = pObj->freelistProfilerContext;
309 pObj->freelistProfilerContext = c->previous;
Victor Stinnerb6404912013-07-07 16:21:41 +0200310 PyMem_Free(c);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000311 }
312 pObj->freelistProfilerContext = NULL;
Armin Rigoa871ef22006-02-08 12:53:56 +0000313}
314
315static void
316initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
317{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000318 self->ctxEntry = entry;
319 self->subt = 0;
320 self->previous = pObj->currentProfilerContext;
321 pObj->currentProfilerContext = self;
322 ++entry->recursionLevel;
323 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
324 /* find or create an entry for me in my caller's entry */
325 ProfilerEntry *caller = self->previous->ctxEntry;
326 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
327 if (subentry == NULL)
328 subentry = newSubEntry(pObj, caller, entry);
329 if (subentry)
330 ++subentry->recursionLevel;
331 }
332 self->t0 = CALL_TIMER(pObj);
Armin Rigoa871ef22006-02-08 12:53:56 +0000333}
334
335static void
336Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
337{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000338 PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0;
339 PY_LONG_LONG it = tt - self->subt;
340 if (self->previous)
341 self->previous->subt += tt;
342 pObj->currentProfilerContext = self->previous;
343 if (--entry->recursionLevel == 0)
344 entry->tt += tt;
345 else
346 ++entry->recursivecallcount;
347 entry->it += it;
348 entry->callcount++;
349 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
350 /* find or create an entry for me in my caller's entry */
351 ProfilerEntry *caller = self->previous->ctxEntry;
352 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
353 if (subentry) {
354 if (--subentry->recursionLevel == 0)
355 subentry->tt += tt;
356 else
357 ++subentry->recursivecallcount;
358 subentry->it += it;
359 ++subentry->callcount;
360 }
361 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000362}
363
364static void
365ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
366{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 /* entering a call to the function identified by 'key'
368 (which can be a PyCodeObject or a PyMethodDef pointer) */
369 ProfilerObject *pObj = (ProfilerObject*)self;
370 ProfilerEntry *profEntry;
371 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000372
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000373 /* In the case of entering a generator expression frame via a
374 * throw (gen_send_ex(.., 1)), we may already have an
375 * Exception set here. We must not mess around with this
376 * exception, and some of the code under here assumes that
377 * PyErr_* is its own to mess around with, so we have to
378 * save and restore any current exception. */
379 PyObject *last_type, *last_value, *last_tb;
380 PyErr_Fetch(&last_type, &last_value, &last_tb);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000381
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000382 profEntry = getEntry(pObj, key);
383 if (profEntry == NULL) {
384 profEntry = newProfilerEntry(pObj, key, userObj);
385 if (profEntry == NULL)
386 goto restorePyerr;
387 }
388 /* grab a ProfilerContext out of the free list */
389 pContext = pObj->freelistProfilerContext;
390 if (pContext) {
391 pObj->freelistProfilerContext = pContext->previous;
392 }
393 else {
394 /* free list exhausted, allocate a new one */
395 pContext = (ProfilerContext*)
Victor Stinnerb6404912013-07-07 16:21:41 +0200396 PyMem_Malloc(sizeof(ProfilerContext));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000397 if (pContext == NULL) {
398 pObj->flags |= POF_NOMEMORY;
399 goto restorePyerr;
400 }
401 }
402 initContext(pObj, pContext, profEntry);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000403
404restorePyerr:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000405 PyErr_Restore(last_type, last_value, last_tb);
Armin Rigoa871ef22006-02-08 12:53:56 +0000406}
407
408static void
409ptrace_leave_call(PyObject *self, void *key)
410{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000411 /* leaving a call to the function identified by 'key' */
412 ProfilerObject *pObj = (ProfilerObject*)self;
413 ProfilerEntry *profEntry;
414 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000415
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000416 pContext = pObj->currentProfilerContext;
417 if (pContext == NULL)
418 return;
419 profEntry = getEntry(pObj, key);
420 if (profEntry) {
421 Stop(pObj, pContext, profEntry);
422 }
423 else {
424 pObj->currentProfilerContext = pContext->previous;
425 }
426 /* put pContext into the free list */
427 pContext->previous = pObj->freelistProfilerContext;
428 pObj->freelistProfilerContext = pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000429}
430
431static int
432profiler_callback(PyObject *self, PyFrameObject *frame, int what,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000433 PyObject *arg)
Armin Rigoa871ef22006-02-08 12:53:56 +0000434{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000435 switch (what) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000436
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000437 /* the 'frame' of a called function is about to start its execution */
438 case PyTrace_CALL:
439 ptrace_enter_call(self, (void *)frame->f_code,
440 (PyObject *)frame->f_code);
441 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000442
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000443 /* the 'frame' of a called function is about to finish
444 (either normally or with an exception) */
445 case PyTrace_RETURN:
446 ptrace_leave_call(self, (void *)frame->f_code);
447 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000448
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000449 /* case PyTrace_EXCEPTION:
450 If the exception results in the function exiting, a
451 PyTrace_RETURN event will be generated, so we don't need to
452 handle it. */
Armin Rigoa871ef22006-02-08 12:53:56 +0000453
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000454#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */
455 /* the Python function 'frame' is issuing a call to the built-in
456 function 'arg' */
457 case PyTrace_C_CALL:
458 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
459 && PyCFunction_Check(arg)) {
460 ptrace_enter_call(self,
461 ((PyCFunctionObject *)arg)->m_ml,
462 arg);
463 }
464 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000465
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000466 /* the call to the built-in function 'arg' is returning into its
467 caller 'frame' */
468 case PyTrace_C_RETURN: /* ...normally */
469 case PyTrace_C_EXCEPTION: /* ...with an exception set */
470 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
471 && PyCFunction_Check(arg)) {
472 ptrace_leave_call(self,
473 ((PyCFunctionObject *)arg)->m_ml);
474 }
475 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000476#endif
477
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000478 default:
479 break;
480 }
481 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000482}
483
484static int
485pending_exception(ProfilerObject *pObj)
486{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000487 if (pObj->flags & POF_NOMEMORY) {
488 pObj->flags -= POF_NOMEMORY;
489 PyErr_SetString(PyExc_MemoryError,
490 "memory was exhausted while profiling");
491 return -1;
492 }
493 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000494}
495
496/************************************************************/
497
498static PyStructSequence_Field profiler_entry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000499 {"code", "code object or built-in function name"},
500 {"callcount", "how many times this was called"},
501 {"reccallcount", "how many times called recursively"},
502 {"totaltime", "total time in this entry"},
503 {"inlinetime", "inline time in this entry (not in subcalls)"},
504 {"calls", "details of the calls"},
505 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000506};
507
508static PyStructSequence_Field profiler_subentry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000509 {"code", "called code object or built-in function name"},
510 {"callcount", "how many times this is called"},
511 {"reccallcount", "how many times this is called recursively"},
512 {"totaltime", "total time spent in this call"},
513 {"inlinetime", "inline time (not in further subcalls)"},
514 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000515};
516
517static PyStructSequence_Desc profiler_entry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000518 "_lsprof.profiler_entry", /* name */
519 NULL, /* doc */
520 profiler_entry_fields,
521 6
Armin Rigoa871ef22006-02-08 12:53:56 +0000522};
523
524static PyStructSequence_Desc profiler_subentry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000525 "_lsprof.profiler_subentry", /* name */
526 NULL, /* doc */
527 profiler_subentry_fields,
528 5
Armin Rigoa871ef22006-02-08 12:53:56 +0000529};
530
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000531static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000532static PyTypeObject StatsEntryType;
533static PyTypeObject StatsSubEntryType;
534
535
536typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000537 PyObject *list;
538 PyObject *sublist;
539 double factor;
Armin Rigoa871ef22006-02-08 12:53:56 +0000540} statscollector_t;
541
542static int statsForSubEntry(rotating_node_t *node, void *arg)
543{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000544 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
545 statscollector_t *collect = (statscollector_t*) arg;
546 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
547 int err;
548 PyObject *sinfo;
549 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
550 "((Olldd))",
551 entry->userObj,
552 sentry->callcount,
553 sentry->recursivecallcount,
554 collect->factor * sentry->tt,
555 collect->factor * sentry->it);
556 if (sinfo == NULL)
557 return -1;
558 err = PyList_Append(collect->sublist, sinfo);
559 Py_DECREF(sinfo);
560 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000561}
562
563static int statsForEntry(rotating_node_t *node, void *arg)
564{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000565 ProfilerEntry *entry = (ProfilerEntry*) node;
566 statscollector_t *collect = (statscollector_t*) arg;
567 PyObject *info;
568 int err;
569 if (entry->callcount == 0)
570 return 0; /* skip */
Armin Rigoa871ef22006-02-08 12:53:56 +0000571
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000572 if (entry->calls != EMPTY_ROTATING_TREE) {
573 collect->sublist = PyList_New(0);
574 if (collect->sublist == NULL)
575 return -1;
576 if (RotatingTree_Enum(entry->calls,
577 statsForSubEntry, collect) != 0) {
578 Py_DECREF(collect->sublist);
579 return -1;
580 }
581 }
582 else {
583 Py_INCREF(Py_None);
584 collect->sublist = Py_None;
585 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000586
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000587 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
588 "((OllddO))",
589 entry->userObj,
590 entry->callcount,
591 entry->recursivecallcount,
592 collect->factor * entry->tt,
593 collect->factor * entry->it,
594 collect->sublist);
595 Py_DECREF(collect->sublist);
596 if (info == NULL)
597 return -1;
598 err = PyList_Append(collect->list, info);
599 Py_DECREF(info);
600 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000601}
602
603PyDoc_STRVAR(getstats_doc, "\
604getstats() -> list of profiler_entry objects\n\
605\n\
606Return all information collected by the profiler.\n\
607Each profiler_entry is a tuple-like object with the\n\
608following attributes:\n\
609\n\
610 code code object\n\
611 callcount how many times this was called\n\
612 reccallcount how many times called recursively\n\
613 totaltime total time in this entry\n\
614 inlinetime inline time in this entry (not in subcalls)\n\
615 calls details of the calls\n\
616\n\
617The calls attribute is either None or a list of\n\
618profiler_subentry objects:\n\
619\n\
620 code called code object\n\
621 callcount how many times this is called\n\
622 reccallcount how many times this is called recursively\n\
623 totaltime total time spent in this call\n\
624 inlinetime inline time (not in further subcalls)\n\
625");
626
627static PyObject*
628profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
629{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000630 statscollector_t collect;
631 if (pending_exception(pObj))
632 return NULL;
633 if (!pObj->externalTimer)
634 collect.factor = hpTimerUnit();
635 else if (pObj->externalTimerUnit > 0.0)
636 collect.factor = pObj->externalTimerUnit;
637 else
638 collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
639 collect.list = PyList_New(0);
640 if (collect.list == NULL)
641 return NULL;
642 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
643 != 0) {
644 Py_DECREF(collect.list);
645 return NULL;
646 }
647 return collect.list;
Armin Rigoa871ef22006-02-08 12:53:56 +0000648}
649
650static int
651setSubcalls(ProfilerObject *pObj, int nvalue)
652{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000653 if (nvalue == 0)
654 pObj->flags &= ~POF_SUBCALLS;
655 else if (nvalue > 0)
656 pObj->flags |= POF_SUBCALLS;
657 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000658}
659
660static int
661setBuiltins(ProfilerObject *pObj, int nvalue)
662{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000663 if (nvalue == 0)
664 pObj->flags &= ~POF_BUILTINS;
665 else if (nvalue > 0) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000666#ifndef PyTrace_C_CALL
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000667 PyErr_SetString(PyExc_ValueError,
668 "builtins=True requires Python >= 2.4");
669 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000670#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000671 pObj->flags |= POF_BUILTINS;
Armin Rigoa871ef22006-02-08 12:53:56 +0000672#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000673 }
674 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000675}
676
677PyDoc_STRVAR(enable_doc, "\
678enable(subcalls=True, builtins=True)\n\
679\n\
680Start collecting profiling information.\n\
681If 'subcalls' is True, also records for each function\n\
682statistics separated according to its current caller.\n\
683If 'builtins' is True, records the time spent in\n\
684built-in functions separately from their caller.\n\
685");
686
687static PyObject*
688profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
689{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000690 int subcalls = -1;
691 int builtins = -1;
692 static char *kwlist[] = {"subcalls", "builtins", 0};
693 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
694 kwlist, &subcalls, &builtins))
695 return NULL;
696 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
697 return NULL;
698 PyEval_SetProfile(profiler_callback, (PyObject*)self);
699 self->flags |= POF_ENABLED;
700 Py_INCREF(Py_None);
701 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000702}
703
704static void
705flush_unmatched(ProfilerObject *pObj)
706{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000707 while (pObj->currentProfilerContext) {
708 ProfilerContext *pContext = pObj->currentProfilerContext;
709 ProfilerEntry *profEntry= pContext->ctxEntry;
710 if (profEntry)
711 Stop(pObj, pContext, profEntry);
712 else
713 pObj->currentProfilerContext = pContext->previous;
714 if (pContext)
Victor Stinnerb6404912013-07-07 16:21:41 +0200715 PyMem_Free(pContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000716 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000717
718}
719
720PyDoc_STRVAR(disable_doc, "\
721disable()\n\
722\n\
723Stop collecting profiling information.\n\
724");
725
726static PyObject*
727profiler_disable(ProfilerObject *self, PyObject* noarg)
728{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000729 self->flags &= ~POF_ENABLED;
730 PyEval_SetProfile(NULL, NULL);
731 flush_unmatched(self);
732 if (pending_exception(self))
733 return NULL;
734 Py_INCREF(Py_None);
735 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000736}
737
738PyDoc_STRVAR(clear_doc, "\
739clear()\n\
740\n\
741Clear all profiling information collected so far.\n\
742");
743
744static PyObject*
745profiler_clear(ProfilerObject *pObj, PyObject* noarg)
746{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000747 clearEntries(pObj);
748 Py_INCREF(Py_None);
749 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000750}
751
752static void
753profiler_dealloc(ProfilerObject *op)
754{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000755 if (op->flags & POF_ENABLED)
756 PyEval_SetProfile(NULL, NULL);
757 flush_unmatched(op);
758 clearEntries(op);
759 Py_XDECREF(op->externalTimer);
760 Py_TYPE(op)->tp_free(op);
Armin Rigoa871ef22006-02-08 12:53:56 +0000761}
762
763static int
764profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
765{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000766 PyObject *o;
767 PyObject *timer = NULL;
768 double timeunit = 0.0;
769 int subcalls = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000770#ifdef PyTrace_C_CALL
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000771 int builtins = 1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000772#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000773 int builtins = 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000774#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000775 static char *kwlist[] = {"timer", "timeunit",
776 "subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000777
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000778 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
779 &timer, &timeunit,
780 &subcalls, &builtins))
781 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000782
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000783 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
784 return -1;
785 o = pObj->externalTimer;
786 pObj->externalTimer = timer;
787 Py_XINCREF(timer);
788 Py_XDECREF(o);
789 pObj->externalTimerUnit = timeunit;
790 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000791}
792
793static PyMethodDef profiler_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000794 {"getstats", (PyCFunction)profiler_getstats,
795 METH_NOARGS, getstats_doc},
796 {"enable", (PyCFunction)profiler_enable,
797 METH_VARARGS | METH_KEYWORDS, enable_doc},
798 {"disable", (PyCFunction)profiler_disable,
799 METH_NOARGS, disable_doc},
800 {"clear", (PyCFunction)profiler_clear,
801 METH_NOARGS, clear_doc},
802 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000803};
804
805PyDoc_STRVAR(profiler_doc, "\
806Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
807\n\
808 Builds a profiler object using the specified timer function.\n\
809 The default timer is a fast built-in one based on real time.\n\
810 For custom timer functions returning integers, time_unit can\n\
811 be a float specifying a scale (i.e. how long each integer unit\n\
812 is, in seconds).\n\
813");
814
Neal Norwitz227b5332006-03-22 09:28:35 +0000815static PyTypeObject PyProfiler_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000816 PyVarObject_HEAD_INIT(NULL, 0)
817 "_lsprof.Profiler", /* tp_name */
818 sizeof(ProfilerObject), /* tp_basicsize */
819 0, /* tp_itemsize */
820 (destructor)profiler_dealloc, /* tp_dealloc */
821 0, /* tp_print */
822 0, /* tp_getattr */
823 0, /* tp_setattr */
824 0, /* tp_reserved */
825 0, /* tp_repr */
826 0, /* tp_as_number */
827 0, /* tp_as_sequence */
828 0, /* tp_as_mapping */
829 0, /* tp_hash */
830 0, /* tp_call */
831 0, /* tp_str */
832 0, /* tp_getattro */
833 0, /* tp_setattro */
834 0, /* tp_as_buffer */
835 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
836 profiler_doc, /* tp_doc */
837 0, /* tp_traverse */
838 0, /* tp_clear */
839 0, /* tp_richcompare */
840 0, /* tp_weaklistoffset */
841 0, /* tp_iter */
842 0, /* tp_iternext */
843 profiler_methods, /* tp_methods */
844 0, /* tp_members */
845 0, /* tp_getset */
846 0, /* tp_base */
847 0, /* tp_dict */
848 0, /* tp_descr_get */
849 0, /* tp_descr_set */
850 0, /* tp_dictoffset */
851 (initproc)profiler_init, /* tp_init */
852 PyType_GenericAlloc, /* tp_alloc */
853 PyType_GenericNew, /* tp_new */
854 PyObject_Del, /* tp_free */
Armin Rigoa871ef22006-02-08 12:53:56 +0000855};
856
857static PyMethodDef moduleMethods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000858 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000859};
860
Martin v. Löwis1a214512008-06-11 05:26:20 +0000861
862static struct PyModuleDef _lsprofmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000863 PyModuleDef_HEAD_INIT,
864 "_lsprof",
865 "Fast profiler",
866 -1,
867 moduleMethods,
868 NULL,
869 NULL,
870 NULL,
871 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000872};
873
Armin Rigoa871ef22006-02-08 12:53:56 +0000874PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000875PyInit__lsprof(void)
Armin Rigoa871ef22006-02-08 12:53:56 +0000876{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000877 PyObject *module, *d;
878 module = PyModule_Create(&_lsprofmodule);
879 if (module == NULL)
880 return NULL;
881 d = PyModule_GetDict(module);
882 if (PyType_Ready(&PyProfiler_Type) < 0)
883 return NULL;
884 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
Armin Rigoa871ef22006-02-08 12:53:56 +0000885
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000886 if (!initialized) {
887 PyStructSequence_InitType(&StatsEntryType,
888 &profiler_entry_desc);
889 PyStructSequence_InitType(&StatsSubEntryType,
890 &profiler_subentry_desc);
891 }
892 Py_INCREF((PyObject*) &StatsEntryType);
893 Py_INCREF((PyObject*) &StatsSubEntryType);
894 PyModule_AddObject(module, "profiler_entry",
895 (PyObject*) &StatsEntryType);
896 PyModule_AddObject(module, "profiler_subentry",
897 (PyObject*) &StatsSubEntryType);
898 empty_tuple = PyTuple_New(0);
899 initialized = 1;
900 return module;
Armin Rigoa871ef22006-02-08 12:53:56 +0000901}