blob: 5e53d839640d994f01e15309a698f98dc2b1193e [file] [log] [blame]
Armin Rigoa871ef22006-02-08 12:53:56 +00001#include "Python.h"
Armin Rigoa871ef22006-02-08 12:53:56 +00002#include "rotatingtree.h"
3
Armin Rigoa871ef22006-02-08 12:53:56 +00004/************************************************************/
5/* Written by Brett Rosen and Ted Czotter */
6
7struct _ProfilerEntry;
8
9/* represents a function called from another function */
10typedef struct _ProfilerSubEntry {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000011 rotating_node_t header;
Inada Naoki536a35b2019-04-11 19:11:46 +090012 _PyTime_t tt;
13 _PyTime_t it;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000014 long callcount;
15 long recursivecallcount;
16 long recursionLevel;
Armin Rigoa871ef22006-02-08 12:53:56 +000017} ProfilerSubEntry;
18
19/* represents a function or user defined block */
20typedef struct _ProfilerEntry {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000021 rotating_node_t header;
22 PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
Inada Naoki536a35b2019-04-11 19:11:46 +090023 _PyTime_t tt; /* total time in this entry */
24 _PyTime_t it; /* inline time in this entry (not in subcalls) */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000025 long callcount; /* how many times this was called */
26 long recursivecallcount; /* how many times called recursively */
27 long recursionLevel;
28 rotating_node_t *calls;
Armin Rigoa871ef22006-02-08 12:53:56 +000029} ProfilerEntry;
30
31typedef struct _ProfilerContext {
Inada Naoki536a35b2019-04-11 19:11:46 +090032 _PyTime_t t0;
33 _PyTime_t subt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000034 struct _ProfilerContext *previous;
35 ProfilerEntry *ctxEntry;
Armin Rigoa871ef22006-02-08 12:53:56 +000036} ProfilerContext;
37
38typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000039 PyObject_HEAD
40 rotating_node_t *profilerEntries;
41 ProfilerContext *currentProfilerContext;
42 ProfilerContext *freelistProfilerContext;
43 int flags;
44 PyObject *externalTimer;
45 double externalTimerUnit;
Armin Rigoa871ef22006-02-08 12:53:56 +000046} ProfilerObject;
47
48#define POF_ENABLED 0x001
49#define POF_SUBCALLS 0x002
50#define POF_BUILTINS 0x004
51#define POF_NOMEMORY 0x100
52
Neal Norwitz227b5332006-03-22 09:28:35 +000053static PyTypeObject PyProfiler_Type;
Armin Rigoa871ef22006-02-08 12:53:56 +000054
55#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
Dong-hee Na1b55b652020-02-17 19:09:15 +090056#define PyProfiler_CheckExact(op) Py_IS_TYPE(op, &PyProfiler_Type)
Armin Rigoa871ef22006-02-08 12:53:56 +000057
58/*** External Timers ***/
59
Inada Naoki536a35b2019-04-11 19:11:46 +090060static _PyTime_t CallExternalTimer(ProfilerObject *pObj)
Armin Rigoa871ef22006-02-08 12:53:56 +000061{
Inada Naoki536a35b2019-04-11 19:11:46 +090062 PyObject *o = _PyObject_CallNoArg(pObj->externalTimer);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000063 if (o == NULL) {
64 PyErr_WriteUnraisable(pObj->externalTimer);
65 return 0;
66 }
Inada Naoki536a35b2019-04-11 19:11:46 +090067
68 _PyTime_t result;
69 int err;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000070 if (pObj->externalTimerUnit > 0.0) {
71 /* interpret the result as an integer that will be scaled
72 in profiler_getstats() */
Inada Naoki536a35b2019-04-11 19:11:46 +090073 err = _PyTime_FromNanosecondsObject(&result, o);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000074 }
75 else {
76 /* interpret the result as a double measured in seconds.
Inada Naoki536a35b2019-04-11 19:11:46 +090077 As the profiler works with _PyTime_t internally
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000078 we convert it to a large integer */
Inada Naoki536a35b2019-04-11 19:11:46 +090079 err = _PyTime_FromSecondsObject(&result, o, _PyTime_ROUND_FLOOR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000080 }
81 Py_DECREF(o);
Inada Naoki536a35b2019-04-11 19:11:46 +090082 if (err < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000083 PyErr_WriteUnraisable(pObj->externalTimer);
84 return 0;
85 }
86 return result;
Armin Rigoa871ef22006-02-08 12:53:56 +000087}
88
Inada Naoki536a35b2019-04-11 19:11:46 +090089static inline _PyTime_t
90call_timer(ProfilerObject *pObj)
91{
92 if (pObj->externalTimer != NULL) {
93 return CallExternalTimer(pObj);
94 }
95 else {
96 return _PyTime_GetPerfCounter();
97 }
98}
99
Armin Rigoa871ef22006-02-08 12:53:56 +0000100
101/*** ProfilerObject ***/
102
103static PyObject *
104normalizeUserObj(PyObject *obj)
105{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000106 PyCFunctionObject *fn;
107 if (!PyCFunction_Check(obj)) {
108 Py_INCREF(obj);
109 return obj;
110 }
111 /* Replace built-in function objects with a descriptive string
112 because of built-in methods -- keeping a reference to
113 __self__ is probably not a good idea. */
114 fn = (PyCFunctionObject *)obj;
Armin Rigoa871ef22006-02-08 12:53:56 +0000115
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000116 if (fn->m_self == NULL) {
117 /* built-in function: look up the module name */
118 PyObject *mod = fn->m_module;
Victor Stinner7edb5df2011-06-20 14:59:53 +0200119 PyObject *modname = NULL;
120 if (mod != NULL) {
121 if (PyUnicode_Check(mod)) {
122 modname = mod;
123 Py_INCREF(modname);
124 }
125 else if (PyModule_Check(mod)) {
126 modname = PyModule_GetNameObject(mod);
127 if (modname == NULL)
128 PyErr_Clear();
Alexander Belopolskye239d232010-12-08 23:31:48 +0000129 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000130 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200131 if (modname != NULL) {
Serhiy Storchakaf4934ea2016-11-16 10:17:58 +0200132 if (!_PyUnicode_EqualToASCIIString(modname, "builtins")) {
Victor Stinner7edb5df2011-06-20 14:59:53 +0200133 PyObject *result;
134 result = PyUnicode_FromFormat("<%U.%s>", modname,
135 fn->m_ml->ml_name);
136 Py_DECREF(modname);
137 return result;
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000138 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200139 Py_DECREF(modname);
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000140 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200141 return PyUnicode_FromFormat("<%s>", fn->m_ml->ml_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000142 }
143 else {
144 /* built-in method: try to return
145 repr(getattr(type(__self__), __name__))
146 */
147 PyObject *self = fn->m_self;
148 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400149 PyObject *modname = fn->m_module;
150
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000151 if (name != NULL) {
152 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
153 Py_XINCREF(mo);
154 Py_DECREF(name);
155 if (mo != NULL) {
156 PyObject *res = PyObject_Repr(mo);
157 Py_DECREF(mo);
158 if (res != NULL)
159 return res;
160 }
161 }
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400162 /* Otherwise, use __module__ */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000163 PyErr_Clear();
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400164 if (modname != NULL && PyUnicode_Check(modname))
165 return PyUnicode_FromFormat("<built-in method %S.%s>",
166 modname, fn->m_ml->ml_name);
167 else
168 return PyUnicode_FromFormat("<built-in method %s>",
169 fn->m_ml->ml_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000170 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000171}
172
173static ProfilerEntry*
174newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
175{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000176 ProfilerEntry *self;
Victor Stinnerb6404912013-07-07 16:21:41 +0200177 self = (ProfilerEntry*) PyMem_Malloc(sizeof(ProfilerEntry));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000178 if (self == NULL) {
179 pObj->flags |= POF_NOMEMORY;
180 return NULL;
181 }
182 userObj = normalizeUserObj(userObj);
183 if (userObj == NULL) {
184 PyErr_Clear();
Victor Stinnerb6404912013-07-07 16:21:41 +0200185 PyMem_Free(self);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000186 pObj->flags |= POF_NOMEMORY;
187 return NULL;
188 }
189 self->header.key = key;
190 self->userObj = userObj;
191 self->tt = 0;
192 self->it = 0;
193 self->callcount = 0;
194 self->recursivecallcount = 0;
195 self->recursionLevel = 0;
196 self->calls = EMPTY_ROTATING_TREE;
197 RotatingTree_Add(&pObj->profilerEntries, &self->header);
198 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000199}
200
201static ProfilerEntry*
202getEntry(ProfilerObject *pObj, void *key)
203{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000204 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
Armin Rigoa871ef22006-02-08 12:53:56 +0000205}
206
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000207static ProfilerSubEntry *
Armin Rigoa871ef22006-02-08 12:53:56 +0000208getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
209{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
211 (void *)entry);
Armin Rigoa871ef22006-02-08 12:53:56 +0000212}
213
214static ProfilerSubEntry *
215newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
216{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000217 ProfilerSubEntry *self;
Victor Stinnerb6404912013-07-07 16:21:41 +0200218 self = (ProfilerSubEntry*) PyMem_Malloc(sizeof(ProfilerSubEntry));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000219 if (self == NULL) {
220 pObj->flags |= POF_NOMEMORY;
221 return NULL;
222 }
223 self->header.key = (void *)entry;
224 self->tt = 0;
225 self->it = 0;
226 self->callcount = 0;
227 self->recursivecallcount = 0;
228 self->recursionLevel = 0;
229 RotatingTree_Add(&caller->calls, &self->header);
230 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000231}
232
233static int freeSubEntry(rotating_node_t *header, void *arg)
234{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000235 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
Victor Stinnerb6404912013-07-07 16:21:41 +0200236 PyMem_Free(subentry);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000237 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000238}
239
240static int freeEntry(rotating_node_t *header, void *arg)
241{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000242 ProfilerEntry *entry = (ProfilerEntry*) header;
243 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
244 Py_DECREF(entry->userObj);
Victor Stinnerb6404912013-07-07 16:21:41 +0200245 PyMem_Free(entry);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000246 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000247}
248
249static void clearEntries(ProfilerObject *pObj)
250{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000251 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
252 pObj->profilerEntries = EMPTY_ROTATING_TREE;
253 /* release the memory hold by the ProfilerContexts */
254 if (pObj->currentProfilerContext) {
Victor Stinnerb6404912013-07-07 16:21:41 +0200255 PyMem_Free(pObj->currentProfilerContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000256 pObj->currentProfilerContext = NULL;
257 }
258 while (pObj->freelistProfilerContext) {
259 ProfilerContext *c = pObj->freelistProfilerContext;
260 pObj->freelistProfilerContext = c->previous;
Victor Stinnerb6404912013-07-07 16:21:41 +0200261 PyMem_Free(c);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000262 }
263 pObj->freelistProfilerContext = NULL;
Armin Rigoa871ef22006-02-08 12:53:56 +0000264}
265
266static void
267initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
268{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000269 self->ctxEntry = entry;
270 self->subt = 0;
271 self->previous = pObj->currentProfilerContext;
272 pObj->currentProfilerContext = self;
273 ++entry->recursionLevel;
274 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
275 /* find or create an entry for me in my caller's entry */
276 ProfilerEntry *caller = self->previous->ctxEntry;
277 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
278 if (subentry == NULL)
279 subentry = newSubEntry(pObj, caller, entry);
280 if (subentry)
281 ++subentry->recursionLevel;
282 }
Inada Naoki536a35b2019-04-11 19:11:46 +0900283 self->t0 = call_timer(pObj);
Armin Rigoa871ef22006-02-08 12:53:56 +0000284}
285
286static void
287Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
288{
Inada Naoki536a35b2019-04-11 19:11:46 +0900289 _PyTime_t tt = call_timer(pObj) - self->t0;
290 _PyTime_t it = tt - self->subt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 if (self->previous)
292 self->previous->subt += tt;
293 pObj->currentProfilerContext = self->previous;
294 if (--entry->recursionLevel == 0)
295 entry->tt += tt;
296 else
297 ++entry->recursivecallcount;
298 entry->it += it;
299 entry->callcount++;
300 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
301 /* find or create an entry for me in my caller's entry */
302 ProfilerEntry *caller = self->previous->ctxEntry;
303 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
304 if (subentry) {
305 if (--subentry->recursionLevel == 0)
306 subentry->tt += tt;
307 else
308 ++subentry->recursivecallcount;
309 subentry->it += it;
310 ++subentry->callcount;
311 }
312 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000313}
314
315static void
316ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
317{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000318 /* entering a call to the function identified by 'key'
319 (which can be a PyCodeObject or a PyMethodDef pointer) */
320 ProfilerObject *pObj = (ProfilerObject*)self;
321 ProfilerEntry *profEntry;
322 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000323
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000324 /* In the case of entering a generator expression frame via a
325 * throw (gen_send_ex(.., 1)), we may already have an
326 * Exception set here. We must not mess around with this
327 * exception, and some of the code under here assumes that
328 * PyErr_* is its own to mess around with, so we have to
329 * save and restore any current exception. */
330 PyObject *last_type, *last_value, *last_tb;
331 PyErr_Fetch(&last_type, &last_value, &last_tb);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000332
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000333 profEntry = getEntry(pObj, key);
334 if (profEntry == NULL) {
335 profEntry = newProfilerEntry(pObj, key, userObj);
336 if (profEntry == NULL)
337 goto restorePyerr;
338 }
339 /* grab a ProfilerContext out of the free list */
340 pContext = pObj->freelistProfilerContext;
341 if (pContext) {
342 pObj->freelistProfilerContext = pContext->previous;
343 }
344 else {
345 /* free list exhausted, allocate a new one */
346 pContext = (ProfilerContext*)
Victor Stinnerb6404912013-07-07 16:21:41 +0200347 PyMem_Malloc(sizeof(ProfilerContext));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000348 if (pContext == NULL) {
349 pObj->flags |= POF_NOMEMORY;
350 goto restorePyerr;
351 }
352 }
353 initContext(pObj, pContext, profEntry);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000354
355restorePyerr:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000356 PyErr_Restore(last_type, last_value, last_tb);
Armin Rigoa871ef22006-02-08 12:53:56 +0000357}
358
359static void
360ptrace_leave_call(PyObject *self, void *key)
361{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000362 /* leaving a call to the function identified by 'key' */
363 ProfilerObject *pObj = (ProfilerObject*)self;
364 ProfilerEntry *profEntry;
365 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000366
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 pContext = pObj->currentProfilerContext;
368 if (pContext == NULL)
369 return;
370 profEntry = getEntry(pObj, key);
371 if (profEntry) {
372 Stop(pObj, pContext, profEntry);
373 }
374 else {
375 pObj->currentProfilerContext = pContext->previous;
376 }
377 /* put pContext into the free list */
378 pContext->previous = pObj->freelistProfilerContext;
379 pObj->freelistProfilerContext = pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000380}
381
382static int
383profiler_callback(PyObject *self, PyFrameObject *frame, int what,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 PyObject *arg)
Armin Rigoa871ef22006-02-08 12:53:56 +0000385{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000386 switch (what) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000387
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000388 /* the 'frame' of a called function is about to start its execution */
389 case PyTrace_CALL:
Victor Stinnera42ca742020-04-28 19:01:31 +0200390 {
391 PyCodeObject *code = PyFrame_GetCode(frame);
392 ptrace_enter_call(self, (void *)code, (PyObject *)code);
Victor Stinner8852ad42020-04-29 01:28:13 +0200393 Py_DECREF(code);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000394 break;
Victor Stinnera42ca742020-04-28 19:01:31 +0200395 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000396
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000397 /* the 'frame' of a called function is about to finish
398 (either normally or with an exception) */
399 case PyTrace_RETURN:
Victor Stinner8852ad42020-04-29 01:28:13 +0200400 {
401 PyCodeObject *code = PyFrame_GetCode(frame);
402 ptrace_leave_call(self, (void *)code);
403 Py_DECREF(code);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000404 break;
Victor Stinner8852ad42020-04-29 01:28:13 +0200405 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000406
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000407 /* case PyTrace_EXCEPTION:
408 If the exception results in the function exiting, a
409 PyTrace_RETURN event will be generated, so we don't need to
410 handle it. */
Armin Rigoa871ef22006-02-08 12:53:56 +0000411
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000412 /* the Python function 'frame' is issuing a call to the built-in
413 function 'arg' */
414 case PyTrace_C_CALL:
415 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
416 && PyCFunction_Check(arg)) {
417 ptrace_enter_call(self,
418 ((PyCFunctionObject *)arg)->m_ml,
419 arg);
420 }
421 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000422
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000423 /* the call to the built-in function 'arg' is returning into its
424 caller 'frame' */
425 case PyTrace_C_RETURN: /* ...normally */
426 case PyTrace_C_EXCEPTION: /* ...with an exception set */
427 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
428 && PyCFunction_Check(arg)) {
429 ptrace_leave_call(self,
430 ((PyCFunctionObject *)arg)->m_ml);
431 }
432 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000433
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000434 default:
435 break;
436 }
437 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000438}
439
440static int
441pending_exception(ProfilerObject *pObj)
442{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000443 if (pObj->flags & POF_NOMEMORY) {
444 pObj->flags -= POF_NOMEMORY;
445 PyErr_SetString(PyExc_MemoryError,
446 "memory was exhausted while profiling");
447 return -1;
448 }
449 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000450}
451
452/************************************************************/
453
454static PyStructSequence_Field profiler_entry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000455 {"code", "code object or built-in function name"},
456 {"callcount", "how many times this was called"},
457 {"reccallcount", "how many times called recursively"},
458 {"totaltime", "total time in this entry"},
459 {"inlinetime", "inline time in this entry (not in subcalls)"},
460 {"calls", "details of the calls"},
461 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000462};
463
464static PyStructSequence_Field profiler_subentry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000465 {"code", "called code object or built-in function name"},
466 {"callcount", "how many times this is called"},
467 {"reccallcount", "how many times this is called recursively"},
468 {"totaltime", "total time spent in this call"},
469 {"inlinetime", "inline time (not in further subcalls)"},
470 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000471};
472
473static PyStructSequence_Desc profiler_entry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000474 "_lsprof.profiler_entry", /* name */
475 NULL, /* doc */
476 profiler_entry_fields,
477 6
Armin Rigoa871ef22006-02-08 12:53:56 +0000478};
479
480static PyStructSequence_Desc profiler_subentry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000481 "_lsprof.profiler_subentry", /* name */
482 NULL, /* doc */
483 profiler_subentry_fields,
484 5
Armin Rigoa871ef22006-02-08 12:53:56 +0000485};
486
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000487static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000488static PyTypeObject StatsEntryType;
489static PyTypeObject StatsSubEntryType;
490
491
492typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000493 PyObject *list;
494 PyObject *sublist;
495 double factor;
Armin Rigoa871ef22006-02-08 12:53:56 +0000496} statscollector_t;
497
498static int statsForSubEntry(rotating_node_t *node, void *arg)
499{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000500 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
501 statscollector_t *collect = (statscollector_t*) arg;
502 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
503 int err;
504 PyObject *sinfo;
505 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
506 "((Olldd))",
507 entry->userObj,
508 sentry->callcount,
509 sentry->recursivecallcount,
510 collect->factor * sentry->tt,
511 collect->factor * sentry->it);
512 if (sinfo == NULL)
513 return -1;
514 err = PyList_Append(collect->sublist, sinfo);
515 Py_DECREF(sinfo);
516 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000517}
518
519static int statsForEntry(rotating_node_t *node, void *arg)
520{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000521 ProfilerEntry *entry = (ProfilerEntry*) node;
522 statscollector_t *collect = (statscollector_t*) arg;
523 PyObject *info;
524 int err;
525 if (entry->callcount == 0)
526 return 0; /* skip */
Armin Rigoa871ef22006-02-08 12:53:56 +0000527
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000528 if (entry->calls != EMPTY_ROTATING_TREE) {
529 collect->sublist = PyList_New(0);
530 if (collect->sublist == NULL)
531 return -1;
532 if (RotatingTree_Enum(entry->calls,
533 statsForSubEntry, collect) != 0) {
534 Py_DECREF(collect->sublist);
535 return -1;
536 }
537 }
538 else {
539 Py_INCREF(Py_None);
540 collect->sublist = Py_None;
541 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000542
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000543 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
544 "((OllddO))",
545 entry->userObj,
546 entry->callcount,
547 entry->recursivecallcount,
548 collect->factor * entry->tt,
549 collect->factor * entry->it,
550 collect->sublist);
551 Py_DECREF(collect->sublist);
552 if (info == NULL)
553 return -1;
554 err = PyList_Append(collect->list, info);
555 Py_DECREF(info);
556 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000557}
558
559PyDoc_STRVAR(getstats_doc, "\
560getstats() -> list of profiler_entry objects\n\
561\n\
562Return all information collected by the profiler.\n\
563Each profiler_entry is a tuple-like object with the\n\
564following attributes:\n\
565\n\
566 code code object\n\
567 callcount how many times this was called\n\
568 reccallcount how many times called recursively\n\
569 totaltime total time in this entry\n\
570 inlinetime inline time in this entry (not in subcalls)\n\
571 calls details of the calls\n\
572\n\
573The calls attribute is either None or a list of\n\
574profiler_subentry objects:\n\
575\n\
576 code called code object\n\
577 callcount how many times this is called\n\
578 reccallcount how many times this is called recursively\n\
579 totaltime total time spent in this call\n\
580 inlinetime inline time (not in further subcalls)\n\
581");
582
583static PyObject*
584profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
585{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000586 statscollector_t collect;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100587 if (pending_exception(pObj)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000588 return NULL;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100589 }
Inada Naoki536a35b2019-04-11 19:11:46 +0900590 if (!pObj->externalTimer || pObj->externalTimerUnit == 0.0) {
591 _PyTime_t onesec = _PyTime_FromSeconds(1);
592 collect.factor = (double)1 / onesec;
593 }
594 else {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000595 collect.factor = pObj->externalTimerUnit;
Inada Naoki536a35b2019-04-11 19:11:46 +0900596 }
597
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000598 collect.list = PyList_New(0);
599 if (collect.list == NULL)
600 return NULL;
601 if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
602 != 0) {
603 Py_DECREF(collect.list);
604 return NULL;
605 }
606 return collect.list;
Armin Rigoa871ef22006-02-08 12:53:56 +0000607}
608
609static int
610setSubcalls(ProfilerObject *pObj, int nvalue)
611{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000612 if (nvalue == 0)
613 pObj->flags &= ~POF_SUBCALLS;
614 else if (nvalue > 0)
615 pObj->flags |= POF_SUBCALLS;
616 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000617}
618
619static int
620setBuiltins(ProfilerObject *pObj, int nvalue)
621{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000622 if (nvalue == 0)
623 pObj->flags &= ~POF_BUILTINS;
624 else if (nvalue > 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000625 pObj->flags |= POF_BUILTINS;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000626 }
627 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000628}
629
630PyDoc_STRVAR(enable_doc, "\
631enable(subcalls=True, builtins=True)\n\
632\n\
633Start collecting profiling information.\n\
634If 'subcalls' is True, also records for each function\n\
635statistics separated according to its current caller.\n\
636If 'builtins' is True, records the time spent in\n\
637built-in functions separately from their caller.\n\
638");
639
640static PyObject*
641profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
642{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000643 int subcalls = -1;
644 int builtins = -1;
645 static char *kwlist[] = {"subcalls", "builtins", 0};
646 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
647 kwlist, &subcalls, &builtins))
648 return NULL;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100649 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000650 return NULL;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100651 }
652
653 PyThreadState *tstate = PyThreadState_GET();
654 if (_PyEval_SetProfile(tstate, profiler_callback, (PyObject*)self) < 0) {
655 return NULL;
656 }
657
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000658 self->flags |= POF_ENABLED;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200659 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000660}
661
662static void
663flush_unmatched(ProfilerObject *pObj)
664{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000665 while (pObj->currentProfilerContext) {
666 ProfilerContext *pContext = pObj->currentProfilerContext;
667 ProfilerEntry *profEntry= pContext->ctxEntry;
668 if (profEntry)
669 Stop(pObj, pContext, profEntry);
670 else
671 pObj->currentProfilerContext = pContext->previous;
672 if (pContext)
Victor Stinnerb6404912013-07-07 16:21:41 +0200673 PyMem_Free(pContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000674 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000675
676}
677
678PyDoc_STRVAR(disable_doc, "\
679disable()\n\
680\n\
681Stop collecting profiling information.\n\
682");
683
684static PyObject*
685profiler_disable(ProfilerObject *self, PyObject* noarg)
686{
Victor Stinner309d7cc2020-03-13 16:39:12 +0100687 PyThreadState *tstate = PyThreadState_GET();
688 if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000689 return NULL;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100690 }
691 self->flags &= ~POF_ENABLED;
692
693 flush_unmatched(self);
694 if (pending_exception(self)) {
695 return NULL;
696 }
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200697 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000698}
699
700PyDoc_STRVAR(clear_doc, "\
701clear()\n\
702\n\
703Clear all profiling information collected so far.\n\
704");
705
706static PyObject*
707profiler_clear(ProfilerObject *pObj, PyObject* noarg)
708{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000709 clearEntries(pObj);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200710 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000711}
712
713static void
714profiler_dealloc(ProfilerObject *op)
715{
Victor Stinner309d7cc2020-03-13 16:39:12 +0100716 if (op->flags & POF_ENABLED) {
717 PyThreadState *tstate = PyThreadState_GET();
718 if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
719 PyErr_WriteUnraisable((PyObject *)op);
720 }
721 }
722
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000723 flush_unmatched(op);
724 clearEntries(op);
725 Py_XDECREF(op->externalTimer);
726 Py_TYPE(op)->tp_free(op);
Armin Rigoa871ef22006-02-08 12:53:56 +0000727}
728
729static int
730profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
731{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000732 PyObject *timer = NULL;
733 double timeunit = 0.0;
734 int subcalls = 1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000735 int builtins = 1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000736 static char *kwlist[] = {"timer", "timeunit",
737 "subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000738
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000739 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
740 &timer, &timeunit,
741 &subcalls, &builtins))
742 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000743
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000744 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
745 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000746 pObj->externalTimerUnit = timeunit;
Serhiy Storchaka576f1322016-01-05 21:27:54 +0200747 Py_XINCREF(timer);
Serhiy Storchakaec397562016-04-06 09:50:03 +0300748 Py_XSETREF(pObj->externalTimer, timer);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000749 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000750}
751
752static PyMethodDef profiler_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000753 {"getstats", (PyCFunction)profiler_getstats,
754 METH_NOARGS, getstats_doc},
Serhiy Storchaka62be7422018-11-27 13:27:31 +0200755 {"enable", (PyCFunction)(void(*)(void))profiler_enable,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000756 METH_VARARGS | METH_KEYWORDS, enable_doc},
757 {"disable", (PyCFunction)profiler_disable,
758 METH_NOARGS, disable_doc},
759 {"clear", (PyCFunction)profiler_clear,
760 METH_NOARGS, clear_doc},
761 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000762};
763
764PyDoc_STRVAR(profiler_doc, "\
INADA Naoki2ebd3812018-08-03 18:09:57 +0900765Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\
Armin Rigoa871ef22006-02-08 12:53:56 +0000766\n\
767 Builds a profiler object using the specified timer function.\n\
768 The default timer is a fast built-in one based on real time.\n\
INADA Naoki2ebd3812018-08-03 18:09:57 +0900769 For custom timer functions returning integers, timeunit can\n\
Armin Rigoa871ef22006-02-08 12:53:56 +0000770 be a float specifying a scale (i.e. how long each integer unit\n\
771 is, in seconds).\n\
772");
773
Neal Norwitz227b5332006-03-22 09:28:35 +0000774static PyTypeObject PyProfiler_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000775 PyVarObject_HEAD_INIT(NULL, 0)
776 "_lsprof.Profiler", /* tp_name */
777 sizeof(ProfilerObject), /* tp_basicsize */
778 0, /* tp_itemsize */
779 (destructor)profiler_dealloc, /* tp_dealloc */
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200780 0, /* tp_vectorcall_offset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000781 0, /* tp_getattr */
782 0, /* tp_setattr */
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200783 0, /* tp_as_async */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000784 0, /* tp_repr */
785 0, /* tp_as_number */
786 0, /* tp_as_sequence */
787 0, /* tp_as_mapping */
788 0, /* tp_hash */
789 0, /* tp_call */
790 0, /* tp_str */
791 0, /* tp_getattro */
792 0, /* tp_setattro */
793 0, /* tp_as_buffer */
794 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
795 profiler_doc, /* tp_doc */
796 0, /* tp_traverse */
797 0, /* tp_clear */
798 0, /* tp_richcompare */
799 0, /* tp_weaklistoffset */
800 0, /* tp_iter */
801 0, /* tp_iternext */
802 profiler_methods, /* tp_methods */
803 0, /* tp_members */
804 0, /* tp_getset */
805 0, /* tp_base */
806 0, /* tp_dict */
807 0, /* tp_descr_get */
808 0, /* tp_descr_set */
809 0, /* tp_dictoffset */
810 (initproc)profiler_init, /* tp_init */
811 PyType_GenericAlloc, /* tp_alloc */
812 PyType_GenericNew, /* tp_new */
813 PyObject_Del, /* tp_free */
Armin Rigoa871ef22006-02-08 12:53:56 +0000814};
815
816static PyMethodDef moduleMethods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000817 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000818};
819
Martin v. Löwis1a214512008-06-11 05:26:20 +0000820
821static struct PyModuleDef _lsprofmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000822 PyModuleDef_HEAD_INIT,
823 "_lsprof",
824 "Fast profiler",
825 -1,
826 moduleMethods,
827 NULL,
828 NULL,
829 NULL,
830 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000831};
832
Armin Rigoa871ef22006-02-08 12:53:56 +0000833PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000834PyInit__lsprof(void)
Armin Rigoa871ef22006-02-08 12:53:56 +0000835{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000836 PyObject *module, *d;
837 module = PyModule_Create(&_lsprofmodule);
838 if (module == NULL)
839 return NULL;
840 d = PyModule_GetDict(module);
841 if (PyType_Ready(&PyProfiler_Type) < 0)
842 return NULL;
843 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
Armin Rigoa871ef22006-02-08 12:53:56 +0000844
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000845 if (!initialized) {
Victor Stinner1c8f0592013-07-22 22:24:54 +0200846 if (PyStructSequence_InitType2(&StatsEntryType,
847 &profiler_entry_desc) < 0)
848 return NULL;
849 if (PyStructSequence_InitType2(&StatsSubEntryType,
850 &profiler_subentry_desc) < 0)
851 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000852 }
853 Py_INCREF((PyObject*) &StatsEntryType);
854 Py_INCREF((PyObject*) &StatsSubEntryType);
855 PyModule_AddObject(module, "profiler_entry",
856 (PyObject*) &StatsEntryType);
857 PyModule_AddObject(module, "profiler_subentry",
858 (PyObject*) &StatsSubEntryType);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000859 initialized = 1;
860 return module;
Armin Rigoa871ef22006-02-08 12:53:56 +0000861}