blob: c4e0f52389d952220cbb175cd87b7d58da0c009f [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/************************************************************/
6/* Written by Brett Rosen and Ted Czotter */
7
8struct _ProfilerEntry;
9
10/* represents a function called from another function */
11typedef struct _ProfilerSubEntry {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000012 rotating_node_t header;
Inada Naoki536a35b2019-04-11 19:11:46 +090013 _PyTime_t tt;
14 _PyTime_t it;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000015 long callcount;
16 long recursivecallcount;
17 long recursionLevel;
Armin Rigoa871ef22006-02-08 12:53:56 +000018} ProfilerSubEntry;
19
20/* represents a function or user defined block */
21typedef struct _ProfilerEntry {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000022 rotating_node_t header;
23 PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
Inada Naoki536a35b2019-04-11 19:11:46 +090024 _PyTime_t tt; /* total time in this entry */
25 _PyTime_t it; /* inline time in this entry (not in subcalls) */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000026 long callcount; /* how many times this was called */
27 long recursivecallcount; /* how many times called recursively */
28 long recursionLevel;
29 rotating_node_t *calls;
Armin Rigoa871ef22006-02-08 12:53:56 +000030} ProfilerEntry;
31
32typedef struct _ProfilerContext {
Inada Naoki536a35b2019-04-11 19:11:46 +090033 _PyTime_t t0;
34 _PyTime_t subt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000035 struct _ProfilerContext *previous;
36 ProfilerEntry *ctxEntry;
Armin Rigoa871ef22006-02-08 12:53:56 +000037} ProfilerContext;
38
39typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000040 PyObject_HEAD
41 rotating_node_t *profilerEntries;
42 ProfilerContext *currentProfilerContext;
43 ProfilerContext *freelistProfilerContext;
44 int flags;
45 PyObject *externalTimer;
46 double externalTimerUnit;
Armin Rigoa871ef22006-02-08 12:53:56 +000047} ProfilerObject;
48
49#define POF_ENABLED 0x001
50#define POF_SUBCALLS 0x002
51#define POF_BUILTINS 0x004
52#define POF_NOMEMORY 0x100
53
Neal Norwitz227b5332006-03-22 09:28:35 +000054static PyTypeObject PyProfiler_Type;
Armin Rigoa871ef22006-02-08 12:53:56 +000055
56#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
Christian Heimes90aa7642007-12-19 02:45:37 +000057#define PyProfiler_CheckExact(op) (Py_TYPE(op) == &PyProfiler_Type)
Armin Rigoa871ef22006-02-08 12:53:56 +000058
59/*** External Timers ***/
60
Inada Naoki536a35b2019-04-11 19:11:46 +090061static _PyTime_t CallExternalTimer(ProfilerObject *pObj)
Armin Rigoa871ef22006-02-08 12:53:56 +000062{
Inada Naoki536a35b2019-04-11 19:11:46 +090063 PyObject *o = _PyObject_CallNoArg(pObj->externalTimer);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000064 if (o == NULL) {
65 PyErr_WriteUnraisable(pObj->externalTimer);
66 return 0;
67 }
Inada Naoki536a35b2019-04-11 19:11:46 +090068
69 _PyTime_t result;
70 int err;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000071 if (pObj->externalTimerUnit > 0.0) {
72 /* interpret the result as an integer that will be scaled
73 in profiler_getstats() */
Inada Naoki536a35b2019-04-11 19:11:46 +090074 err = _PyTime_FromNanosecondsObject(&result, o);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000075 }
76 else {
77 /* interpret the result as a double measured in seconds.
Inada Naoki536a35b2019-04-11 19:11:46 +090078 As the profiler works with _PyTime_t internally
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000079 we convert it to a large integer */
Inada Naoki536a35b2019-04-11 19:11:46 +090080 err = _PyTime_FromSecondsObject(&result, o, _PyTime_ROUND_FLOOR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000081 }
82 Py_DECREF(o);
Inada Naoki536a35b2019-04-11 19:11:46 +090083 if (err < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000084 PyErr_WriteUnraisable(pObj->externalTimer);
85 return 0;
86 }
87 return result;
Armin Rigoa871ef22006-02-08 12:53:56 +000088}
89
Inada Naoki536a35b2019-04-11 19:11:46 +090090static inline _PyTime_t
91call_timer(ProfilerObject *pObj)
92{
93 if (pObj->externalTimer != NULL) {
94 return CallExternalTimer(pObj);
95 }
96 else {
97 return _PyTime_GetPerfCounter();
98 }
99}
100
Armin Rigoa871ef22006-02-08 12:53:56 +0000101
102/*** ProfilerObject ***/
103
104static PyObject *
105normalizeUserObj(PyObject *obj)
106{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000107 PyCFunctionObject *fn;
108 if (!PyCFunction_Check(obj)) {
109 Py_INCREF(obj);
110 return obj;
111 }
112 /* Replace built-in function objects with a descriptive string
113 because of built-in methods -- keeping a reference to
114 __self__ is probably not a good idea. */
115 fn = (PyCFunctionObject *)obj;
Armin Rigoa871ef22006-02-08 12:53:56 +0000116
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000117 if (fn->m_self == NULL) {
118 /* built-in function: look up the module name */
119 PyObject *mod = fn->m_module;
Victor Stinner7edb5df2011-06-20 14:59:53 +0200120 PyObject *modname = NULL;
121 if (mod != NULL) {
122 if (PyUnicode_Check(mod)) {
123 modname = mod;
124 Py_INCREF(modname);
125 }
126 else if (PyModule_Check(mod)) {
127 modname = PyModule_GetNameObject(mod);
128 if (modname == NULL)
129 PyErr_Clear();
Alexander Belopolskye239d232010-12-08 23:31:48 +0000130 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000131 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200132 if (modname != NULL) {
Serhiy Storchakaf4934ea2016-11-16 10:17:58 +0200133 if (!_PyUnicode_EqualToASCIIString(modname, "builtins")) {
Victor Stinner7edb5df2011-06-20 14:59:53 +0200134 PyObject *result;
135 result = PyUnicode_FromFormat("<%U.%s>", modname,
136 fn->m_ml->ml_name);
137 Py_DECREF(modname);
138 return result;
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000139 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200140 Py_DECREF(modname);
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000141 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200142 return PyUnicode_FromFormat("<%s>", fn->m_ml->ml_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000143 }
144 else {
145 /* built-in method: try to return
146 repr(getattr(type(__self__), __name__))
147 */
148 PyObject *self = fn->m_self;
149 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400150 PyObject *modname = fn->m_module;
151
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000152 if (name != NULL) {
153 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
154 Py_XINCREF(mo);
155 Py_DECREF(name);
156 if (mo != NULL) {
157 PyObject *res = PyObject_Repr(mo);
158 Py_DECREF(mo);
159 if (res != NULL)
160 return res;
161 }
162 }
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400163 /* Otherwise, use __module__ */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000164 PyErr_Clear();
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400165 if (modname != NULL && PyUnicode_Check(modname))
166 return PyUnicode_FromFormat("<built-in method %S.%s>",
167 modname, fn->m_ml->ml_name);
168 else
169 return PyUnicode_FromFormat("<built-in method %s>",
170 fn->m_ml->ml_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000171 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000172}
173
174static ProfilerEntry*
175newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
176{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000177 ProfilerEntry *self;
Victor Stinnerb6404912013-07-07 16:21:41 +0200178 self = (ProfilerEntry*) PyMem_Malloc(sizeof(ProfilerEntry));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000179 if (self == NULL) {
180 pObj->flags |= POF_NOMEMORY;
181 return NULL;
182 }
183 userObj = normalizeUserObj(userObj);
184 if (userObj == NULL) {
185 PyErr_Clear();
Victor Stinnerb6404912013-07-07 16:21:41 +0200186 PyMem_Free(self);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000187 pObj->flags |= POF_NOMEMORY;
188 return NULL;
189 }
190 self->header.key = key;
191 self->userObj = userObj;
192 self->tt = 0;
193 self->it = 0;
194 self->callcount = 0;
195 self->recursivecallcount = 0;
196 self->recursionLevel = 0;
197 self->calls = EMPTY_ROTATING_TREE;
198 RotatingTree_Add(&pObj->profilerEntries, &self->header);
199 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000200}
201
202static ProfilerEntry*
203getEntry(ProfilerObject *pObj, void *key)
204{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000205 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
Armin Rigoa871ef22006-02-08 12:53:56 +0000206}
207
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208static ProfilerSubEntry *
Armin Rigoa871ef22006-02-08 12:53:56 +0000209getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
210{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000211 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
212 (void *)entry);
Armin Rigoa871ef22006-02-08 12:53:56 +0000213}
214
215static ProfilerSubEntry *
216newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
217{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000218 ProfilerSubEntry *self;
Victor Stinnerb6404912013-07-07 16:21:41 +0200219 self = (ProfilerSubEntry*) PyMem_Malloc(sizeof(ProfilerSubEntry));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000220 if (self == NULL) {
221 pObj->flags |= POF_NOMEMORY;
222 return NULL;
223 }
224 self->header.key = (void *)entry;
225 self->tt = 0;
226 self->it = 0;
227 self->callcount = 0;
228 self->recursivecallcount = 0;
229 self->recursionLevel = 0;
230 RotatingTree_Add(&caller->calls, &self->header);
231 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000232}
233
234static int freeSubEntry(rotating_node_t *header, void *arg)
235{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000236 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
Victor Stinnerb6404912013-07-07 16:21:41 +0200237 PyMem_Free(subentry);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000238 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000239}
240
241static int freeEntry(rotating_node_t *header, void *arg)
242{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000243 ProfilerEntry *entry = (ProfilerEntry*) header;
244 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
245 Py_DECREF(entry->userObj);
Victor Stinnerb6404912013-07-07 16:21:41 +0200246 PyMem_Free(entry);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000247 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000248}
249
250static void clearEntries(ProfilerObject *pObj)
251{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000252 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
253 pObj->profilerEntries = EMPTY_ROTATING_TREE;
254 /* release the memory hold by the ProfilerContexts */
255 if (pObj->currentProfilerContext) {
Victor Stinnerb6404912013-07-07 16:21:41 +0200256 PyMem_Free(pObj->currentProfilerContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000257 pObj->currentProfilerContext = NULL;
258 }
259 while (pObj->freelistProfilerContext) {
260 ProfilerContext *c = pObj->freelistProfilerContext;
261 pObj->freelistProfilerContext = c->previous;
Victor Stinnerb6404912013-07-07 16:21:41 +0200262 PyMem_Free(c);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 }
264 pObj->freelistProfilerContext = NULL;
Armin Rigoa871ef22006-02-08 12:53:56 +0000265}
266
267static void
268initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
269{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000270 self->ctxEntry = entry;
271 self->subt = 0;
272 self->previous = pObj->currentProfilerContext;
273 pObj->currentProfilerContext = self;
274 ++entry->recursionLevel;
275 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
276 /* find or create an entry for me in my caller's entry */
277 ProfilerEntry *caller = self->previous->ctxEntry;
278 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
279 if (subentry == NULL)
280 subentry = newSubEntry(pObj, caller, entry);
281 if (subentry)
282 ++subentry->recursionLevel;
283 }
Inada Naoki536a35b2019-04-11 19:11:46 +0900284 self->t0 = call_timer(pObj);
Armin Rigoa871ef22006-02-08 12:53:56 +0000285}
286
287static void
288Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
289{
Inada Naoki536a35b2019-04-11 19:11:46 +0900290 _PyTime_t tt = call_timer(pObj) - self->t0;
291 _PyTime_t it = tt - self->subt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000292 if (self->previous)
293 self->previous->subt += tt;
294 pObj->currentProfilerContext = self->previous;
295 if (--entry->recursionLevel == 0)
296 entry->tt += tt;
297 else
298 ++entry->recursivecallcount;
299 entry->it += it;
300 entry->callcount++;
301 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
302 /* find or create an entry for me in my caller's entry */
303 ProfilerEntry *caller = self->previous->ctxEntry;
304 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
305 if (subentry) {
306 if (--subentry->recursionLevel == 0)
307 subentry->tt += tt;
308 else
309 ++subentry->recursivecallcount;
310 subentry->it += it;
311 ++subentry->callcount;
312 }
313 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000314}
315
316static void
317ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
318{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000319 /* entering a call to the function identified by 'key'
320 (which can be a PyCodeObject or a PyMethodDef pointer) */
321 ProfilerObject *pObj = (ProfilerObject*)self;
322 ProfilerEntry *profEntry;
323 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000324
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 /* In the case of entering a generator expression frame via a
326 * throw (gen_send_ex(.., 1)), we may already have an
327 * Exception set here. We must not mess around with this
328 * exception, and some of the code under here assumes that
329 * PyErr_* is its own to mess around with, so we have to
330 * save and restore any current exception. */
331 PyObject *last_type, *last_value, *last_tb;
332 PyErr_Fetch(&last_type, &last_value, &last_tb);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000333
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000334 profEntry = getEntry(pObj, key);
335 if (profEntry == NULL) {
336 profEntry = newProfilerEntry(pObj, key, userObj);
337 if (profEntry == NULL)
338 goto restorePyerr;
339 }
340 /* grab a ProfilerContext out of the free list */
341 pContext = pObj->freelistProfilerContext;
342 if (pContext) {
343 pObj->freelistProfilerContext = pContext->previous;
344 }
345 else {
346 /* free list exhausted, allocate a new one */
347 pContext = (ProfilerContext*)
Victor Stinnerb6404912013-07-07 16:21:41 +0200348 PyMem_Malloc(sizeof(ProfilerContext));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000349 if (pContext == NULL) {
350 pObj->flags |= POF_NOMEMORY;
351 goto restorePyerr;
352 }
353 }
354 initContext(pObj, pContext, profEntry);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000355
356restorePyerr:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000357 PyErr_Restore(last_type, last_value, last_tb);
Armin Rigoa871ef22006-02-08 12:53:56 +0000358}
359
360static void
361ptrace_leave_call(PyObject *self, void *key)
362{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000363 /* leaving a call to the function identified by 'key' */
364 ProfilerObject *pObj = (ProfilerObject*)self;
365 ProfilerEntry *profEntry;
366 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000367
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000368 pContext = pObj->currentProfilerContext;
369 if (pContext == NULL)
370 return;
371 profEntry = getEntry(pObj, key);
372 if (profEntry) {
373 Stop(pObj, pContext, profEntry);
374 }
375 else {
376 pObj->currentProfilerContext = pContext->previous;
377 }
378 /* put pContext into the free list */
379 pContext->previous = pObj->freelistProfilerContext;
380 pObj->freelistProfilerContext = pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000381}
382
383static int
384profiler_callback(PyObject *self, PyFrameObject *frame, int what,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000385 PyObject *arg)
Armin Rigoa871ef22006-02-08 12:53:56 +0000386{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000387 switch (what) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000388
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000389 /* the 'frame' of a called function is about to start its execution */
390 case PyTrace_CALL:
391 ptrace_enter_call(self, (void *)frame->f_code,
392 (PyObject *)frame->f_code);
393 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000394
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000395 /* the 'frame' of a called function is about to finish
396 (either normally or with an exception) */
397 case PyTrace_RETURN:
398 ptrace_leave_call(self, (void *)frame->f_code);
399 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000400
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000401 /* case PyTrace_EXCEPTION:
402 If the exception results in the function exiting, a
403 PyTrace_RETURN event will be generated, so we don't need to
404 handle it. */
Armin Rigoa871ef22006-02-08 12:53:56 +0000405
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000406 /* the Python function 'frame' is issuing a call to the built-in
407 function 'arg' */
408 case PyTrace_C_CALL:
409 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
410 && PyCFunction_Check(arg)) {
411 ptrace_enter_call(self,
412 ((PyCFunctionObject *)arg)->m_ml,
413 arg);
414 }
415 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000416
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000417 /* the call to the built-in function 'arg' is returning into its
418 caller 'frame' */
419 case PyTrace_C_RETURN: /* ...normally */
420 case PyTrace_C_EXCEPTION: /* ...with an exception set */
421 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
422 && PyCFunction_Check(arg)) {
423 ptrace_leave_call(self,
424 ((PyCFunctionObject *)arg)->m_ml);
425 }
426 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000427
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000428 default:
429 break;
430 }
431 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000432}
433
434static int
435pending_exception(ProfilerObject *pObj)
436{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000437 if (pObj->flags & POF_NOMEMORY) {
438 pObj->flags -= POF_NOMEMORY;
439 PyErr_SetString(PyExc_MemoryError,
440 "memory was exhausted while profiling");
441 return -1;
442 }
443 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000444}
445
446/************************************************************/
447
448static PyStructSequence_Field profiler_entry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000449 {"code", "code object or built-in function name"},
450 {"callcount", "how many times this was called"},
451 {"reccallcount", "how many times called recursively"},
452 {"totaltime", "total time in this entry"},
453 {"inlinetime", "inline time in this entry (not in subcalls)"},
454 {"calls", "details of the calls"},
455 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000456};
457
458static PyStructSequence_Field profiler_subentry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000459 {"code", "called code object or built-in function name"},
460 {"callcount", "how many times this is called"},
461 {"reccallcount", "how many times this is called recursively"},
462 {"totaltime", "total time spent in this call"},
463 {"inlinetime", "inline time (not in further subcalls)"},
464 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000465};
466
467static PyStructSequence_Desc profiler_entry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000468 "_lsprof.profiler_entry", /* name */
469 NULL, /* doc */
470 profiler_entry_fields,
471 6
Armin Rigoa871ef22006-02-08 12:53:56 +0000472};
473
474static PyStructSequence_Desc profiler_subentry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000475 "_lsprof.profiler_subentry", /* name */
476 NULL, /* doc */
477 profiler_subentry_fields,
478 5
Armin Rigoa871ef22006-02-08 12:53:56 +0000479};
480
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000481static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000482static PyTypeObject StatsEntryType;
483static PyTypeObject StatsSubEntryType;
484
485
486typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000487 PyObject *list;
488 PyObject *sublist;
489 double factor;
Armin Rigoa871ef22006-02-08 12:53:56 +0000490} statscollector_t;
491
492static int statsForSubEntry(rotating_node_t *node, void *arg)
493{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000494 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
495 statscollector_t *collect = (statscollector_t*) arg;
496 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
497 int err;
498 PyObject *sinfo;
499 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
500 "((Olldd))",
501 entry->userObj,
502 sentry->callcount,
503 sentry->recursivecallcount,
504 collect->factor * sentry->tt,
505 collect->factor * sentry->it);
506 if (sinfo == NULL)
507 return -1;
508 err = PyList_Append(collect->sublist, sinfo);
509 Py_DECREF(sinfo);
510 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000511}
512
513static int statsForEntry(rotating_node_t *node, void *arg)
514{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000515 ProfilerEntry *entry = (ProfilerEntry*) node;
516 statscollector_t *collect = (statscollector_t*) arg;
517 PyObject *info;
518 int err;
519 if (entry->callcount == 0)
520 return 0; /* skip */
Armin Rigoa871ef22006-02-08 12:53:56 +0000521
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000522 if (entry->calls != EMPTY_ROTATING_TREE) {
523 collect->sublist = PyList_New(0);
524 if (collect->sublist == NULL)
525 return -1;
526 if (RotatingTree_Enum(entry->calls,
527 statsForSubEntry, collect) != 0) {
528 Py_DECREF(collect->sublist);
529 return -1;
530 }
531 }
532 else {
533 Py_INCREF(Py_None);
534 collect->sublist = Py_None;
535 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000536
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000537 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
538 "((OllddO))",
539 entry->userObj,
540 entry->callcount,
541 entry->recursivecallcount,
542 collect->factor * entry->tt,
543 collect->factor * entry->it,
544 collect->sublist);
545 Py_DECREF(collect->sublist);
546 if (info == NULL)
547 return -1;
548 err = PyList_Append(collect->list, info);
549 Py_DECREF(info);
550 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000551}
552
553PyDoc_STRVAR(getstats_doc, "\
554getstats() -> list of profiler_entry objects\n\
555\n\
556Return all information collected by the profiler.\n\
557Each profiler_entry is a tuple-like object with the\n\
558following attributes:\n\
559\n\
560 code code object\n\
561 callcount how many times this was called\n\
562 reccallcount how many times called recursively\n\
563 totaltime total time in this entry\n\
564 inlinetime inline time in this entry (not in subcalls)\n\
565 calls details of the calls\n\
566\n\
567The calls attribute is either None or a list of\n\
568profiler_subentry objects:\n\
569\n\
570 code called code object\n\
571 callcount how many times this is called\n\
572 reccallcount how many times this is called recursively\n\
573 totaltime total time spent in this call\n\
574 inlinetime inline time (not in further subcalls)\n\
575");
576
577static PyObject*
578profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
579{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000580 statscollector_t collect;
581 if (pending_exception(pObj))
582 return NULL;
Inada Naoki536a35b2019-04-11 19:11:46 +0900583 if (!pObj->externalTimer || pObj->externalTimerUnit == 0.0) {
584 _PyTime_t onesec = _PyTime_FromSeconds(1);
585 collect.factor = (double)1 / onesec;
586 }
587 else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000588 collect.factor = pObj->externalTimerUnit;
Inada Naoki536a35b2019-04-11 19:11:46 +0900589 }
590
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000591 collect.list = PyList_New(0);
592 if (collect.list == NULL)
593 return NULL;
594 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
595 != 0) {
596 Py_DECREF(collect.list);
597 return NULL;
598 }
599 return collect.list;
Armin Rigoa871ef22006-02-08 12:53:56 +0000600}
601
602static int
603setSubcalls(ProfilerObject *pObj, int nvalue)
604{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000605 if (nvalue == 0)
606 pObj->flags &= ~POF_SUBCALLS;
607 else if (nvalue > 0)
608 pObj->flags |= POF_SUBCALLS;
609 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000610}
611
612static int
613setBuiltins(ProfilerObject *pObj, int nvalue)
614{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000615 if (nvalue == 0)
616 pObj->flags &= ~POF_BUILTINS;
617 else if (nvalue > 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000618 pObj->flags |= POF_BUILTINS;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000619 }
620 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000621}
622
623PyDoc_STRVAR(enable_doc, "\
624enable(subcalls=True, builtins=True)\n\
625\n\
626Start collecting profiling information.\n\
627If 'subcalls' is True, also records for each function\n\
628statistics separated according to its current caller.\n\
629If 'builtins' is True, records the time spent in\n\
630built-in functions separately from their caller.\n\
631");
632
633static PyObject*
634profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
635{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000636 int subcalls = -1;
637 int builtins = -1;
638 static char *kwlist[] = {"subcalls", "builtins", 0};
639 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
640 kwlist, &subcalls, &builtins))
641 return NULL;
642 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
643 return NULL;
644 PyEval_SetProfile(profiler_callback, (PyObject*)self);
645 self->flags |= POF_ENABLED;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200646 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000647}
648
649static void
650flush_unmatched(ProfilerObject *pObj)
651{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000652 while (pObj->currentProfilerContext) {
653 ProfilerContext *pContext = pObj->currentProfilerContext;
654 ProfilerEntry *profEntry= pContext->ctxEntry;
655 if (profEntry)
656 Stop(pObj, pContext, profEntry);
657 else
658 pObj->currentProfilerContext = pContext->previous;
659 if (pContext)
Victor Stinnerb6404912013-07-07 16:21:41 +0200660 PyMem_Free(pContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000661 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000662
663}
664
665PyDoc_STRVAR(disable_doc, "\
666disable()\n\
667\n\
668Stop collecting profiling information.\n\
669");
670
671static PyObject*
672profiler_disable(ProfilerObject *self, PyObject* noarg)
673{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000674 self->flags &= ~POF_ENABLED;
675 PyEval_SetProfile(NULL, NULL);
676 flush_unmatched(self);
677 if (pending_exception(self))
678 return NULL;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200679 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000680}
681
682PyDoc_STRVAR(clear_doc, "\
683clear()\n\
684\n\
685Clear all profiling information collected so far.\n\
686");
687
688static PyObject*
689profiler_clear(ProfilerObject *pObj, PyObject* noarg)
690{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000691 clearEntries(pObj);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200692 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000693}
694
695static void
696profiler_dealloc(ProfilerObject *op)
697{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000698 if (op->flags & POF_ENABLED)
699 PyEval_SetProfile(NULL, NULL);
700 flush_unmatched(op);
701 clearEntries(op);
702 Py_XDECREF(op->externalTimer);
703 Py_TYPE(op)->tp_free(op);
Armin Rigoa871ef22006-02-08 12:53:56 +0000704}
705
706static int
707profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
708{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000709 PyObject *timer = NULL;
710 double timeunit = 0.0;
711 int subcalls = 1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000712 int builtins = 1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000713 static char *kwlist[] = {"timer", "timeunit",
714 "subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000715
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000716 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
717 &timer, &timeunit,
718 &subcalls, &builtins))
719 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000720
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000721 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
722 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000723 pObj->externalTimerUnit = timeunit;
Serhiy Storchaka576f1322016-01-05 21:27:54 +0200724 Py_XINCREF(timer);
Serhiy Storchakaec397562016-04-06 09:50:03 +0300725 Py_XSETREF(pObj->externalTimer, timer);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000726 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000727}
728
729static PyMethodDef profiler_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000730 {"getstats", (PyCFunction)profiler_getstats,
731 METH_NOARGS, getstats_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +0200732 {"enable", (PyCFunction)(void(*)(void))profiler_enable,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000733 METH_VARARGS | METH_KEYWORDS, enable_doc},
734 {"disable", (PyCFunction)profiler_disable,
735 METH_NOARGS, disable_doc},
736 {"clear", (PyCFunction)profiler_clear,
737 METH_NOARGS, clear_doc},
738 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000739};
740
741PyDoc_STRVAR(profiler_doc, "\
INADA Naoki2ebd3812018-08-03 18:09:57 +0900742Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\
Armin Rigoa871ef22006-02-08 12:53:56 +0000743\n\
744 Builds a profiler object using the specified timer function.\n\
745 The default timer is a fast built-in one based on real time.\n\
INADA Naoki2ebd3812018-08-03 18:09:57 +0900746 For custom timer functions returning integers, timeunit can\n\
Armin Rigoa871ef22006-02-08 12:53:56 +0000747 be a float specifying a scale (i.e. how long each integer unit\n\
748 is, in seconds).\n\
749");
750
Neal Norwitz227b5332006-03-22 09:28:35 +0000751static PyTypeObject PyProfiler_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000752 PyVarObject_HEAD_INIT(NULL, 0)
753 "_lsprof.Profiler", /* tp_name */
754 sizeof(ProfilerObject), /* tp_basicsize */
755 0, /* tp_itemsize */
756 (destructor)profiler_dealloc, /* tp_dealloc */
757 0, /* tp_print */
758 0, /* tp_getattr */
759 0, /* tp_setattr */
760 0, /* tp_reserved */
761 0, /* tp_repr */
762 0, /* tp_as_number */
763 0, /* tp_as_sequence */
764 0, /* tp_as_mapping */
765 0, /* tp_hash */
766 0, /* tp_call */
767 0, /* tp_str */
768 0, /* tp_getattro */
769 0, /* tp_setattro */
770 0, /* tp_as_buffer */
771 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
772 profiler_doc, /* tp_doc */
773 0, /* tp_traverse */
774 0, /* tp_clear */
775 0, /* tp_richcompare */
776 0, /* tp_weaklistoffset */
777 0, /* tp_iter */
778 0, /* tp_iternext */
779 profiler_methods, /* tp_methods */
780 0, /* tp_members */
781 0, /* tp_getset */
782 0, /* tp_base */
783 0, /* tp_dict */
784 0, /* tp_descr_get */
785 0, /* tp_descr_set */
786 0, /* tp_dictoffset */
787 (initproc)profiler_init, /* tp_init */
788 PyType_GenericAlloc, /* tp_alloc */
789 PyType_GenericNew, /* tp_new */
790 PyObject_Del, /* tp_free */
Armin Rigoa871ef22006-02-08 12:53:56 +0000791};
792
793static PyMethodDef moduleMethods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000794 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000795};
796
Martin v. Löwis1a214512008-06-11 05:26:20 +0000797
798static struct PyModuleDef _lsprofmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000799 PyModuleDef_HEAD_INIT,
800 "_lsprof",
801 "Fast profiler",
802 -1,
803 moduleMethods,
804 NULL,
805 NULL,
806 NULL,
807 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000808};
809
Armin Rigoa871ef22006-02-08 12:53:56 +0000810PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000811PyInit__lsprof(void)
Armin Rigoa871ef22006-02-08 12:53:56 +0000812{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000813 PyObject *module, *d;
814 module = PyModule_Create(&_lsprofmodule);
815 if (module == NULL)
816 return NULL;
817 d = PyModule_GetDict(module);
818 if (PyType_Ready(&PyProfiler_Type) < 0)
819 return NULL;
820 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
Armin Rigoa871ef22006-02-08 12:53:56 +0000821
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000822 if (!initialized) {
Victor Stinner1c8f0592013-07-22 22:24:54 +0200823 if (PyStructSequence_InitType2(&StatsEntryType,
824 &profiler_entry_desc) < 0)
825 return NULL;
826 if (PyStructSequence_InitType2(&StatsSubEntryType,
827 &profiler_subentry_desc) < 0)
828 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000829 }
830 Py_INCREF((PyObject*) &StatsEntryType);
831 Py_INCREF((PyObject*) &StatsSubEntryType);
832 PyModule_AddObject(module, "profiler_entry",
833 (PyObject*) &StatsEntryType);
834 PyModule_AddObject(module, "profiler_subentry",
835 (PyObject*) &StatsSubEntryType);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000836 initialized = 1;
837 return module;
Armin Rigoa871ef22006-02-08 12:53:56 +0000838}