blob: 0137d9544375268aedb2f85a15e91d09fdfef4bd [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) {
Victor Stinnerbd303c12013-11-07 23:07:29 +0100188 if (PyUnicode_CompareWithASCIIString(modname, "builtins") != 0) {
Victor Stinner7edb5df2011-06-20 14:59:53 +0200189 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 /* the Python function 'frame' is issuing a call to the built-in
455 function 'arg' */
456 case PyTrace_C_CALL:
457 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
458 && PyCFunction_Check(arg)) {
459 ptrace_enter_call(self,
460 ((PyCFunctionObject *)arg)->m_ml,
461 arg);
462 }
463 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000464
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000465 /* the call to the built-in function 'arg' is returning into its
466 caller 'frame' */
467 case PyTrace_C_RETURN: /* ...normally */
468 case PyTrace_C_EXCEPTION: /* ...with an exception set */
469 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
470 && PyCFunction_Check(arg)) {
471 ptrace_leave_call(self,
472 ((PyCFunctionObject *)arg)->m_ml);
473 }
474 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000475
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000476 default:
477 break;
478 }
479 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000480}
481
482static int
483pending_exception(ProfilerObject *pObj)
484{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000485 if (pObj->flags & POF_NOMEMORY) {
486 pObj->flags -= POF_NOMEMORY;
487 PyErr_SetString(PyExc_MemoryError,
488 "memory was exhausted while profiling");
489 return -1;
490 }
491 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000492}
493
494/************************************************************/
495
496static PyStructSequence_Field profiler_entry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000497 {"code", "code object or built-in function name"},
498 {"callcount", "how many times this was called"},
499 {"reccallcount", "how many times called recursively"},
500 {"totaltime", "total time in this entry"},
501 {"inlinetime", "inline time in this entry (not in subcalls)"},
502 {"calls", "details of the calls"},
503 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000504};
505
506static PyStructSequence_Field profiler_subentry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000507 {"code", "called code object or built-in function name"},
508 {"callcount", "how many times this is called"},
509 {"reccallcount", "how many times this is called recursively"},
510 {"totaltime", "total time spent in this call"},
511 {"inlinetime", "inline time (not in further subcalls)"},
512 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000513};
514
515static PyStructSequence_Desc profiler_entry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000516 "_lsprof.profiler_entry", /* name */
517 NULL, /* doc */
518 profiler_entry_fields,
519 6
Armin Rigoa871ef22006-02-08 12:53:56 +0000520};
521
522static PyStructSequence_Desc profiler_subentry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000523 "_lsprof.profiler_subentry", /* name */
524 NULL, /* doc */
525 profiler_subentry_fields,
526 5
Armin Rigoa871ef22006-02-08 12:53:56 +0000527};
528
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000529static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000530static PyTypeObject StatsEntryType;
531static PyTypeObject StatsSubEntryType;
532
533
534typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000535 PyObject *list;
536 PyObject *sublist;
537 double factor;
Armin Rigoa871ef22006-02-08 12:53:56 +0000538} statscollector_t;
539
540static int statsForSubEntry(rotating_node_t *node, void *arg)
541{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000542 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
543 statscollector_t *collect = (statscollector_t*) arg;
544 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
545 int err;
546 PyObject *sinfo;
547 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
548 "((Olldd))",
549 entry->userObj,
550 sentry->callcount,
551 sentry->recursivecallcount,
552 collect->factor * sentry->tt,
553 collect->factor * sentry->it);
554 if (sinfo == NULL)
555 return -1;
556 err = PyList_Append(collect->sublist, sinfo);
557 Py_DECREF(sinfo);
558 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000559}
560
561static int statsForEntry(rotating_node_t *node, void *arg)
562{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000563 ProfilerEntry *entry = (ProfilerEntry*) node;
564 statscollector_t *collect = (statscollector_t*) arg;
565 PyObject *info;
566 int err;
567 if (entry->callcount == 0)
568 return 0; /* skip */
Armin Rigoa871ef22006-02-08 12:53:56 +0000569
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000570 if (entry->calls != EMPTY_ROTATING_TREE) {
571 collect->sublist = PyList_New(0);
572 if (collect->sublist == NULL)
573 return -1;
574 if (RotatingTree_Enum(entry->calls,
575 statsForSubEntry, collect) != 0) {
576 Py_DECREF(collect->sublist);
577 return -1;
578 }
579 }
580 else {
581 Py_INCREF(Py_None);
582 collect->sublist = Py_None;
583 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000584
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000585 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
586 "((OllddO))",
587 entry->userObj,
588 entry->callcount,
589 entry->recursivecallcount,
590 collect->factor * entry->tt,
591 collect->factor * entry->it,
592 collect->sublist);
593 Py_DECREF(collect->sublist);
594 if (info == NULL)
595 return -1;
596 err = PyList_Append(collect->list, info);
597 Py_DECREF(info);
598 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000599}
600
601PyDoc_STRVAR(getstats_doc, "\
602getstats() -> list of profiler_entry objects\n\
603\n\
604Return all information collected by the profiler.\n\
605Each profiler_entry is a tuple-like object with the\n\
606following attributes:\n\
607\n\
608 code code object\n\
609 callcount how many times this was called\n\
610 reccallcount how many times called recursively\n\
611 totaltime total time in this entry\n\
612 inlinetime inline time in this entry (not in subcalls)\n\
613 calls details of the calls\n\
614\n\
615The calls attribute is either None or a list of\n\
616profiler_subentry objects:\n\
617\n\
618 code called code object\n\
619 callcount how many times this is called\n\
620 reccallcount how many times this is called recursively\n\
621 totaltime total time spent in this call\n\
622 inlinetime inline time (not in further subcalls)\n\
623");
624
625static PyObject*
626profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
627{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000628 statscollector_t collect;
629 if (pending_exception(pObj))
630 return NULL;
631 if (!pObj->externalTimer)
632 collect.factor = hpTimerUnit();
633 else if (pObj->externalTimerUnit > 0.0)
634 collect.factor = pObj->externalTimerUnit;
635 else
636 collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
637 collect.list = PyList_New(0);
638 if (collect.list == NULL)
639 return NULL;
640 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
641 != 0) {
642 Py_DECREF(collect.list);
643 return NULL;
644 }
645 return collect.list;
Armin Rigoa871ef22006-02-08 12:53:56 +0000646}
647
648static int
649setSubcalls(ProfilerObject *pObj, int nvalue)
650{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000651 if (nvalue == 0)
652 pObj->flags &= ~POF_SUBCALLS;
653 else if (nvalue > 0)
654 pObj->flags |= POF_SUBCALLS;
655 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000656}
657
658static int
659setBuiltins(ProfilerObject *pObj, int nvalue)
660{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000661 if (nvalue == 0)
662 pObj->flags &= ~POF_BUILTINS;
663 else if (nvalue > 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000664 pObj->flags |= POF_BUILTINS;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000665 }
666 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000667}
668
669PyDoc_STRVAR(enable_doc, "\
670enable(subcalls=True, builtins=True)\n\
671\n\
672Start collecting profiling information.\n\
673If 'subcalls' is True, also records for each function\n\
674statistics separated according to its current caller.\n\
675If 'builtins' is True, records the time spent in\n\
676built-in functions separately from their caller.\n\
677");
678
679static PyObject*
680profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
681{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000682 int subcalls = -1;
683 int builtins = -1;
684 static char *kwlist[] = {"subcalls", "builtins", 0};
685 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
686 kwlist, &subcalls, &builtins))
687 return NULL;
688 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
689 return NULL;
690 PyEval_SetProfile(profiler_callback, (PyObject*)self);
691 self->flags |= POF_ENABLED;
692 Py_INCREF(Py_None);
693 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000694}
695
696static void
697flush_unmatched(ProfilerObject *pObj)
698{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000699 while (pObj->currentProfilerContext) {
700 ProfilerContext *pContext = pObj->currentProfilerContext;
701 ProfilerEntry *profEntry= pContext->ctxEntry;
702 if (profEntry)
703 Stop(pObj, pContext, profEntry);
704 else
705 pObj->currentProfilerContext = pContext->previous;
706 if (pContext)
Victor Stinnerb6404912013-07-07 16:21:41 +0200707 PyMem_Free(pContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000708 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000709
710}
711
712PyDoc_STRVAR(disable_doc, "\
713disable()\n\
714\n\
715Stop collecting profiling information.\n\
716");
717
718static PyObject*
719profiler_disable(ProfilerObject *self, PyObject* noarg)
720{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000721 self->flags &= ~POF_ENABLED;
722 PyEval_SetProfile(NULL, NULL);
723 flush_unmatched(self);
724 if (pending_exception(self))
725 return NULL;
726 Py_INCREF(Py_None);
727 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000728}
729
730PyDoc_STRVAR(clear_doc, "\
731clear()\n\
732\n\
733Clear all profiling information collected so far.\n\
734");
735
736static PyObject*
737profiler_clear(ProfilerObject *pObj, PyObject* noarg)
738{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000739 clearEntries(pObj);
740 Py_INCREF(Py_None);
741 return Py_None;
Armin Rigoa871ef22006-02-08 12:53:56 +0000742}
743
744static void
745profiler_dealloc(ProfilerObject *op)
746{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000747 if (op->flags & POF_ENABLED)
748 PyEval_SetProfile(NULL, NULL);
749 flush_unmatched(op);
750 clearEntries(op);
751 Py_XDECREF(op->externalTimer);
752 Py_TYPE(op)->tp_free(op);
Armin Rigoa871ef22006-02-08 12:53:56 +0000753}
754
755static int
756profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
757{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000758 PyObject *o;
759 PyObject *timer = NULL;
760 double timeunit = 0.0;
761 int subcalls = 1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000762 int builtins = 1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000763 static char *kwlist[] = {"timer", "timeunit",
764 "subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000765
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000766 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
767 &timer, &timeunit,
768 &subcalls, &builtins))
769 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000770
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000771 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
772 return -1;
773 o = pObj->externalTimer;
774 pObj->externalTimer = timer;
775 Py_XINCREF(timer);
776 Py_XDECREF(o);
777 pObj->externalTimerUnit = timeunit;
778 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000779}
780
781static PyMethodDef profiler_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000782 {"getstats", (PyCFunction)profiler_getstats,
783 METH_NOARGS, getstats_doc},
784 {"enable", (PyCFunction)profiler_enable,
785 METH_VARARGS | METH_KEYWORDS, enable_doc},
786 {"disable", (PyCFunction)profiler_disable,
787 METH_NOARGS, disable_doc},
788 {"clear", (PyCFunction)profiler_clear,
789 METH_NOARGS, clear_doc},
790 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000791};
792
793PyDoc_STRVAR(profiler_doc, "\
794Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
795\n\
796 Builds a profiler object using the specified timer function.\n\
797 The default timer is a fast built-in one based on real time.\n\
798 For custom timer functions returning integers, time_unit can\n\
799 be a float specifying a scale (i.e. how long each integer unit\n\
800 is, in seconds).\n\
801");
802
Neal Norwitz227b5332006-03-22 09:28:35 +0000803static PyTypeObject PyProfiler_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000804 PyVarObject_HEAD_INIT(NULL, 0)
805 "_lsprof.Profiler", /* tp_name */
806 sizeof(ProfilerObject), /* tp_basicsize */
807 0, /* tp_itemsize */
808 (destructor)profiler_dealloc, /* tp_dealloc */
809 0, /* tp_print */
810 0, /* tp_getattr */
811 0, /* tp_setattr */
812 0, /* tp_reserved */
813 0, /* tp_repr */
814 0, /* tp_as_number */
815 0, /* tp_as_sequence */
816 0, /* tp_as_mapping */
817 0, /* tp_hash */
818 0, /* tp_call */
819 0, /* tp_str */
820 0, /* tp_getattro */
821 0, /* tp_setattro */
822 0, /* tp_as_buffer */
823 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
824 profiler_doc, /* tp_doc */
825 0, /* tp_traverse */
826 0, /* tp_clear */
827 0, /* tp_richcompare */
828 0, /* tp_weaklistoffset */
829 0, /* tp_iter */
830 0, /* tp_iternext */
831 profiler_methods, /* tp_methods */
832 0, /* tp_members */
833 0, /* tp_getset */
834 0, /* tp_base */
835 0, /* tp_dict */
836 0, /* tp_descr_get */
837 0, /* tp_descr_set */
838 0, /* tp_dictoffset */
839 (initproc)profiler_init, /* tp_init */
840 PyType_GenericAlloc, /* tp_alloc */
841 PyType_GenericNew, /* tp_new */
842 PyObject_Del, /* tp_free */
Armin Rigoa871ef22006-02-08 12:53:56 +0000843};
844
845static PyMethodDef moduleMethods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000846 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000847};
848
Martin v. Löwis1a214512008-06-11 05:26:20 +0000849
850static struct PyModuleDef _lsprofmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000851 PyModuleDef_HEAD_INIT,
852 "_lsprof",
853 "Fast profiler",
854 -1,
855 moduleMethods,
856 NULL,
857 NULL,
858 NULL,
859 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000860};
861
Armin Rigoa871ef22006-02-08 12:53:56 +0000862PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000863PyInit__lsprof(void)
Armin Rigoa871ef22006-02-08 12:53:56 +0000864{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000865 PyObject *module, *d;
866 module = PyModule_Create(&_lsprofmodule);
867 if (module == NULL)
868 return NULL;
869 d = PyModule_GetDict(module);
870 if (PyType_Ready(&PyProfiler_Type) < 0)
871 return NULL;
872 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
Armin Rigoa871ef22006-02-08 12:53:56 +0000873
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000874 if (!initialized) {
Victor Stinner1c8f0592013-07-22 22:24:54 +0200875 if (PyStructSequence_InitType2(&StatsEntryType,
876 &profiler_entry_desc) < 0)
877 return NULL;
878 if (PyStructSequence_InitType2(&StatsSubEntryType,
879 &profiler_subentry_desc) < 0)
880 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000881 }
882 Py_INCREF((PyObject*) &StatsEntryType);
883 Py_INCREF((PyObject*) &StatsSubEntryType);
884 PyModule_AddObject(module, "profiler_entry",
885 (PyObject*) &StatsEntryType);
886 PyModule_AddObject(module, "profiler_subentry",
887 (PyObject*) &StatsSubEntryType);
888 empty_tuple = PyTuple_New(0);
889 initialized = 1;
890 return module;
Armin Rigoa871ef22006-02-08 12:53:56 +0000891}