blob: a4ba7d523003381e99bf249ce50bb8fb626551d9 [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]*/
Neal Norwitz227b5332006-03-22 09:28:35 +000058static PyTypeObject PyProfiler_Type;
Armin Rigoa871ef22006-02-08 12:53:56 +000059
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -050060#include "clinic/_lsprof.c.h"
61
Armin Rigoa871ef22006-02-08 12:53:56 +000062#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
Dong-hee Na1b55b652020-02-17 19:09:15 +090063#define PyProfiler_CheckExact(op) Py_IS_TYPE(op, &PyProfiler_Type)
Armin Rigoa871ef22006-02-08 12:53:56 +000064
65/*** External Timers ***/
66
Inada Naoki536a35b2019-04-11 19:11:46 +090067static _PyTime_t CallExternalTimer(ProfilerObject *pObj)
Armin Rigoa871ef22006-02-08 12:53:56 +000068{
Inada Naoki536a35b2019-04-11 19:11:46 +090069 PyObject *o = _PyObject_CallNoArg(pObj->externalTimer);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000070 if (o == NULL) {
71 PyErr_WriteUnraisable(pObj->externalTimer);
72 return 0;
73 }
Inada Naoki536a35b2019-04-11 19:11:46 +090074
75 _PyTime_t result;
76 int err;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000077 if (pObj->externalTimerUnit > 0.0) {
78 /* interpret the result as an integer that will be scaled
79 in profiler_getstats() */
Inada Naoki536a35b2019-04-11 19:11:46 +090080 err = _PyTime_FromNanosecondsObject(&result, o);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000081 }
82 else {
83 /* interpret the result as a double measured in seconds.
Inada Naoki536a35b2019-04-11 19:11:46 +090084 As the profiler works with _PyTime_t internally
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000085 we convert it to a large integer */
Inada Naoki536a35b2019-04-11 19:11:46 +090086 err = _PyTime_FromSecondsObject(&result, o, _PyTime_ROUND_FLOOR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000087 }
88 Py_DECREF(o);
Inada Naoki536a35b2019-04-11 19:11:46 +090089 if (err < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000090 PyErr_WriteUnraisable(pObj->externalTimer);
91 return 0;
92 }
93 return result;
Armin Rigoa871ef22006-02-08 12:53:56 +000094}
95
Inada Naoki536a35b2019-04-11 19:11:46 +090096static inline _PyTime_t
97call_timer(ProfilerObject *pObj)
98{
99 if (pObj->externalTimer != NULL) {
100 return CallExternalTimer(pObj);
101 }
102 else {
103 return _PyTime_GetPerfCounter();
104 }
105}
106
Armin Rigoa871ef22006-02-08 12:53:56 +0000107
108/*** ProfilerObject ***/
109
110static PyObject *
111normalizeUserObj(PyObject *obj)
112{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000113 PyCFunctionObject *fn;
114 if (!PyCFunction_Check(obj)) {
115 Py_INCREF(obj);
116 return obj;
117 }
118 /* Replace built-in function objects with a descriptive string
119 because of built-in methods -- keeping a reference to
120 __self__ is probably not a good idea. */
121 fn = (PyCFunctionObject *)obj;
Armin Rigoa871ef22006-02-08 12:53:56 +0000122
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000123 if (fn->m_self == NULL) {
124 /* built-in function: look up the module name */
125 PyObject *mod = fn->m_module;
Victor Stinner7edb5df2011-06-20 14:59:53 +0200126 PyObject *modname = NULL;
127 if (mod != NULL) {
128 if (PyUnicode_Check(mod)) {
129 modname = mod;
130 Py_INCREF(modname);
131 }
132 else if (PyModule_Check(mod)) {
133 modname = PyModule_GetNameObject(mod);
134 if (modname == NULL)
135 PyErr_Clear();
Alexander Belopolskye239d232010-12-08 23:31:48 +0000136 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000137 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200138 if (modname != NULL) {
Serhiy Storchakaf4934ea2016-11-16 10:17:58 +0200139 if (!_PyUnicode_EqualToASCIIString(modname, "builtins")) {
Victor Stinner7edb5df2011-06-20 14:59:53 +0200140 PyObject *result;
141 result = PyUnicode_FromFormat("<%U.%s>", modname,
142 fn->m_ml->ml_name);
143 Py_DECREF(modname);
144 return result;
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000145 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200146 Py_DECREF(modname);
Alexander Belopolsky532d0912010-12-10 18:14:16 +0000147 }
Victor Stinner7edb5df2011-06-20 14:59:53 +0200148 return PyUnicode_FromFormat("<%s>", fn->m_ml->ml_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000149 }
150 else {
151 /* built-in method: try to return
152 repr(getattr(type(__self__), __name__))
153 */
154 PyObject *self = fn->m_self;
155 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400156 PyObject *modname = fn->m_module;
157
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158 if (name != NULL) {
159 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
160 Py_XINCREF(mo);
161 Py_DECREF(name);
162 if (mo != NULL) {
163 PyObject *res = PyObject_Repr(mo);
164 Py_DECREF(mo);
165 if (res != NULL)
166 return res;
167 }
168 }
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400169 /* Otherwise, use __module__ */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000170 PyErr_Clear();
Antoine Pitrou8477f7a2014-06-27 23:49:29 -0400171 if (modname != NULL && PyUnicode_Check(modname))
172 return PyUnicode_FromFormat("<built-in method %S.%s>",
173 modname, fn->m_ml->ml_name);
174 else
175 return PyUnicode_FromFormat("<built-in method %s>",
176 fn->m_ml->ml_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000177 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000178}
179
180static ProfilerEntry*
181newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
182{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000183 ProfilerEntry *self;
Victor Stinnerb6404912013-07-07 16:21:41 +0200184 self = (ProfilerEntry*) PyMem_Malloc(sizeof(ProfilerEntry));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000185 if (self == NULL) {
186 pObj->flags |= POF_NOMEMORY;
187 return NULL;
188 }
189 userObj = normalizeUserObj(userObj);
190 if (userObj == NULL) {
191 PyErr_Clear();
Victor Stinnerb6404912013-07-07 16:21:41 +0200192 PyMem_Free(self);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000193 pObj->flags |= POF_NOMEMORY;
194 return NULL;
195 }
196 self->header.key = key;
197 self->userObj = userObj;
198 self->tt = 0;
199 self->it = 0;
200 self->callcount = 0;
201 self->recursivecallcount = 0;
202 self->recursionLevel = 0;
203 self->calls = EMPTY_ROTATING_TREE;
204 RotatingTree_Add(&pObj->profilerEntries, &self->header);
205 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000206}
207
208static ProfilerEntry*
209getEntry(ProfilerObject *pObj, void *key)
210{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000211 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
Armin Rigoa871ef22006-02-08 12:53:56 +0000212}
213
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000214static ProfilerSubEntry *
Armin Rigoa871ef22006-02-08 12:53:56 +0000215getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
216{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000217 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
218 (void *)entry);
Armin Rigoa871ef22006-02-08 12:53:56 +0000219}
220
221static ProfilerSubEntry *
222newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
223{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000224 ProfilerSubEntry *self;
Victor Stinnerb6404912013-07-07 16:21:41 +0200225 self = (ProfilerSubEntry*) PyMem_Malloc(sizeof(ProfilerSubEntry));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000226 if (self == NULL) {
227 pObj->flags |= POF_NOMEMORY;
228 return NULL;
229 }
230 self->header.key = (void *)entry;
231 self->tt = 0;
232 self->it = 0;
233 self->callcount = 0;
234 self->recursivecallcount = 0;
235 self->recursionLevel = 0;
236 RotatingTree_Add(&caller->calls, &self->header);
237 return self;
Armin Rigoa871ef22006-02-08 12:53:56 +0000238}
239
240static int freeSubEntry(rotating_node_t *header, void *arg)
241{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000242 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
Victor Stinnerb6404912013-07-07 16:21:41 +0200243 PyMem_Free(subentry);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000244 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000245}
246
247static int freeEntry(rotating_node_t *header, void *arg)
248{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000249 ProfilerEntry *entry = (ProfilerEntry*) header;
250 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
251 Py_DECREF(entry->userObj);
Victor Stinnerb6404912013-07-07 16:21:41 +0200252 PyMem_Free(entry);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000253 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000254}
255
256static void clearEntries(ProfilerObject *pObj)
257{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000258 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
259 pObj->profilerEntries = EMPTY_ROTATING_TREE;
260 /* release the memory hold by the ProfilerContexts */
261 if (pObj->currentProfilerContext) {
Victor Stinnerb6404912013-07-07 16:21:41 +0200262 PyMem_Free(pObj->currentProfilerContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 pObj->currentProfilerContext = NULL;
264 }
265 while (pObj->freelistProfilerContext) {
266 ProfilerContext *c = pObj->freelistProfilerContext;
267 pObj->freelistProfilerContext = c->previous;
Victor Stinnerb6404912013-07-07 16:21:41 +0200268 PyMem_Free(c);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000269 }
270 pObj->freelistProfilerContext = NULL;
Armin Rigoa871ef22006-02-08 12:53:56 +0000271}
272
273static void
274initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
275{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000276 self->ctxEntry = entry;
277 self->subt = 0;
278 self->previous = pObj->currentProfilerContext;
279 pObj->currentProfilerContext = self;
280 ++entry->recursionLevel;
281 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
282 /* find or create an entry for me in my caller's entry */
283 ProfilerEntry *caller = self->previous->ctxEntry;
284 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
285 if (subentry == NULL)
286 subentry = newSubEntry(pObj, caller, entry);
287 if (subentry)
288 ++subentry->recursionLevel;
289 }
Inada Naoki536a35b2019-04-11 19:11:46 +0900290 self->t0 = call_timer(pObj);
Armin Rigoa871ef22006-02-08 12:53:56 +0000291}
292
293static void
294Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
295{
Inada Naoki536a35b2019-04-11 19:11:46 +0900296 _PyTime_t tt = call_timer(pObj) - self->t0;
297 _PyTime_t it = tt - self->subt;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 if (self->previous)
299 self->previous->subt += tt;
300 pObj->currentProfilerContext = self->previous;
301 if (--entry->recursionLevel == 0)
302 entry->tt += tt;
303 else
304 ++entry->recursivecallcount;
305 entry->it += it;
306 entry->callcount++;
307 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
308 /* find or create an entry for me in my caller's entry */
309 ProfilerEntry *caller = self->previous->ctxEntry;
310 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
311 if (subentry) {
312 if (--subentry->recursionLevel == 0)
313 subentry->tt += tt;
314 else
315 ++subentry->recursivecallcount;
316 subentry->it += it;
317 ++subentry->callcount;
318 }
319 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000320}
321
322static void
323ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
324{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 /* entering a call to the function identified by 'key'
326 (which can be a PyCodeObject or a PyMethodDef pointer) */
327 ProfilerObject *pObj = (ProfilerObject*)self;
328 ProfilerEntry *profEntry;
329 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000330
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000331 /* In the case of entering a generator expression frame via a
332 * throw (gen_send_ex(.., 1)), we may already have an
333 * Exception set here. We must not mess around with this
334 * exception, and some of the code under here assumes that
335 * PyErr_* is its own to mess around with, so we have to
336 * save and restore any current exception. */
337 PyObject *last_type, *last_value, *last_tb;
338 PyErr_Fetch(&last_type, &last_value, &last_tb);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000339
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000340 profEntry = getEntry(pObj, key);
341 if (profEntry == NULL) {
342 profEntry = newProfilerEntry(pObj, key, userObj);
343 if (profEntry == NULL)
344 goto restorePyerr;
345 }
346 /* grab a ProfilerContext out of the free list */
347 pContext = pObj->freelistProfilerContext;
348 if (pContext) {
349 pObj->freelistProfilerContext = pContext->previous;
350 }
351 else {
352 /* free list exhausted, allocate a new one */
353 pContext = (ProfilerContext*)
Victor Stinnerb6404912013-07-07 16:21:41 +0200354 PyMem_Malloc(sizeof(ProfilerContext));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000355 if (pContext == NULL) {
356 pObj->flags |= POF_NOMEMORY;
357 goto restorePyerr;
358 }
359 }
360 initContext(pObj, pContext, profEntry);
Thomas Wouters89d996e2007-09-08 17:39:28 +0000361
362restorePyerr:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000363 PyErr_Restore(last_type, last_value, last_tb);
Armin Rigoa871ef22006-02-08 12:53:56 +0000364}
365
366static void
367ptrace_leave_call(PyObject *self, void *key)
368{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000369 /* leaving a call to the function identified by 'key' */
370 ProfilerObject *pObj = (ProfilerObject*)self;
371 ProfilerEntry *profEntry;
372 ProfilerContext *pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000373
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000374 pContext = pObj->currentProfilerContext;
375 if (pContext == NULL)
376 return;
377 profEntry = getEntry(pObj, key);
378 if (profEntry) {
379 Stop(pObj, pContext, profEntry);
380 }
381 else {
382 pObj->currentProfilerContext = pContext->previous;
383 }
384 /* put pContext into the free list */
385 pContext->previous = pObj->freelistProfilerContext;
386 pObj->freelistProfilerContext = pContext;
Armin Rigoa871ef22006-02-08 12:53:56 +0000387}
388
389static int
390profiler_callback(PyObject *self, PyFrameObject *frame, int what,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000391 PyObject *arg)
Armin Rigoa871ef22006-02-08 12:53:56 +0000392{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000393 switch (what) {
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 start its execution */
396 case PyTrace_CALL:
Victor Stinnera42ca742020-04-28 19:01:31 +0200397 {
398 PyCodeObject *code = PyFrame_GetCode(frame);
399 ptrace_enter_call(self, (void *)code, (PyObject *)code);
Victor Stinner8852ad42020-04-29 01:28:13 +0200400 Py_DECREF(code);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000401 break;
Victor Stinnera42ca742020-04-28 19:01:31 +0200402 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000403
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000404 /* the 'frame' of a called function is about to finish
405 (either normally or with an exception) */
406 case PyTrace_RETURN:
Victor Stinner8852ad42020-04-29 01:28:13 +0200407 {
408 PyCodeObject *code = PyFrame_GetCode(frame);
409 ptrace_leave_call(self, (void *)code);
410 Py_DECREF(code);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000411 break;
Victor Stinner8852ad42020-04-29 01:28:13 +0200412 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000413
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000414 /* case PyTrace_EXCEPTION:
415 If the exception results in the function exiting, a
416 PyTrace_RETURN event will be generated, so we don't need to
417 handle it. */
Armin Rigoa871ef22006-02-08 12:53:56 +0000418
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000419 /* the Python function 'frame' is issuing a call to the built-in
420 function 'arg' */
421 case PyTrace_C_CALL:
422 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
423 && PyCFunction_Check(arg)) {
424 ptrace_enter_call(self,
425 ((PyCFunctionObject *)arg)->m_ml,
426 arg);
427 }
428 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000429
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000430 /* the call to the built-in function 'arg' is returning into its
431 caller 'frame' */
432 case PyTrace_C_RETURN: /* ...normally */
433 case PyTrace_C_EXCEPTION: /* ...with an exception set */
434 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
435 && PyCFunction_Check(arg)) {
436 ptrace_leave_call(self,
437 ((PyCFunctionObject *)arg)->m_ml);
438 }
439 break;
Armin Rigoa871ef22006-02-08 12:53:56 +0000440
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000441 default:
442 break;
443 }
444 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000445}
446
447static int
448pending_exception(ProfilerObject *pObj)
449{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000450 if (pObj->flags & POF_NOMEMORY) {
451 pObj->flags -= POF_NOMEMORY;
452 PyErr_SetString(PyExc_MemoryError,
453 "memory was exhausted while profiling");
454 return -1;
455 }
456 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000457}
458
459/************************************************************/
460
461static PyStructSequence_Field profiler_entry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000462 {"code", "code object or built-in function name"},
463 {"callcount", "how many times this was called"},
464 {"reccallcount", "how many times called recursively"},
465 {"totaltime", "total time in this entry"},
466 {"inlinetime", "inline time in this entry (not in subcalls)"},
467 {"calls", "details of the calls"},
468 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000469};
470
471static PyStructSequence_Field profiler_subentry_fields[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000472 {"code", "called code object or built-in function name"},
473 {"callcount", "how many times this is called"},
474 {"reccallcount", "how many times this is called recursively"},
475 {"totaltime", "total time spent in this call"},
476 {"inlinetime", "inline time (not in further subcalls)"},
477 {0}
Armin Rigoa871ef22006-02-08 12:53:56 +0000478};
479
480static PyStructSequence_Desc profiler_entry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000481 "_lsprof.profiler_entry", /* name */
482 NULL, /* doc */
483 profiler_entry_fields,
484 6
Armin Rigoa871ef22006-02-08 12:53:56 +0000485};
486
487static PyStructSequence_Desc profiler_subentry_desc = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000488 "_lsprof.profiler_subentry", /* name */
489 NULL, /* doc */
490 profiler_subentry_fields,
491 5
Armin Rigoa871ef22006-02-08 12:53:56 +0000492};
493
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000494static int initialized;
Armin Rigoa871ef22006-02-08 12:53:56 +0000495static PyTypeObject StatsEntryType;
496static PyTypeObject StatsSubEntryType;
497
498
499typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000500 PyObject *list;
501 PyObject *sublist;
502 double factor;
Armin Rigoa871ef22006-02-08 12:53:56 +0000503} statscollector_t;
504
505static int statsForSubEntry(rotating_node_t *node, void *arg)
506{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000507 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
508 statscollector_t *collect = (statscollector_t*) arg;
509 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
510 int err;
511 PyObject *sinfo;
512 sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
513 "((Olldd))",
514 entry->userObj,
515 sentry->callcount,
516 sentry->recursivecallcount,
517 collect->factor * sentry->tt,
518 collect->factor * sentry->it);
519 if (sinfo == NULL)
520 return -1;
521 err = PyList_Append(collect->sublist, sinfo);
522 Py_DECREF(sinfo);
523 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000524}
525
526static int statsForEntry(rotating_node_t *node, void *arg)
527{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000528 ProfilerEntry *entry = (ProfilerEntry*) node;
529 statscollector_t *collect = (statscollector_t*) arg;
530 PyObject *info;
531 int err;
532 if (entry->callcount == 0)
533 return 0; /* skip */
Armin Rigoa871ef22006-02-08 12:53:56 +0000534
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000535 if (entry->calls != EMPTY_ROTATING_TREE) {
536 collect->sublist = PyList_New(0);
537 if (collect->sublist == NULL)
538 return -1;
539 if (RotatingTree_Enum(entry->calls,
540 statsForSubEntry, collect) != 0) {
541 Py_DECREF(collect->sublist);
542 return -1;
543 }
544 }
545 else {
546 Py_INCREF(Py_None);
547 collect->sublist = Py_None;
548 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000549
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000550 info = PyObject_CallFunction((PyObject*) &StatsEntryType,
551 "((OllddO))",
552 entry->userObj,
553 entry->callcount,
554 entry->recursivecallcount,
555 collect->factor * entry->tt,
556 collect->factor * entry->it,
557 collect->sublist);
558 Py_DECREF(collect->sublist);
559 if (info == NULL)
560 return -1;
561 err = PyList_Append(collect->list, info);
562 Py_DECREF(info);
563 return err;
Armin Rigoa871ef22006-02-08 12:53:56 +0000564}
565
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500566/*[clinic input]
567_lsprof.Profiler.getstats
Armin Rigoa871ef22006-02-08 12:53:56 +0000568
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500569list of profiler_entry objects.
570
571getstats() -> list of profiler_entry objects
572
573Return all information collected by the profiler.
574Each profiler_entry is a tuple-like object with the
575following attributes:
576
577 code code object
578 callcount how many times this was called
579 reccallcount how many times called recursively
580 totaltime total time in this entry
581 inlinetime inline time in this entry (not in subcalls)
582 calls details of the calls
583
584The calls attribute is either None or a list of
585profiler_subentry objects:
586
587 code called code object
588 callcount how many times this is called
589 reccallcount how many times this is called recursively
590 totaltime total time spent in this call
591 inlinetime inline time (not in further subcalls)
592[clinic start generated code]*/
593
594static PyObject *
595_lsprof_Profiler_getstats_impl(ProfilerObject *self)
596/*[clinic end generated code: output=9461b451e9ef0f24 input=ade04fa384ce450a]*/
Armin Rigoa871ef22006-02-08 12:53:56 +0000597{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000598 statscollector_t collect;
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500599 if (pending_exception(self)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000600 return NULL;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100601 }
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500602 if (!self->externalTimer || self->externalTimerUnit == 0.0) {
Inada Naoki536a35b2019-04-11 19:11:46 +0900603 _PyTime_t onesec = _PyTime_FromSeconds(1);
604 collect.factor = (double)1 / onesec;
605 }
606 else {
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500607 collect.factor = self->externalTimerUnit;
Inada Naoki536a35b2019-04-11 19:11:46 +0900608 }
609
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000610 collect.list = PyList_New(0);
611 if (collect.list == NULL)
612 return NULL;
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500613 if (RotatingTree_Enum(self->profilerEntries, statsForEntry, &collect)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000614 != 0) {
615 Py_DECREF(collect.list);
616 return NULL;
617 }
618 return collect.list;
Armin Rigoa871ef22006-02-08 12:53:56 +0000619}
620
621static int
622setSubcalls(ProfilerObject *pObj, int nvalue)
623{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000624 if (nvalue == 0)
625 pObj->flags &= ~POF_SUBCALLS;
626 else if (nvalue > 0)
627 pObj->flags |= POF_SUBCALLS;
628 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000629}
630
631static int
632setBuiltins(ProfilerObject *pObj, int nvalue)
633{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000634 if (nvalue == 0)
635 pObj->flags &= ~POF_BUILTINS;
636 else if (nvalue > 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000637 pObj->flags |= POF_BUILTINS;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000638 }
639 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000640}
641
642PyDoc_STRVAR(enable_doc, "\
643enable(subcalls=True, builtins=True)\n\
644\n\
645Start collecting profiling information.\n\
646If 'subcalls' is True, also records for each function\n\
647statistics separated according to its current caller.\n\
648If 'builtins' is True, records the time spent in\n\
649built-in functions separately from their caller.\n\
650");
651
652static PyObject*
653profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
654{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000655 int subcalls = -1;
656 int builtins = -1;
657 static char *kwlist[] = {"subcalls", "builtins", 0};
658 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
659 kwlist, &subcalls, &builtins))
660 return NULL;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100661 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000662 return NULL;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100663 }
664
665 PyThreadState *tstate = PyThreadState_GET();
666 if (_PyEval_SetProfile(tstate, profiler_callback, (PyObject*)self) < 0) {
667 return NULL;
668 }
669
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000670 self->flags |= POF_ENABLED;
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200671 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000672}
673
674static void
675flush_unmatched(ProfilerObject *pObj)
676{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000677 while (pObj->currentProfilerContext) {
678 ProfilerContext *pContext = pObj->currentProfilerContext;
679 ProfilerEntry *profEntry= pContext->ctxEntry;
680 if (profEntry)
681 Stop(pObj, pContext, profEntry);
682 else
683 pObj->currentProfilerContext = pContext->previous;
684 if (pContext)
Victor Stinnerb6404912013-07-07 16:21:41 +0200685 PyMem_Free(pContext);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000686 }
Armin Rigoa871ef22006-02-08 12:53:56 +0000687
688}
689
690PyDoc_STRVAR(disable_doc, "\
691disable()\n\
692\n\
693Stop collecting profiling information.\n\
694");
695
696static PyObject*
697profiler_disable(ProfilerObject *self, PyObject* noarg)
698{
Victor Stinner309d7cc2020-03-13 16:39:12 +0100699 PyThreadState *tstate = PyThreadState_GET();
700 if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000701 return NULL;
Victor Stinner309d7cc2020-03-13 16:39:12 +0100702 }
703 self->flags &= ~POF_ENABLED;
704
705 flush_unmatched(self);
706 if (pending_exception(self)) {
707 return NULL;
708 }
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200709 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000710}
711
712PyDoc_STRVAR(clear_doc, "\
713clear()\n\
714\n\
715Clear all profiling information collected so far.\n\
716");
717
718static PyObject*
719profiler_clear(ProfilerObject *pObj, PyObject* noarg)
720{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000721 clearEntries(pObj);
Serhiy Storchaka228b12e2017-01-23 09:47:21 +0200722 Py_RETURN_NONE;
Armin Rigoa871ef22006-02-08 12:53:56 +0000723}
724
725static void
726profiler_dealloc(ProfilerObject *op)
727{
Victor Stinner309d7cc2020-03-13 16:39:12 +0100728 if (op->flags & POF_ENABLED) {
729 PyThreadState *tstate = PyThreadState_GET();
730 if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
731 PyErr_WriteUnraisable((PyObject *)op);
732 }
733 }
734
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000735 flush_unmatched(op);
736 clearEntries(op);
737 Py_XDECREF(op->externalTimer);
738 Py_TYPE(op)->tp_free(op);
Armin Rigoa871ef22006-02-08 12:53:56 +0000739}
740
741static int
742profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
743{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000744 PyObject *timer = NULL;
745 double timeunit = 0.0;
746 int subcalls = 1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000747 int builtins = 1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000748 static char *kwlist[] = {"timer", "timeunit",
749 "subcalls", "builtins", 0};
Armin Rigoa871ef22006-02-08 12:53:56 +0000750
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000751 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
752 &timer, &timeunit,
753 &subcalls, &builtins))
754 return -1;
Armin Rigoa871ef22006-02-08 12:53:56 +0000755
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000756 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
757 return -1;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000758 pObj->externalTimerUnit = timeunit;
Serhiy Storchaka576f1322016-01-05 21:27:54 +0200759 Py_XINCREF(timer);
Serhiy Storchakaec397562016-04-06 09:50:03 +0300760 Py_XSETREF(pObj->externalTimer, timer);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000761 return 0;
Armin Rigoa871ef22006-02-08 12:53:56 +0000762}
763
764static PyMethodDef profiler_methods[] = {
Mohamed Koubaa1b328ea2020-09-21 07:40:42 -0500765 _LSPROF_PROFILER_GETSTATS_METHODDEF
Serhiy Storchaka62be7422018-11-27 13:27:31 +0200766 {"enable", (PyCFunction)(void(*)(void))profiler_enable,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000767 METH_VARARGS | METH_KEYWORDS, enable_doc},
768 {"disable", (PyCFunction)profiler_disable,
769 METH_NOARGS, disable_doc},
770 {"clear", (PyCFunction)profiler_clear,
771 METH_NOARGS, clear_doc},
772 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000773};
774
775PyDoc_STRVAR(profiler_doc, "\
INADA Naoki2ebd3812018-08-03 18:09:57 +0900776Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\
Armin Rigoa871ef22006-02-08 12:53:56 +0000777\n\
778 Builds a profiler object using the specified timer function.\n\
779 The default timer is a fast built-in one based on real time.\n\
INADA Naoki2ebd3812018-08-03 18:09:57 +0900780 For custom timer functions returning integers, timeunit can\n\
Armin Rigoa871ef22006-02-08 12:53:56 +0000781 be a float specifying a scale (i.e. how long each integer unit\n\
782 is, in seconds).\n\
783");
784
Neal Norwitz227b5332006-03-22 09:28:35 +0000785static PyTypeObject PyProfiler_Type = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000786 PyVarObject_HEAD_INIT(NULL, 0)
787 "_lsprof.Profiler", /* tp_name */
788 sizeof(ProfilerObject), /* tp_basicsize */
789 0, /* tp_itemsize */
790 (destructor)profiler_dealloc, /* tp_dealloc */
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200791 0, /* tp_vectorcall_offset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000792 0, /* tp_getattr */
793 0, /* tp_setattr */
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200794 0, /* tp_as_async */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000795 0, /* tp_repr */
796 0, /* tp_as_number */
797 0, /* tp_as_sequence */
798 0, /* tp_as_mapping */
799 0, /* tp_hash */
800 0, /* tp_call */
801 0, /* tp_str */
802 0, /* tp_getattro */
803 0, /* tp_setattro */
804 0, /* tp_as_buffer */
805 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
806 profiler_doc, /* tp_doc */
807 0, /* tp_traverse */
808 0, /* tp_clear */
809 0, /* tp_richcompare */
810 0, /* tp_weaklistoffset */
811 0, /* tp_iter */
812 0, /* tp_iternext */
813 profiler_methods, /* tp_methods */
814 0, /* tp_members */
815 0, /* tp_getset */
816 0, /* tp_base */
817 0, /* tp_dict */
818 0, /* tp_descr_get */
819 0, /* tp_descr_set */
820 0, /* tp_dictoffset */
821 (initproc)profiler_init, /* tp_init */
822 PyType_GenericAlloc, /* tp_alloc */
823 PyType_GenericNew, /* tp_new */
824 PyObject_Del, /* tp_free */
Armin Rigoa871ef22006-02-08 12:53:56 +0000825};
826
827static PyMethodDef moduleMethods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000828 {NULL, NULL}
Armin Rigoa871ef22006-02-08 12:53:56 +0000829};
830
Martin v. Löwis1a214512008-06-11 05:26:20 +0000831
832static struct PyModuleDef _lsprofmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000833 PyModuleDef_HEAD_INIT,
834 "_lsprof",
835 "Fast profiler",
836 -1,
837 moduleMethods,
838 NULL,
839 NULL,
840 NULL,
841 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000842};
843
Armin Rigoa871ef22006-02-08 12:53:56 +0000844PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000845PyInit__lsprof(void)
Armin Rigoa871ef22006-02-08 12:53:56 +0000846{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000847 PyObject *module, *d;
848 module = PyModule_Create(&_lsprofmodule);
849 if (module == NULL)
850 return NULL;
851 d = PyModule_GetDict(module);
852 if (PyType_Ready(&PyProfiler_Type) < 0)
853 return NULL;
854 PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
Armin Rigoa871ef22006-02-08 12:53:56 +0000855
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000856 if (!initialized) {
Victor Stinner1c8f0592013-07-22 22:24:54 +0200857 if (PyStructSequence_InitType2(&StatsEntryType,
858 &profiler_entry_desc) < 0)
859 return NULL;
860 if (PyStructSequence_InitType2(&StatsSubEntryType,
861 &profiler_subentry_desc) < 0)
862 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000863 }
864 Py_INCREF((PyObject*) &StatsEntryType);
865 Py_INCREF((PyObject*) &StatsSubEntryType);
866 PyModule_AddObject(module, "profiler_entry",
867 (PyObject*) &StatsEntryType);
868 PyModule_AddObject(module, "profiler_subentry",
869 (PyObject*) &StatsSubEntryType);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000870 initialized = 1;
871 return module;
Armin Rigoa871ef22006-02-08 12:53:56 +0000872}