blob: 602747098bb66bc0778c5cac097e1cfc3dd81081 [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
Armin Rigoa871ef22006-02-08 12:53:56 +00005/*** Selection of a high-precision timer ***/
6
7#ifdef MS_WINDOWS
8
9#include <windows.h>
10
Benjamin Petersonaf580df2016-09-06 10:46:49 -070011static long long
Armin Rigoa871ef22006-02-08 12:53:56 +000012hpTimer(void)
13{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000014 LARGE_INTEGER li;
15 QueryPerformanceCounter(&li);
16 return li.QuadPart;
Armin Rigoa871ef22006-02-08 12:53:56 +000017}
18
19static double
20hpTimerUnit(void)
21{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000022 LARGE_INTEGER li;
23 if (QueryPerformanceFrequency(&li))
24 return 1.0 / li.QuadPart;
25 else
26 return 0.000001; /* unlikely */
Armin Rigoa871ef22006-02-08 12:53:56 +000027}
28
29#else /* !MS_WINDOWS */
30
31#ifndef HAVE_GETTIMEOFDAY
32#error "This module requires gettimeofday() on non-Windows platforms!"
33#endif
34
Armin Rigoa871ef22006-02-08 12:53:56 +000035#include <sys/resource.h>
36#include <sys/times.h>
Armin Rigoa871ef22006-02-08 12:53:56 +000037
Benjamin Petersonaf580df2016-09-06 10:46:49 -070038static long long
Armin Rigoa871ef22006-02-08 12:53:56 +000039hpTimer(void)
40{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000041 struct timeval tv;
Benjamin Petersonaf580df2016-09-06 10:46:49 -070042 long long ret;
Armin Rigoa871ef22006-02-08 12:53:56 +000043#ifdef GETTIMEOFDAY_NO_TZ
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000044 gettimeofday(&tv);
Armin Rigoa871ef22006-02-08 12:53:56 +000045#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000046 gettimeofday(&tv, (struct timezone *)NULL);
Armin Rigoa871ef22006-02-08 12:53:56 +000047#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000048 ret = tv.tv_sec;
49 ret = ret * 1000000 + tv.tv_usec;
50 return ret;
Armin Rigoa871ef22006-02-08 12:53:56 +000051}
52
53static double
54hpTimerUnit(void)
55{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000056 return 0.000001;
Armin Rigoa871ef22006-02-08 12:53:56 +000057}
58
59#endif /* MS_WINDOWS */
60
61/************************************************************/
62/* Written by Brett Rosen and Ted Czotter */
63
64struct _ProfilerEntry;
65
66/* represents a function called from another function */
67typedef struct _ProfilerSubEntry {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000068 rotating_node_t header;
Benjamin Petersonaf580df2016-09-06 10:46:49 -070069 long long tt;
70 long long it;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000071 long callcount;
72 long recursivecallcount;
73 long recursionLevel;
Armin Rigoa871ef22006-02-08 12:53:56 +000074} ProfilerSubEntry;
75
76/* represents a function or user defined block */
77typedef struct _ProfilerEntry {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000078 rotating_node_t header;
79 PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
Benjamin Petersonaf580df2016-09-06 10:46:49 -070080 long long tt; /* total time in this entry */
81 long long it; /* inline time in this entry (not in subcalls) */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000082 long callcount; /* how many times this was called */
83 long recursivecallcount; /* how many times called recursively */
84 long recursionLevel;
85 rotating_node_t *calls;
Armin Rigoa871ef22006-02-08 12:53:56 +000086} ProfilerEntry;
87
88typedef struct _ProfilerContext {
Benjamin Petersonaf580df2016-09-06 10:46:49 -070089 long long t0;
90 long long subt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000091 struct _ProfilerContext *previous;
92 ProfilerEntry *ctxEntry;
Armin Rigoa871ef22006-02-08 12:53:56 +000093} ProfilerContext;
94
95typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000096 PyObject_HEAD
97 rotating_node_t *profilerEntries;
98 ProfilerContext *currentProfilerContext;
99 ProfilerContext *freelistProfilerContext;
100 int flags;
101 PyObject *externalTimer;
102 double externalTimerUnit;
Armin Rigoa871ef22006-02-08 12:53:56 +0000103} ProfilerObject;
104
105#define POF_ENABLED 0x001
106#define POF_SUBCALLS 0x002
107#define POF_BUILTINS 0x004
108#define POF_NOMEMORY 0x100
109
Neal Norwitz227b5332006-03-22 09:28:35 +0000110static PyTypeObject PyProfiler_Type;
Armin Rigoa871ef22006-02-08 12:53:56 +0000111
112#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
Christian Heimes90aa7642007-12-19 02:45:37 +0000113#define PyProfiler_CheckExact(op) (Py_TYPE(op) == &PyProfiler_Type)
Armin Rigoa871ef22006-02-08 12:53:56 +0000114
115/*** External Timers ***/
116
117#define DOUBLE_TIMER_PRECISION 4294967296.0
118static PyObject *empty_tuple;
119
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700120static long long CallExternalTimer(ProfilerObject *pObj)
Armin Rigoa871ef22006-02-08 12:53:56 +0000121{
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700122 long long result;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000123 PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL);
124 if (o == NULL) {
125 PyErr_WriteUnraisable(pObj->externalTimer);
126 return 0;
127 }
128 if (pObj->externalTimerUnit > 0.0) {
129 /* interpret the result as an integer that will be scaled
130 in profiler_getstats() */
131 result = PyLong_AsLongLong(o);
132 }
133 else {
134 /* interpret the result as a double measured in seconds.
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700135 As the profiler works with long long internally
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000136 we convert it to a large integer */
137 double val = PyFloat_AsDouble(o);
138 /* error handling delayed to the code below */
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700139 result = (long long) (val * DOUBLE_TIMER_PRECISION);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000140 }
141 Py_DECREF(o);
142 if (PyErr_Occurred()) {
143 PyErr_WriteUnraisable(pObj->externalTimer);
144 return 0;
145 }
146 return result;
Armin Rigoa871ef22006-02-08 12:53:56 +0000147}
148
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000149#define CALL_TIMER(pObj) ((pObj)->externalTimer ? \
150 CallExternalTimer(pObj) : \
151 hpTimer())
Armin Rigoa871ef22006-02-08 12:53:56 +0000152
153/*** ProfilerObject ***/
154
155static PyObject *
156normalizeUserObj(PyObject *obj)
157{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158 PyCFunctionObject *fn;
159 if (!PyCFunction_Check(obj)) {
160 Py_INCREF(obj);
161 return obj;
162 }
163 /* Replace built-in function objects with a descriptive string
164 because of built-in methods -- keeping a reference to
165 __self__ is probably not a good idea. */
166 fn = (PyCFunctionObject *)obj;
Armin Rigoa871ef22006-02-08 12:53:56 +0000167
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000168 if (fn->m_self == NULL) {
169 /* built-in function: look up the module name */
170 PyObject *mod = fn->m_module;
Victor Stinner7edb5df2011-06-20 14:59:53 +0200171 PyObject *modname = NULL;
172 if (mod != NULL) {
173 if (PyUnicode_Check(mod)) {
174 modname = mod;
175 Py_INCREF(modname);
176 }
177 else if (PyModule_Check(mod)) {
178 modname = PyModule_GetNameObject(mod);
179 if (modname == NULL)
180 PyErr_Clear();
Alexander Belopolskye239d232010-12-08 23:31:48 +0000181 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000182 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200183 if (modname != NULL) {
Serhiy Storchakaf4934ea2016-11-16 10:17:58 +0200184 if (!_PyUnicode_EqualToASCIIString(modname, "builtins")) {
Victor Stinner7edb5df2011-06-20 14:59:53 +0200185 PyObject *result;
186 result = PyUnicode_FromFormat("<%U.%s>", modname,
187 fn->m_ml->ml_name);
188 Py_DECREF(modname);
189 return result;
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000190 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200191 Py_DECREF(modname);
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000192 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200193 return PyUnicode_FromFormat("<%s>", fn->m_ml->ml_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000194 }
195 else {
196 /* built-in method: try to return
197 repr(getattr(type(__self__), __name__))
198 */
199 PyObject *self = fn->m_self;
200 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400201 PyObject *modname = fn->m_module;
202
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000203 if (name != NULL) {
204 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
205 Py_XINCREF(mo);
206 Py_DECREF(name);
207 if (mo != NULL) {
208 PyObject *res = PyObject_Repr(mo);
209 Py_DECREF(mo);
210 if (res != NULL)
211 return res;
212 }
213 }
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400214 /* Otherwise, use __module__ */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000215 PyErr_Clear();
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400216 if (modname != NULL && PyUnicode_Check(modname))
217 return PyUnicode_FromFormat("<built-in method %S.%s>",
218 modname, fn->m_ml->ml_name);
219 else
220 return PyUnicode_FromFormat("<built-in method %s>",
221 fn->m_ml->ml_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000222 }
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;
Victor Stinnerb6404912013-07-07 16:21:41 +0200229 self = (ProfilerEntry*) PyMem_Malloc(sizeof(ProfilerEntry));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000230 if (self == NULL) {
231 pObj->flags |= POF_NOMEMORY;
232 return NULL;
233 }
234 userObj = normalizeUserObj(userObj);
235 if (userObj == NULL) {
236 PyErr_Clear();
Victor Stinnerb6404912013-07-07 16:21:41 +0200237 PyMem_Free(self);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000238 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;
Victor Stinnerb6404912013-07-07 16:21:41 +0200270 self = (ProfilerSubEntry*) PyMem_Malloc(sizeof(ProfilerSubEntry));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000271 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;
Victor Stinnerb6404912013-07-07 16:21:41 +0200288 PyMem_Free(subentry);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000289 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);
Victor Stinnerb6404912013-07-07 16:21:41 +0200297 PyMem_Free(entry);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 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) {
Victor Stinnerb6404912013-07-07 16:21:41 +0200307 PyMem_Free(pObj->currentProfilerContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000308 pObj->currentProfilerContext = NULL;
309 }
310 while (pObj->freelistProfilerContext) {
311 ProfilerContext *c = pObj->freelistProfilerContext;
312 pObj->freelistProfilerContext = c->previous;
Victor Stinnerb6404912013-07-07 16:21:41 +0200313 PyMem_Free(c);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000314 }
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{
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700341 long long tt = CALL_TIMER(pObj) - self->t0;
342 long long it = tt - self->subt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000343 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*)
Victor Stinnerb6404912013-07-07 16:21:41 +0200399 PyMem_Malloc(sizeof(ProfilerContext));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000400 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 /* the Python function 'frame' is issuing a call to the built-in
458 function 'arg' */
459 case PyTrace_C_CALL:
460 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
461 && PyCFunction_Check(arg)) {
462 ptrace_enter_call(self,
463 ((PyCFunctionObject *)arg)->m_ml,
464 arg);
465 }
466 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000467
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000468 /* the call to the built-in function 'arg' is returning into its
469 caller 'frame' */
470 case PyTrace_C_RETURN: /* ...normally */
471 case PyTrace_C_EXCEPTION: /* ...with an exception set */
472 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
473 && PyCFunction_Check(arg)) {
474 ptrace_leave_call(self,
475 ((PyCFunctionObject *)arg)->m_ml);
476 }
477 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000478
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000479 default:
480 break;
481 }
482 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000483}
484
485static int
486pending_exception(ProfilerObject *pObj)
487{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000488 if (pObj->flags & POF_NOMEMORY) {
489 pObj->flags -= POF_NOMEMORY;
490 PyErr_SetString(PyExc_MemoryError,
491 "memory was exhausted while profiling");
492 return -1;
493 }
494 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000495}
496
497/************************************************************/
498
499static PyStructSequence_Field profiler_entry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000500 {"code", "code object or built-in function name"},
501 {"callcount", "how many times this was called"},
502 {"reccallcount", "how many times called recursively"},
503 {"totaltime", "total time in this entry"},
504 {"inlinetime", "inline time in this entry (not in subcalls)"},
505 {"calls", "details of the calls"},
506 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000507};
508
509static PyStructSequence_Field profiler_subentry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000510 {"code", "called code object or built-in function name"},
511 {"callcount", "how many times this is called"},
512 {"reccallcount", "how many times this is called recursively"},
513 {"totaltime", "total time spent in this call"},
514 {"inlinetime", "inline time (not in further subcalls)"},
515 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000516};
517
518static PyStructSequence_Desc profiler_entry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000519 "_lsprof.profiler_entry", /* name */
520 NULL, /* doc */
521 profiler_entry_fields,
522 6
Armin Rigoa871ef22006-02-08 12:53:56 +0000523};
524
525static PyStructSequence_Desc profiler_subentry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000526 "_lsprof.profiler_subentry", /* name */
527 NULL, /* doc */
528 profiler_subentry_fields,
529 5
Armin Rigoa871ef22006-02-08 12:53:56 +0000530};
531
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000532static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000533static PyTypeObject StatsEntryType;
534static PyTypeObject StatsSubEntryType;
535
536
537typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000538 PyObject *list;
539 PyObject *sublist;
540 double factor;
Armin Rigoa871ef22006-02-08 12:53:56 +0000541} statscollector_t;
542
543static int statsForSubEntry(rotating_node_t *node, void *arg)
544{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000545 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
546 statscollector_t *collect = (statscollector_t*) arg;
547 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
548 int err;
549 PyObject *sinfo;
550 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
551 "((Olldd))",
552 entry->userObj,
553 sentry->callcount,
554 sentry->recursivecallcount,
555 collect->factor * sentry->tt,
556 collect->factor * sentry->it);
557 if (sinfo == NULL)
558 return -1;
559 err = PyList_Append(collect->sublist, sinfo);
560 Py_DECREF(sinfo);
561 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000562}
563
564static int statsForEntry(rotating_node_t *node, void *arg)
565{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000566 ProfilerEntry *entry = (ProfilerEntry*) node;
567 statscollector_t *collect = (statscollector_t*) arg;
568 PyObject *info;
569 int err;
570 if (entry->callcount == 0)
571 return 0; /* skip */
Armin Rigoa871ef22006-02-08 12:53:56 +0000572
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000573 if (entry->calls != EMPTY_ROTATING_TREE) {
574 collect->sublist = PyList_New(0);
575 if (collect->sublist == NULL)
576 return -1;
577 if (RotatingTree_Enum(entry->calls,
578 statsForSubEntry, collect) != 0) {
579 Py_DECREF(collect->sublist);
580 return -1;
581 }
582 }
583 else {
584 Py_INCREF(Py_None);
585 collect->sublist = Py_None;
586 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000587
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000588 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
589 "((OllddO))",
590 entry->userObj,
591 entry->callcount,
592 entry->recursivecallcount,
593 collect->factor * entry->tt,
594 collect->factor * entry->it,
595 collect->sublist);
596 Py_DECREF(collect->sublist);
597 if (info == NULL)
598 return -1;
599 err = PyList_Append(collect->list, info);
600 Py_DECREF(info);
601 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000602}
603
604PyDoc_STRVAR(getstats_doc, "\
605getstats() -> list of profiler_entry objects\n\
606\n\
607Return all information collected by the profiler.\n\
608Each profiler_entry is a tuple-like object with the\n\
609following attributes:\n\
610\n\
611 code code object\n\
612 callcount how many times this was called\n\
613 reccallcount how many times called recursively\n\
614 totaltime total time in this entry\n\
615 inlinetime inline time in this entry (not in subcalls)\n\
616 calls details of the calls\n\
617\n\
618The calls attribute is either None or a list of\n\
619profiler_subentry objects:\n\
620\n\
621 code called code object\n\
622 callcount how many times this is called\n\
623 reccallcount how many times this is called recursively\n\
624 totaltime total time spent in this call\n\
625 inlinetime inline time (not in further subcalls)\n\
626");
627
628static PyObject*
629profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
630{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000631 statscollector_t collect;
632 if (pending_exception(pObj))
633 return NULL;
634 if (!pObj->externalTimer)
635 collect.factor = hpTimerUnit();
636 else if (pObj->externalTimerUnit > 0.0)
637 collect.factor = pObj->externalTimerUnit;
638 else
639 collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
640 collect.list = PyList_New(0);
641 if (collect.list == NULL)
642 return NULL;
643 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
644 != 0) {
645 Py_DECREF(collect.list);
646 return NULL;
647 }
648 return collect.list;
Armin Rigoa871ef22006-02-08 12:53:56 +0000649}
650
651static int
652setSubcalls(ProfilerObject *pObj, int nvalue)
653{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000654 if (nvalue == 0)
655 pObj->flags &= ~POF_SUBCALLS;
656 else if (nvalue > 0)
657 pObj->flags |= POF_SUBCALLS;
658 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000659}
660
661static int
662setBuiltins(ProfilerObject *pObj, int nvalue)
663{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000664 if (nvalue == 0)
665 pObj->flags &= ~POF_BUILTINS;
666 else if (nvalue > 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000667 pObj->flags |= POF_BUILTINS;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000668 }
669 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000670}
671
672PyDoc_STRVAR(enable_doc, "\
673enable(subcalls=True, builtins=True)\n\
674\n\
675Start collecting profiling information.\n\
676If 'subcalls' is True, also records for each function\n\
677statistics separated according to its current caller.\n\
678If 'builtins' is True, records the time spent in\n\
679built-in functions separately from their caller.\n\
680");
681
682static PyObject*
683profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
684{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000685 int subcalls = -1;
686 int builtins = -1;
687 static char *kwlist[] = {"subcalls", "builtins", 0};
688 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
689 kwlist, &subcalls, &builtins))
690 return NULL;
691 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
692 return NULL;
693 PyEval_SetProfile(profiler_callback, (PyObject*)self);
694 self->flags |= POF_ENABLED;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200695 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000696}
697
698static void
699flush_unmatched(ProfilerObject *pObj)
700{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000701 while (pObj->currentProfilerContext) {
702 ProfilerContext *pContext = pObj->currentProfilerContext;
703 ProfilerEntry *profEntry= pContext->ctxEntry;
704 if (profEntry)
705 Stop(pObj, pContext, profEntry);
706 else
707 pObj->currentProfilerContext = pContext->previous;
708 if (pContext)
Victor Stinnerb6404912013-07-07 16:21:41 +0200709 PyMem_Free(pContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000710 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000711
712}
713
714PyDoc_STRVAR(disable_doc, "\
715disable()\n\
716\n\
717Stop collecting profiling information.\n\
718");
719
720static PyObject*
721profiler_disable(ProfilerObject *self, PyObject* noarg)
722{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000723 self->flags &= ~POF_ENABLED;
724 PyEval_SetProfile(NULL, NULL);
725 flush_unmatched(self);
726 if (pending_exception(self))
727 return NULL;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200728 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000729}
730
731PyDoc_STRVAR(clear_doc, "\
732clear()\n\
733\n\
734Clear all profiling information collected so far.\n\
735");
736
737static PyObject*
738profiler_clear(ProfilerObject *pObj, PyObject* noarg)
739{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000740 clearEntries(pObj);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200741 Py_RETURN_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 *timer = NULL;
759 double timeunit = 0.0;
760 int subcalls = 1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000761 int builtins = 1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000762 static char *kwlist[] = {"timer", "timeunit",
763 "subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000764
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000765 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
766 &timer, &timeunit,
767 &subcalls, &builtins))
768 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000769
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000770 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
771 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000772 pObj->externalTimerUnit = timeunit;
Serhiy Storchaka576f1322016-01-05 21:27:54 +0200773 Py_XINCREF(timer);
Serhiy Storchakaec397562016-04-06 09:50:03 +0300774 Py_XSETREF(pObj->externalTimer, timer);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000775 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000776}
777
778static PyMethodDef profiler_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000779 {"getstats", (PyCFunction)profiler_getstats,
780 METH_NOARGS, getstats_doc},
781 {"enable", (PyCFunction)profiler_enable,
782 METH_VARARGS | METH_KEYWORDS, enable_doc},
783 {"disable", (PyCFunction)profiler_disable,
784 METH_NOARGS, disable_doc},
785 {"clear", (PyCFunction)profiler_clear,
786 METH_NOARGS, clear_doc},
787 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000788};
789
790PyDoc_STRVAR(profiler_doc, "\
791Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
792\n\
793 Builds a profiler object using the specified timer function.\n\
794 The default timer is a fast built-in one based on real time.\n\
795 For custom timer functions returning integers, time_unit can\n\
796 be a float specifying a scale (i.e. how long each integer unit\n\
797 is, in seconds).\n\
798");
799
Neal Norwitz227b5332006-03-22 09:28:35 +0000800static PyTypeObject PyProfiler_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000801 PyVarObject_HEAD_INIT(NULL, 0)
802 "_lsprof.Profiler", /* tp_name */
803 sizeof(ProfilerObject), /* tp_basicsize */
804 0, /* tp_itemsize */
805 (destructor)profiler_dealloc, /* tp_dealloc */
806 0, /* tp_print */
807 0, /* tp_getattr */
808 0, /* tp_setattr */
809 0, /* tp_reserved */
810 0, /* tp_repr */
811 0, /* tp_as_number */
812 0, /* tp_as_sequence */
813 0, /* tp_as_mapping */
814 0, /* tp_hash */
815 0, /* tp_call */
816 0, /* tp_str */
817 0, /* tp_getattro */
818 0, /* tp_setattro */
819 0, /* tp_as_buffer */
820 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
821 profiler_doc, /* tp_doc */
822 0, /* tp_traverse */
823 0, /* tp_clear */
824 0, /* tp_richcompare */
825 0, /* tp_weaklistoffset */
826 0, /* tp_iter */
827 0, /* tp_iternext */
828 profiler_methods, /* tp_methods */
829 0, /* tp_members */
830 0, /* tp_getset */
831 0, /* tp_base */
832 0, /* tp_dict */
833 0, /* tp_descr_get */
834 0, /* tp_descr_set */
835 0, /* tp_dictoffset */
836 (initproc)profiler_init, /* tp_init */
837 PyType_GenericAlloc, /* tp_alloc */
838 PyType_GenericNew, /* tp_new */
839 PyObject_Del, /* tp_free */
Armin Rigoa871ef22006-02-08 12:53:56 +0000840};
841
842static PyMethodDef moduleMethods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000843 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000844};
845
Martin v. Löwis1a214512008-06-11 05:26:20 +0000846
847static struct PyModuleDef _lsprofmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000848 PyModuleDef_HEAD_INIT,
849 "_lsprof",
850 "Fast profiler",
851 -1,
852 moduleMethods,
853 NULL,
854 NULL,
855 NULL,
856 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000857};
858
Armin Rigoa871ef22006-02-08 12:53:56 +0000859PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000860PyInit__lsprof(void)
Armin Rigoa871ef22006-02-08 12:53:56 +0000861{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000862 PyObject *module, *d;
863 module = PyModule_Create(&_lsprofmodule);
864 if (module == NULL)
865 return NULL;
866 d = PyModule_GetDict(module);
867 if (PyType_Ready(&PyProfiler_Type) < 0)
868 return NULL;
869 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
Armin Rigoa871ef22006-02-08 12:53:56 +0000870
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000871 if (!initialized) {
Victor Stinner1c8f0592013-07-22 22:24:54 +0200872 if (PyStructSequence_InitType2(&StatsEntryType,
873 &profiler_entry_desc) < 0)
874 return NULL;
875 if (PyStructSequence_InitType2(&StatsSubEntryType,
876 &profiler_subentry_desc) < 0)
877 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000878 }
879 Py_INCREF((PyObject*) &StatsEntryType);
880 Py_INCREF((PyObject*) &StatsSubEntryType);
881 PyModule_AddObject(module, "profiler_entry",
882 (PyObject*) &StatsEntryType);
883 PyModule_AddObject(module, "profiler_subentry",
884 (PyObject*) &StatsSubEntryType);
885 empty_tuple = PyTuple_New(0);
886 initialized = 1;
887 return module;
Armin Rigoa871ef22006-02-08 12:53:56 +0000888}