blob: 78d464d1481d75e63497be71fbf62adc2bf59924 [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
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -050053/*[clinic input]
54module _lsprof
55class _lsprof.Profiler "ProfilerObject *" "&ProfilerType"
56[clinic start generated code]*/
57/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e349ac952152f336]*/
Armin Rigoa871ef22006-02-08 12:53:56 +000058
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -050059#include "clinic/_lsprof.c.h"
60
Mohamed Koubaa83de1102020-09-23 05:33:21 -050061typedef struct {
62 PyTypeObject *profiler_type;
63 PyTypeObject *stats_entry_type;
64 PyTypeObject *stats_subentry_type;
65} _lsprof_state;
66
67static inline _lsprof_state*
68_lsprof_get_state(PyObject *module)
69{
70 void *state = PyModule_GetState(module);
71 assert(state != NULL);
72 return (_lsprof_state *)state;
73}
Armin Rigoa871ef22006-02-08 12:53:56 +000074
75/*** External Timers ***/
76
Inada Naoki536a35b2019-04-11 19:11:46 +090077static _PyTime_t CallExternalTimer(ProfilerObject *pObj)
Armin Rigoa871ef22006-02-08 12:53:56 +000078{
Inada Naoki536a35b2019-04-11 19:11:46 +090079 PyObject *o = _PyObject_CallNoArg(pObj->externalTimer);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000080 if (o == NULL) {
81 PyErr_WriteUnraisable(pObj->externalTimer);
82 return 0;
83 }
Inada Naoki536a35b2019-04-11 19:11:46 +090084
85 _PyTime_t result;
86 int err;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000087 if (pObj->externalTimerUnit > 0.0) {
88 /* interpret the result as an integer that will be scaled
89 in profiler_getstats() */
Inada Naoki536a35b2019-04-11 19:11:46 +090090 err = _PyTime_FromNanosecondsObject(&result, o);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000091 }
92 else {
93 /* interpret the result as a double measured in seconds.
Inada Naoki536a35b2019-04-11 19:11:46 +090094 As the profiler works with _PyTime_t internally
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000095 we convert it to a large integer */
Inada Naoki536a35b2019-04-11 19:11:46 +090096 err = _PyTime_FromSecondsObject(&result, o, _PyTime_ROUND_FLOOR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000097 }
98 Py_DECREF(o);
Inada Naoki536a35b2019-04-11 19:11:46 +090099 if (err < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000100 PyErr_WriteUnraisable(pObj->externalTimer);
101 return 0;
102 }
103 return result;
Armin Rigoa871ef22006-02-08 12:53:56 +0000104}
105
Inada Naoki536a35b2019-04-11 19:11:46 +0900106static inline _PyTime_t
107call_timer(ProfilerObject *pObj)
108{
109 if (pObj->externalTimer != NULL) {
110 return CallExternalTimer(pObj);
111 }
112 else {
113 return _PyTime_GetPerfCounter();
114 }
115}
116
Armin Rigoa871ef22006-02-08 12:53:56 +0000117
118/*** ProfilerObject ***/
119
120static PyObject *
121normalizeUserObj(PyObject *obj)
122{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000123 PyCFunctionObject *fn;
124 if (!PyCFunction_Check(obj)) {
125 Py_INCREF(obj);
126 return obj;
127 }
128 /* Replace built-in function objects with a descriptive string
129 because of built-in methods -- keeping a reference to
130 __self__ is probably not a good idea. */
131 fn = (PyCFunctionObject *)obj;
Armin Rigoa871ef22006-02-08 12:53:56 +0000132
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000133 if (fn->m_self == NULL) {
134 /* built-in function: look up the module name */
135 PyObject *mod = fn->m_module;
Victor Stinner7edb5df2011-06-20 14:59:53 +0200136 PyObject *modname = NULL;
137 if (mod != NULL) {
138 if (PyUnicode_Check(mod)) {
139 modname = mod;
140 Py_INCREF(modname);
141 }
142 else if (PyModule_Check(mod)) {
143 modname = PyModule_GetNameObject(mod);
144 if (modname == NULL)
145 PyErr_Clear();
Alexander Belopolskye239d232010-12-08 23:31:48 +0000146 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200148 if (modname != NULL) {
Serhiy Storchakaf4934ea2016-11-16 10:17:58 +0200149 if (!_PyUnicode_EqualToASCIIString(modname, "builtins")) {
Victor Stinner7edb5df2011-06-20 14:59:53 +0200150 PyObject *result;
151 result = PyUnicode_FromFormat("<%U.%s>", modname,
152 fn->m_ml->ml_name);
153 Py_DECREF(modname);
154 return result;
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000155 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200156 Py_DECREF(modname);
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000157 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200158 return PyUnicode_FromFormat("<%s>", fn->m_ml->ml_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000159 }
160 else {
161 /* built-in method: try to return
162 repr(getattr(type(__self__), __name__))
163 */
164 PyObject *self = fn->m_self;
165 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400166 PyObject *modname = fn->m_module;
167
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000168 if (name != NULL) {
169 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
170 Py_XINCREF(mo);
171 Py_DECREF(name);
172 if (mo != NULL) {
173 PyObject *res = PyObject_Repr(mo);
174 Py_DECREF(mo);
175 if (res != NULL)
176 return res;
177 }
178 }
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400179 /* Otherwise, use __module__ */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000180 PyErr_Clear();
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400181 if (modname != NULL && PyUnicode_Check(modname))
182 return PyUnicode_FromFormat("<built-in method %S.%s>",
183 modname, fn->m_ml->ml_name);
184 else
185 return PyUnicode_FromFormat("<built-in method %s>",
186 fn->m_ml->ml_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000187 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000188}
189
190static ProfilerEntry*
191newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
192{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000193 ProfilerEntry *self;
Victor Stinnerb6404912013-07-07 16:21:41 +0200194 self = (ProfilerEntry*) PyMem_Malloc(sizeof(ProfilerEntry));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000195 if (self == NULL) {
196 pObj->flags |= POF_NOMEMORY;
197 return NULL;
198 }
199 userObj = normalizeUserObj(userObj);
200 if (userObj == NULL) {
201 PyErr_Clear();
Victor Stinnerb6404912013-07-07 16:21:41 +0200202 PyMem_Free(self);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000203 pObj->flags |= POF_NOMEMORY;
204 return NULL;
205 }
206 self->header.key = key;
207 self->userObj = userObj;
208 self->tt = 0;
209 self->it = 0;
210 self->callcount = 0;
211 self->recursivecallcount = 0;
212 self->recursionLevel = 0;
213 self->calls = EMPTY_ROTATING_TREE;
214 RotatingTree_Add(&pObj->profilerEntries, &self->header);
215 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000216}
217
218static ProfilerEntry*
219getEntry(ProfilerObject *pObj, void *key)
220{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000221 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
Armin Rigoa871ef22006-02-08 12:53:56 +0000222}
223
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000224static ProfilerSubEntry *
Armin Rigoa871ef22006-02-08 12:53:56 +0000225getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
226{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000227 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
228 (void *)entry);
Armin Rigoa871ef22006-02-08 12:53:56 +0000229}
230
231static ProfilerSubEntry *
232newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
233{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000234 ProfilerSubEntry *self;
Victor Stinnerb6404912013-07-07 16:21:41 +0200235 self = (ProfilerSubEntry*) PyMem_Malloc(sizeof(ProfilerSubEntry));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000236 if (self == NULL) {
237 pObj->flags |= POF_NOMEMORY;
238 return NULL;
239 }
240 self->header.key = (void *)entry;
241 self->tt = 0;
242 self->it = 0;
243 self->callcount = 0;
244 self->recursivecallcount = 0;
245 self->recursionLevel = 0;
246 RotatingTree_Add(&caller->calls, &self->header);
247 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000248}
249
250static int freeSubEntry(rotating_node_t *header, void *arg)
251{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000252 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
Victor Stinnerb6404912013-07-07 16:21:41 +0200253 PyMem_Free(subentry);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000254 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000255}
256
257static int freeEntry(rotating_node_t *header, void *arg)
258{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000259 ProfilerEntry *entry = (ProfilerEntry*) header;
260 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
261 Py_DECREF(entry->userObj);
Victor Stinnerb6404912013-07-07 16:21:41 +0200262 PyMem_Free(entry);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000264}
265
266static void clearEntries(ProfilerObject *pObj)
267{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000268 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
269 pObj->profilerEntries = EMPTY_ROTATING_TREE;
270 /* release the memory hold by the ProfilerContexts */
271 if (pObj->currentProfilerContext) {
Victor Stinnerb6404912013-07-07 16:21:41 +0200272 PyMem_Free(pObj->currentProfilerContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000273 pObj->currentProfilerContext = NULL;
274 }
275 while (pObj->freelistProfilerContext) {
276 ProfilerContext *c = pObj->freelistProfilerContext;
277 pObj->freelistProfilerContext = c->previous;
Victor Stinnerb6404912013-07-07 16:21:41 +0200278 PyMem_Free(c);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000279 }
280 pObj->freelistProfilerContext = NULL;
Armin Rigoa871ef22006-02-08 12:53:56 +0000281}
282
283static void
284initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
285{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000286 self->ctxEntry = entry;
287 self->subt = 0;
288 self->previous = pObj->currentProfilerContext;
289 pObj->currentProfilerContext = self;
290 ++entry->recursionLevel;
291 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
292 /* find or create an entry for me in my caller's entry */
293 ProfilerEntry *caller = self->previous->ctxEntry;
294 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
295 if (subentry == NULL)
296 subentry = newSubEntry(pObj, caller, entry);
297 if (subentry)
298 ++subentry->recursionLevel;
299 }
Inada Naoki536a35b2019-04-11 19:11:46 +0900300 self->t0 = call_timer(pObj);
Armin Rigoa871ef22006-02-08 12:53:56 +0000301}
302
303static void
304Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
305{
Inada Naoki536a35b2019-04-11 19:11:46 +0900306 _PyTime_t tt = call_timer(pObj) - self->t0;
307 _PyTime_t it = tt - self->subt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000308 if (self->previous)
309 self->previous->subt += tt;
310 pObj->currentProfilerContext = self->previous;
311 if (--entry->recursionLevel == 0)
312 entry->tt += tt;
313 else
314 ++entry->recursivecallcount;
315 entry->it += it;
316 entry->callcount++;
317 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
318 /* find or create an entry for me in my caller's entry */
319 ProfilerEntry *caller = self->previous->ctxEntry;
320 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
321 if (subentry) {
322 if (--subentry->recursionLevel == 0)
323 subentry->tt += tt;
324 else
325 ++subentry->recursivecallcount;
326 subentry->it += it;
327 ++subentry->callcount;
328 }
329 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000330}
331
332static void
333ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
334{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000335 /* entering a call to the function identified by 'key'
336 (which can be a PyCodeObject or a PyMethodDef pointer) */
337 ProfilerObject *pObj = (ProfilerObject*)self;
338 ProfilerEntry *profEntry;
339 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000340
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000341 /* In the case of entering a generator expression frame via a
342 * throw (gen_send_ex(.., 1)), we may already have an
343 * Exception set here. We must not mess around with this
344 * exception, and some of the code under here assumes that
345 * PyErr_* is its own to mess around with, so we have to
346 * save and restore any current exception. */
347 PyObject *last_type, *last_value, *last_tb;
348 PyErr_Fetch(&last_type, &last_value, &last_tb);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000349
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000350 profEntry = getEntry(pObj, key);
351 if (profEntry == NULL) {
352 profEntry = newProfilerEntry(pObj, key, userObj);
353 if (profEntry == NULL)
354 goto restorePyerr;
355 }
356 /* grab a ProfilerContext out of the free list */
357 pContext = pObj->freelistProfilerContext;
358 if (pContext) {
359 pObj->freelistProfilerContext = pContext->previous;
360 }
361 else {
362 /* free list exhausted, allocate a new one */
363 pContext = (ProfilerContext*)
Victor Stinnerb6404912013-07-07 16:21:41 +0200364 PyMem_Malloc(sizeof(ProfilerContext));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000365 if (pContext == NULL) {
366 pObj->flags |= POF_NOMEMORY;
367 goto restorePyerr;
368 }
369 }
370 initContext(pObj, pContext, profEntry);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000371
372restorePyerr:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000373 PyErr_Restore(last_type, last_value, last_tb);
Armin Rigoa871ef22006-02-08 12:53:56 +0000374}
375
376static void
377ptrace_leave_call(PyObject *self, void *key)
378{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000379 /* leaving a call to the function identified by 'key' */
380 ProfilerObject *pObj = (ProfilerObject*)self;
381 ProfilerEntry *profEntry;
382 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000383
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 pContext = pObj->currentProfilerContext;
385 if (pContext == NULL)
386 return;
387 profEntry = getEntry(pObj, key);
388 if (profEntry) {
389 Stop(pObj, pContext, profEntry);
390 }
391 else {
392 pObj->currentProfilerContext = pContext->previous;
393 }
394 /* put pContext into the free list */
395 pContext->previous = pObj->freelistProfilerContext;
396 pObj->freelistProfilerContext = pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000397}
398
399static int
400profiler_callback(PyObject *self, PyFrameObject *frame, int what,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000401 PyObject *arg)
Armin Rigoa871ef22006-02-08 12:53:56 +0000402{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000403 switch (what) {
Armin Rigoa871ef22006-02-08 12:53:56 +0000404
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000405 /* the 'frame' of a called function is about to start its execution */
406 case PyTrace_CALL:
Victor Stinnera42ca742020-04-28 19:01:31 +0200407 {
408 PyCodeObject *code = PyFrame_GetCode(frame);
409 ptrace_enter_call(self, (void *)code, (PyObject *)code);
Victor Stinner8852ad42020-04-29 01:28:13 +0200410 Py_DECREF(code);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000411 break;
Victor Stinnera42ca742020-04-28 19:01:31 +0200412 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000413
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000414 /* the 'frame' of a called function is about to finish
415 (either normally or with an exception) */
416 case PyTrace_RETURN:
Victor Stinner8852ad42020-04-29 01:28:13 +0200417 {
418 PyCodeObject *code = PyFrame_GetCode(frame);
419 ptrace_leave_call(self, (void *)code);
420 Py_DECREF(code);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000421 break;
Victor Stinner8852ad42020-04-29 01:28:13 +0200422 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000423
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000424 /* case PyTrace_EXCEPTION:
425 If the exception results in the function exiting, a
426 PyTrace_RETURN event will be generated, so we don't need to
427 handle it. */
Armin Rigoa871ef22006-02-08 12:53:56 +0000428
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000429 /* the Python function 'frame' is issuing a call to the built-in
430 function 'arg' */
431 case PyTrace_C_CALL:
432 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
433 && PyCFunction_Check(arg)) {
434 ptrace_enter_call(self,
435 ((PyCFunctionObject *)arg)->m_ml,
436 arg);
437 }
438 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000439
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000440 /* the call to the built-in function 'arg' is returning into its
441 caller 'frame' */
442 case PyTrace_C_RETURN: /* ...normally */
443 case PyTrace_C_EXCEPTION: /* ...with an exception set */
444 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
445 && PyCFunction_Check(arg)) {
446 ptrace_leave_call(self,
447 ((PyCFunctionObject *)arg)->m_ml);
448 }
449 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000450
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000451 default:
452 break;
453 }
454 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000455}
456
457static int
458pending_exception(ProfilerObject *pObj)
459{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000460 if (pObj->flags & POF_NOMEMORY) {
461 pObj->flags -= POF_NOMEMORY;
462 PyErr_SetString(PyExc_MemoryError,
463 "memory was exhausted while profiling");
464 return -1;
465 }
466 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000467}
468
469/************************************************************/
470
471static PyStructSequence_Field profiler_entry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000472 {"code", "code object or built-in function name"},
473 {"callcount", "how many times this was called"},
474 {"reccallcount", "how many times called recursively"},
475 {"totaltime", "total time in this entry"},
476 {"inlinetime", "inline time in this entry (not in subcalls)"},
477 {"calls", "details of the calls"},
478 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000479};
480
481static PyStructSequence_Field profiler_subentry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000482 {"code", "called code object or built-in function name"},
483 {"callcount", "how many times this is called"},
484 {"reccallcount", "how many times this is called recursively"},
485 {"totaltime", "total time spent in this call"},
486 {"inlinetime", "inline time (not in further subcalls)"},
487 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000488};
489
490static PyStructSequence_Desc profiler_entry_desc = {
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500491 .name = "_lsprof.profiler_entry",
492 .doc = "",
493 .fields = profiler_entry_fields,
494 .n_in_sequence = 6
Armin Rigoa871ef22006-02-08 12:53:56 +0000495};
496
497static PyStructSequence_Desc profiler_subentry_desc = {
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500498 .name = "_lsprof.profiler_subentry",
499 .doc = "",
500 .fields = profiler_subentry_fields,
501 .n_in_sequence = 5
Armin Rigoa871ef22006-02-08 12:53:56 +0000502};
503
Armin Rigoa871ef22006-02-08 12:53:56 +0000504typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000505 PyObject *list;
506 PyObject *sublist;
507 double factor;
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500508 _lsprof_state *state;
Armin Rigoa871ef22006-02-08 12:53:56 +0000509} statscollector_t;
510
511static int statsForSubEntry(rotating_node_t *node, void *arg)
512{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000513 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
514 statscollector_t *collect = (statscollector_t*) arg;
515 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
516 int err;
517 PyObject *sinfo;
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500518 sinfo = PyObject_CallFunction((PyObject*) collect->state->stats_subentry_type,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000519 "((Olldd))",
520 entry->userObj,
521 sentry->callcount,
522 sentry->recursivecallcount,
523 collect->factor * sentry->tt,
524 collect->factor * sentry->it);
525 if (sinfo == NULL)
526 return -1;
527 err = PyList_Append(collect->sublist, sinfo);
528 Py_DECREF(sinfo);
529 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000530}
531
532static int statsForEntry(rotating_node_t *node, void *arg)
533{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000534 ProfilerEntry *entry = (ProfilerEntry*) node;
535 statscollector_t *collect = (statscollector_t*) arg;
536 PyObject *info;
537 int err;
538 if (entry->callcount == 0)
539 return 0; /* skip */
Armin Rigoa871ef22006-02-08 12:53:56 +0000540
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000541 if (entry->calls != EMPTY_ROTATING_TREE) {
542 collect->sublist = PyList_New(0);
543 if (collect->sublist == NULL)
544 return -1;
545 if (RotatingTree_Enum(entry->calls,
546 statsForSubEntry, collect) != 0) {
547 Py_DECREF(collect->sublist);
548 return -1;
549 }
550 }
551 else {
552 Py_INCREF(Py_None);
553 collect->sublist = Py_None;
554 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000555
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500556 info = PyObject_CallFunction((PyObject*) collect->state->stats_entry_type,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000557 "((OllddO))",
558 entry->userObj,
559 entry->callcount,
560 entry->recursivecallcount,
561 collect->factor * entry->tt,
562 collect->factor * entry->it,
563 collect->sublist);
564 Py_DECREF(collect->sublist);
565 if (info == NULL)
566 return -1;
567 err = PyList_Append(collect->list, info);
568 Py_DECREF(info);
569 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000570}
571
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500572/*[clinic input]
573_lsprof.Profiler.getstats
Armin Rigoa871ef22006-02-08 12:53:56 +0000574
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500575 cls: defining_class
576
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500577list of profiler_entry objects.
578
579getstats() -> list of profiler_entry objects
580
581Return all information collected by the profiler.
582Each profiler_entry is a tuple-like object with the
583following attributes:
584
585 code code object
586 callcount how many times this was called
587 reccallcount how many times called recursively
588 totaltime total time in this entry
589 inlinetime inline time in this entry (not in subcalls)
590 calls details of the calls
591
592The calls attribute is either None or a list of
593profiler_subentry objects:
594
595 code called code object
596 callcount how many times this is called
597 reccallcount how many times this is called recursively
598 totaltime total time spent in this call
599 inlinetime inline time (not in further subcalls)
600[clinic start generated code]*/
601
602static PyObject *
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500603_lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls)
604/*[clinic end generated code: output=1806ef720019ee03 input=445e193ef4522902]*/
Armin Rigoa871ef22006-02-08 12:53:56 +0000605{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000606 statscollector_t collect;
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500607 collect.state = PyType_GetModuleState(cls);
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500608 if (pending_exception(self)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000609 return NULL;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100610 }
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500611 if (!self->externalTimer || self->externalTimerUnit == 0.0) {
Inada Naoki536a35b2019-04-11 19:11:46 +0900612 _PyTime_t onesec = _PyTime_FromSeconds(1);
613 collect.factor = (double)1 / onesec;
614 }
615 else {
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500616 collect.factor = self->externalTimerUnit;
Inada Naoki536a35b2019-04-11 19:11:46 +0900617 }
618
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000619 collect.list = PyList_New(0);
620 if (collect.list == NULL)
621 return NULL;
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500622 if (RotatingTree_Enum(self->profilerEntries, statsForEntry, &collect)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000623 != 0) {
624 Py_DECREF(collect.list);
625 return NULL;
626 }
627 return collect.list;
Armin Rigoa871ef22006-02-08 12:53:56 +0000628}
629
630static int
631setSubcalls(ProfilerObject *pObj, int nvalue)
632{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000633 if (nvalue == 0)
634 pObj->flags &= ~POF_SUBCALLS;
635 else if (nvalue > 0)
636 pObj->flags |= POF_SUBCALLS;
637 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000638}
639
640static int
641setBuiltins(ProfilerObject *pObj, int nvalue)
642{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000643 if (nvalue == 0)
644 pObj->flags &= ~POF_BUILTINS;
645 else if (nvalue > 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000646 pObj->flags |= POF_BUILTINS;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000647 }
648 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000649}
650
651PyDoc_STRVAR(enable_doc, "\
652enable(subcalls=True, builtins=True)\n\
653\n\
654Start collecting profiling information.\n\
655If 'subcalls' is True, also records for each function\n\
656statistics separated according to its current caller.\n\
657If 'builtins' is True, records the time spent in\n\
658built-in functions separately from their caller.\n\
659");
660
661static PyObject*
662profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
663{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000664 int subcalls = -1;
665 int builtins = -1;
666 static char *kwlist[] = {"subcalls", "builtins", 0};
667 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
668 kwlist, &subcalls, &builtins))
669 return NULL;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100670 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000671 return NULL;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100672 }
673
674 PyThreadState *tstate = PyThreadState_GET();
675 if (_PyEval_SetProfile(tstate, profiler_callback, (PyObject*)self) < 0) {
676 return NULL;
677 }
678
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000679 self->flags |= POF_ENABLED;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200680 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000681}
682
683static void
684flush_unmatched(ProfilerObject *pObj)
685{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000686 while (pObj->currentProfilerContext) {
687 ProfilerContext *pContext = pObj->currentProfilerContext;
688 ProfilerEntry *profEntry= pContext->ctxEntry;
689 if (profEntry)
690 Stop(pObj, pContext, profEntry);
691 else
692 pObj->currentProfilerContext = pContext->previous;
693 if (pContext)
Victor Stinnerb6404912013-07-07 16:21:41 +0200694 PyMem_Free(pContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000695 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000696
697}
698
699PyDoc_STRVAR(disable_doc, "\
700disable()\n\
701\n\
702Stop collecting profiling information.\n\
703");
704
705static PyObject*
706profiler_disable(ProfilerObject *self, PyObject* noarg)
707{
Victor Stinner309d7cc2020-03-13 16:39:12 +0100708 PyThreadState *tstate = PyThreadState_GET();
709 if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000710 return NULL;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100711 }
712 self->flags &= ~POF_ENABLED;
713
714 flush_unmatched(self);
715 if (pending_exception(self)) {
716 return NULL;
717 }
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200718 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000719}
720
721PyDoc_STRVAR(clear_doc, "\
722clear()\n\
723\n\
724Clear all profiling information collected so far.\n\
725");
726
727static PyObject*
728profiler_clear(ProfilerObject *pObj, PyObject* noarg)
729{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000730 clearEntries(pObj);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200731 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000732}
733
734static void
735profiler_dealloc(ProfilerObject *op)
736{
Victor Stinner309d7cc2020-03-13 16:39:12 +0100737 if (op->flags & POF_ENABLED) {
738 PyThreadState *tstate = PyThreadState_GET();
739 if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
740 PyErr_WriteUnraisable((PyObject *)op);
741 }
742 }
743
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000744 flush_unmatched(op);
745 clearEntries(op);
746 Py_XDECREF(op->externalTimer);
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500747 PyTypeObject *tp = Py_TYPE(op);
748 tp->tp_free(op);
749 Py_DECREF(tp);
Armin Rigoa871ef22006-02-08 12:53:56 +0000750}
751
752static int
753profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
754{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000755 PyObject *timer = NULL;
756 double timeunit = 0.0;
757 int subcalls = 1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000758 int builtins = 1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000759 static char *kwlist[] = {"timer", "timeunit",
760 "subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000761
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000762 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
763 &timer, &timeunit,
764 &subcalls, &builtins))
765 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000766
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000767 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
768 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000769 pObj->externalTimerUnit = timeunit;
Serhiy Storchaka576f1322016-01-05 21:27:54 +0200770 Py_XINCREF(timer);
Serhiy Storchakaec397562016-04-06 09:50:03 +0300771 Py_XSETREF(pObj->externalTimer, timer);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000772 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000773}
774
775static PyMethodDef profiler_methods[] = {
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500776 _LSPROF_PROFILER_GETSTATS_METHODDEF
Serhiy Storchaka62be7422018-11-27 13:27:31 +0200777 {"enable", (PyCFunction)(void(*)(void))profiler_enable,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000778 METH_VARARGS | METH_KEYWORDS, enable_doc},
779 {"disable", (PyCFunction)profiler_disable,
780 METH_NOARGS, disable_doc},
781 {"clear", (PyCFunction)profiler_clear,
782 METH_NOARGS, clear_doc},
783 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000784};
785
786PyDoc_STRVAR(profiler_doc, "\
INADA Naoki2ebd3812018-08-03 18:09:57 +0900787Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\
Armin Rigoa871ef22006-02-08 12:53:56 +0000788\n\
789 Builds a profiler object using the specified timer function.\n\
790 The default timer is a fast built-in one based on real time.\n\
INADA Naoki2ebd3812018-08-03 18:09:57 +0900791 For custom timer functions returning integers, timeunit can\n\
Armin Rigoa871ef22006-02-08 12:53:56 +0000792 be a float specifying a scale (i.e. how long each integer unit\n\
793 is, in seconds).\n\
794");
795
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500796static PyType_Slot _lsprof_profiler_type_spec_slots[] = {
797 {Py_tp_doc, (void *)profiler_doc},
798 {Py_tp_methods, profiler_methods},
799 {Py_tp_dealloc, profiler_dealloc},
800 {Py_tp_init, profiler_init},
801 {Py_tp_alloc, PyType_GenericAlloc},
802 {Py_tp_new, PyType_GenericNew},
803 {Py_tp_free, PyObject_Del},
804 {0, 0}
805};
806
807static PyType_Spec _lsprof_profiler_type_spec = {
808 .name = "_lsprof.Profiler",
809 .basicsize = sizeof(ProfilerObject),
810 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
811 .slots = _lsprof_profiler_type_spec_slots,
Armin Rigoa871ef22006-02-08 12:53:56 +0000812};
813
814static PyMethodDef moduleMethods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000815 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000816};
817
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500818static int
819_lsprof_traverse(PyObject *module, visitproc visit, void *arg)
820{
821 _lsprof_state *state = _lsprof_get_state(module);
822 Py_VISIT(state->profiler_type);
823 Py_VISIT(state->stats_entry_type);
824 Py_VISIT(state->stats_subentry_type);
825 return 0;
826}
827
828static int
829_lsprof_clear(PyObject *module)
830{
831 _lsprof_state *state = _lsprof_get_state(module);
832 Py_CLEAR(state->profiler_type);
833 Py_CLEAR(state->stats_entry_type);
834 Py_CLEAR(state->stats_subentry_type);
835 return 0;
836}
837
838static void
839_lsprof_free(void *module)
840{
841 _lsprof_clear((PyObject *)module);
842}
843
844static int
845_lsprof_exec(PyObject *module)
846{
847 _lsprof_state *state = PyModule_GetState(module);
848
849 state->profiler_type = (PyTypeObject *)PyType_FromModuleAndSpec(
850 module, &_lsprof_profiler_type_spec, NULL);
851 if (state->profiler_type == NULL) {
852 return -1;
853 }
854
855 if (PyModule_AddType(module, state->profiler_type) < 0) {
856 return -1;
857 }
858
859 state->stats_entry_type = PyStructSequence_NewType(&profiler_entry_desc);
860 if (state->stats_entry_type == NULL) {
861 return -1;
862 }
863 if (PyModule_AddType(module, state->stats_entry_type) < 0) {
864 return -1;
865 }
866
867 state->stats_subentry_type = PyStructSequence_NewType(&profiler_subentry_desc);
868 if (state->stats_subentry_type == NULL) {
869 return -1;
870 }
871 if (PyModule_AddType(module, state->stats_subentry_type) < 0) {
872 return -1;
873 }
874
875 return 0;
876}
877
878static PyModuleDef_Slot _lsprofslots[] = {
879 {Py_mod_exec, _lsprof_exec},
880 {0, NULL}
881};
Martin v. Löwis1a214512008-06-11 05:26:20 +0000882
883static struct PyModuleDef _lsprofmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000884 PyModuleDef_HEAD_INIT,
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500885 .m_name = "_lsprof",
886 .m_doc = "Fast profiler",
887 .m_size = sizeof(_lsprof_state),
888 .m_methods = moduleMethods,
889 .m_slots = _lsprofslots,
890 .m_traverse = _lsprof_traverse,
891 .m_clear = _lsprof_clear,
892 .m_free = _lsprof_free
Martin v. Löwis1a214512008-06-11 05:26:20 +0000893};
894
Armin Rigoa871ef22006-02-08 12:53:56 +0000895PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000896PyInit__lsprof(void)
Armin Rigoa871ef22006-02-08 12:53:56 +0000897{
Mohamed Koubaa83de1102020-09-23 05:33:21 -0500898 return PyModuleDef_Init(&_lsprofmodule);
Armin Rigoa871ef22006-02-08 12:53:56 +0000899}