1 #ifndef Py_BUILD_CORE_BUILTIN
2 # define Py_BUILD_CORE_MODULE 1
3 #endif
4
5 #include "Python.h"
6 #include "pycore_call.h" // _PyObject_CallNoArgs()
7 #include "pycore_pystate.h" // _PyThreadState_GET()
8 #include "rotatingtree.h"
9
10 /************************************************************/
11 /* Written by Brett Rosen and Ted Czotter */
12
13 struct _ProfilerEntry;
14
15 /* represents a function called from another function */
16 typedef struct _ProfilerSubEntry {
17 rotating_node_t header;
18 _PyTime_t tt;
19 _PyTime_t it;
20 long callcount;
21 long recursivecallcount;
22 long recursionLevel;
23 } ProfilerSubEntry;
24
25 /* represents a function or user defined block */
26 typedef struct _ProfilerEntry {
27 rotating_node_t header;
28 PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
29 _PyTime_t tt; /* total time in this entry */
30 _PyTime_t it; /* inline time in this entry (not in subcalls) */
31 long callcount; /* how many times this was called */
32 long recursivecallcount; /* how many times called recursively */
33 long recursionLevel;
34 rotating_node_t *calls;
35 } ProfilerEntry;
36
37 typedef struct _ProfilerContext {
38 _PyTime_t t0;
39 _PyTime_t subt;
40 struct _ProfilerContext *previous;
41 ProfilerEntry *ctxEntry;
42 } ProfilerContext;
43
44 typedef struct {
45 PyObject_HEAD
46 rotating_node_t *profilerEntries;
47 ProfilerContext *currentProfilerContext;
48 ProfilerContext *freelistProfilerContext;
49 int flags;
50 PyObject *externalTimer;
51 double externalTimerUnit;
52 } ProfilerObject;
53
54 #define POF_ENABLED 0x001
55 #define POF_SUBCALLS 0x002
56 #define POF_BUILTINS 0x004
57 #define POF_NOMEMORY 0x100
58
59 /*[clinic input]
60 module _lsprof
61 class _lsprof.Profiler "ProfilerObject *" "&ProfilerType"
62 [clinic start generated code]*/
63 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e349ac952152f336]*/
64
65 #include "clinic/_lsprof.c.h"
66
67 typedef struct {
68 PyTypeObject *profiler_type;
69 PyTypeObject *stats_entry_type;
70 PyTypeObject *stats_subentry_type;
71 } _lsprof_state;
72
73 static inline _lsprof_state*
_lsprof_get_state(PyObject * module)74 _lsprof_get_state(PyObject *module)
75 {
76 void *state = PyModule_GetState(module);
77 assert(state != NULL);
78 return (_lsprof_state *)state;
79 }
80
81 /*** External Timers ***/
82
CallExternalTimer(ProfilerObject * pObj)83 static _PyTime_t CallExternalTimer(ProfilerObject *pObj)
84 {
85 PyObject *o = _PyObject_CallNoArgs(pObj->externalTimer);
86 if (o == NULL) {
87 PyErr_WriteUnraisable(pObj->externalTimer);
88 return 0;
89 }
90
91 _PyTime_t result;
92 int err;
93 if (pObj->externalTimerUnit > 0.0) {
94 /* interpret the result as an integer that will be scaled
95 in profiler_getstats() */
96 err = _PyTime_FromNanosecondsObject(&result, o);
97 }
98 else {
99 /* interpret the result as a double measured in seconds.
100 As the profiler works with _PyTime_t internally
101 we convert it to a large integer */
102 err = _PyTime_FromSecondsObject(&result, o, _PyTime_ROUND_FLOOR);
103 }
104 Py_DECREF(o);
105 if (err < 0) {
106 PyErr_WriteUnraisable(pObj->externalTimer);
107 return 0;
108 }
109 return result;
110 }
111
112 static inline _PyTime_t
call_timer(ProfilerObject * pObj)113 call_timer(ProfilerObject *pObj)
114 {
115 if (pObj->externalTimer != NULL) {
116 return CallExternalTimer(pObj);
117 }
118 else {
119 return _PyTime_GetPerfCounter();
120 }
121 }
122
123
124 /*** ProfilerObject ***/
125
126 static PyObject *
normalizeUserObj(PyObject * obj)127 normalizeUserObj(PyObject *obj)
128 {
129 PyCFunctionObject *fn;
130 if (!PyCFunction_Check(obj)) {
131 Py_INCREF(obj);
132 return obj;
133 }
134 /* Replace built-in function objects with a descriptive string
135 because of built-in methods -- keeping a reference to
136 __self__ is probably not a good idea. */
137 fn = (PyCFunctionObject *)obj;
138
139 if (fn->m_self == NULL) {
140 /* built-in function: look up the module name */
141 PyObject *mod = fn->m_module;
142 PyObject *modname = NULL;
143 if (mod != NULL) {
144 if (PyUnicode_Check(mod)) {
145 modname = mod;
146 Py_INCREF(modname);
147 }
148 else if (PyModule_Check(mod)) {
149 modname = PyModule_GetNameObject(mod);
150 if (modname == NULL)
151 PyErr_Clear();
152 }
153 }
154 if (modname != NULL) {
155 if (!_PyUnicode_EqualToASCIIString(modname, "builtins")) {
156 PyObject *result;
157 result = PyUnicode_FromFormat("<%U.%s>", modname,
158 fn->m_ml->ml_name);
159 Py_DECREF(modname);
160 return result;
161 }
162 Py_DECREF(modname);
163 }
164 return PyUnicode_FromFormat("<%s>", fn->m_ml->ml_name);
165 }
166 else {
167 /* built-in method: try to return
168 repr(getattr(type(__self__), __name__))
169 */
170 PyObject *self = fn->m_self;
171 PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name);
172 PyObject *modname = fn->m_module;
173
174 if (name != NULL) {
175 PyObject *mo = _PyType_Lookup(Py_TYPE(self), name);
176 Py_XINCREF(mo);
177 Py_DECREF(name);
178 if (mo != NULL) {
179 PyObject *res = PyObject_Repr(mo);
180 Py_DECREF(mo);
181 if (res != NULL)
182 return res;
183 }
184 }
185 /* Otherwise, use __module__ */
186 PyErr_Clear();
187 if (modname != NULL && PyUnicode_Check(modname))
188 return PyUnicode_FromFormat("<built-in method %S.%s>",
189 modname, fn->m_ml->ml_name);
190 else
191 return PyUnicode_FromFormat("<built-in method %s>",
192 fn->m_ml->ml_name);
193 }
194 }
195
196 static ProfilerEntry*
newProfilerEntry(ProfilerObject * pObj,void * key,PyObject * userObj)197 newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
198 {
199 ProfilerEntry *self;
200 self = (ProfilerEntry*) PyMem_Malloc(sizeof(ProfilerEntry));
201 if (self == NULL) {
202 pObj->flags |= POF_NOMEMORY;
203 return NULL;
204 }
205 userObj = normalizeUserObj(userObj);
206 if (userObj == NULL) {
207 PyErr_Clear();
208 PyMem_Free(self);
209 pObj->flags |= POF_NOMEMORY;
210 return NULL;
211 }
212 self->header.key = key;
213 self->userObj = userObj;
214 self->tt = 0;
215 self->it = 0;
216 self->callcount = 0;
217 self->recursivecallcount = 0;
218 self->recursionLevel = 0;
219 self->calls = EMPTY_ROTATING_TREE;
220 RotatingTree_Add(&pObj->profilerEntries, &self->header);
221 return self;
222 }
223
224 static ProfilerEntry*
getEntry(ProfilerObject * pObj,void * key)225 getEntry(ProfilerObject *pObj, void *key)
226 {
227 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
228 }
229
230 static ProfilerSubEntry *
getSubEntry(ProfilerObject * pObj,ProfilerEntry * caller,ProfilerEntry * entry)231 getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
232 {
233 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
234 (void *)entry);
235 }
236
237 static ProfilerSubEntry *
newSubEntry(ProfilerObject * pObj,ProfilerEntry * caller,ProfilerEntry * entry)238 newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
239 {
240 ProfilerSubEntry *self;
241 self = (ProfilerSubEntry*) PyMem_Malloc(sizeof(ProfilerSubEntry));
242 if (self == NULL) {
243 pObj->flags |= POF_NOMEMORY;
244 return NULL;
245 }
246 self->header.key = (void *)entry;
247 self->tt = 0;
248 self->it = 0;
249 self->callcount = 0;
250 self->recursivecallcount = 0;
251 self->recursionLevel = 0;
252 RotatingTree_Add(&caller->calls, &self->header);
253 return self;
254 }
255
freeSubEntry(rotating_node_t * header,void * arg)256 static int freeSubEntry(rotating_node_t *header, void *arg)
257 {
258 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
259 PyMem_Free(subentry);
260 return 0;
261 }
262
freeEntry(rotating_node_t * header,void * arg)263 static int freeEntry(rotating_node_t *header, void *arg)
264 {
265 ProfilerEntry *entry = (ProfilerEntry*) header;
266 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
267 Py_DECREF(entry->userObj);
268 PyMem_Free(entry);
269 return 0;
270 }
271
clearEntries(ProfilerObject * pObj)272 static void clearEntries(ProfilerObject *pObj)
273 {
274 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
275 pObj->profilerEntries = EMPTY_ROTATING_TREE;
276 /* release the memory hold by the ProfilerContexts */
277 if (pObj->currentProfilerContext) {
278 PyMem_Free(pObj->currentProfilerContext);
279 pObj->currentProfilerContext = NULL;
280 }
281 while (pObj->freelistProfilerContext) {
282 ProfilerContext *c = pObj->freelistProfilerContext;
283 pObj->freelistProfilerContext = c->previous;
284 PyMem_Free(c);
285 }
286 pObj->freelistProfilerContext = NULL;
287 }
288
289 static void
initContext(ProfilerObject * pObj,ProfilerContext * self,ProfilerEntry * entry)290 initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
291 {
292 self->ctxEntry = entry;
293 self->subt = 0;
294 self->previous = pObj->currentProfilerContext;
295 pObj->currentProfilerContext = self;
296 ++entry->recursionLevel;
297 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
298 /* find or create an entry for me in my caller's entry */
299 ProfilerEntry *caller = self->previous->ctxEntry;
300 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
301 if (subentry == NULL)
302 subentry = newSubEntry(pObj, caller, entry);
303 if (subentry)
304 ++subentry->recursionLevel;
305 }
306 self->t0 = call_timer(pObj);
307 }
308
309 static void
Stop(ProfilerObject * pObj,ProfilerContext * self,ProfilerEntry * entry)310 Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
311 {
312 _PyTime_t tt = call_timer(pObj) - self->t0;
313 _PyTime_t it = tt - self->subt;
314 if (self->previous)
315 self->previous->subt += tt;
316 pObj->currentProfilerContext = self->previous;
317 if (--entry->recursionLevel == 0)
318 entry->tt += tt;
319 else
320 ++entry->recursivecallcount;
321 entry->it += it;
322 entry->callcount++;
323 if ((pObj->flags & POF_SUBCALLS) && self->previous) {
324 /* find or create an entry for me in my caller's entry */
325 ProfilerEntry *caller = self->previous->ctxEntry;
326 ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
327 if (subentry) {
328 if (--subentry->recursionLevel == 0)
329 subentry->tt += tt;
330 else
331 ++subentry->recursivecallcount;
332 subentry->it += it;
333 ++subentry->callcount;
334 }
335 }
336 }
337
338 static void
ptrace_enter_call(PyObject * self,void * key,PyObject * userObj)339 ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
340 {
341 /* entering a call to the function identified by 'key'
342 (which can be a PyCodeObject or a PyMethodDef pointer) */
343 ProfilerObject *pObj = (ProfilerObject*)self;
344 ProfilerEntry *profEntry;
345 ProfilerContext *pContext;
346
347 /* In the case of entering a generator expression frame via a
348 * throw (gen_send_ex(.., 1)), we may already have an
349 * Exception set here. We must not mess around with this
350 * exception, and some of the code under here assumes that
351 * PyErr_* is its own to mess around with, so we have to
352 * save and restore any current exception. */
353 PyObject *last_type, *last_value, *last_tb;
354 PyErr_Fetch(&last_type, &last_value, &last_tb);
355
356 profEntry = getEntry(pObj, key);
357 if (profEntry == NULL) {
358 profEntry = newProfilerEntry(pObj, key, userObj);
359 if (profEntry == NULL)
360 goto restorePyerr;
361 }
362 /* grab a ProfilerContext out of the free list */
363 pContext = pObj->freelistProfilerContext;
364 if (pContext) {
365 pObj->freelistProfilerContext = pContext->previous;
366 }
367 else {
368 /* free list exhausted, allocate a new one */
369 pContext = (ProfilerContext*)
370 PyMem_Malloc(sizeof(ProfilerContext));
371 if (pContext == NULL) {
372 pObj->flags |= POF_NOMEMORY;
373 goto restorePyerr;
374 }
375 }
376 initContext(pObj, pContext, profEntry);
377
378 restorePyerr:
379 PyErr_Restore(last_type, last_value, last_tb);
380 }
381
382 static void
ptrace_leave_call(PyObject * self,void * key)383 ptrace_leave_call(PyObject *self, void *key)
384 {
385 /* leaving a call to the function identified by 'key' */
386 ProfilerObject *pObj = (ProfilerObject*)self;
387 ProfilerEntry *profEntry;
388 ProfilerContext *pContext;
389
390 pContext = pObj->currentProfilerContext;
391 if (pContext == NULL)
392 return;
393 profEntry = getEntry(pObj, key);
394 if (profEntry) {
395 Stop(pObj, pContext, profEntry);
396 }
397 else {
398 pObj->currentProfilerContext = pContext->previous;
399 }
400 /* put pContext into the free list */
401 pContext->previous = pObj->freelistProfilerContext;
402 pObj->freelistProfilerContext = pContext;
403 }
404
405 static int
profiler_callback(PyObject * self,PyFrameObject * frame,int what,PyObject * arg)406 profiler_callback(PyObject *self, PyFrameObject *frame, int what,
407 PyObject *arg)
408 {
409 switch (what) {
410
411 /* the 'frame' of a called function is about to start its execution */
412 case PyTrace_CALL:
413 {
414 PyCodeObject *code = PyFrame_GetCode(frame);
415 ptrace_enter_call(self, (void *)code, (PyObject *)code);
416 Py_DECREF(code);
417 break;
418 }
419
420 /* the 'frame' of a called function is about to finish
421 (either normally or with an exception) */
422 case PyTrace_RETURN:
423 {
424 PyCodeObject *code = PyFrame_GetCode(frame);
425 ptrace_leave_call(self, (void *)code);
426 Py_DECREF(code);
427 break;
428 }
429
430 /* case PyTrace_EXCEPTION:
431 If the exception results in the function exiting, a
432 PyTrace_RETURN event will be generated, so we don't need to
433 handle it. */
434
435 /* the Python function 'frame' is issuing a call to the built-in
436 function 'arg' */
437 case PyTrace_C_CALL:
438 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
439 && PyCFunction_Check(arg)) {
440 ptrace_enter_call(self,
441 ((PyCFunctionObject *)arg)->m_ml,
442 arg);
443 }
444 break;
445
446 /* the call to the built-in function 'arg' is returning into its
447 caller 'frame' */
448 case PyTrace_C_RETURN: /* ...normally */
449 case PyTrace_C_EXCEPTION: /* ...with an exception set */
450 if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
451 && PyCFunction_Check(arg)) {
452 ptrace_leave_call(self,
453 ((PyCFunctionObject *)arg)->m_ml);
454 }
455 break;
456
457 default:
458 break;
459 }
460 return 0;
461 }
462
463 static int
pending_exception(ProfilerObject * pObj)464 pending_exception(ProfilerObject *pObj)
465 {
466 if (pObj->flags & POF_NOMEMORY) {
467 pObj->flags -= POF_NOMEMORY;
468 PyErr_SetString(PyExc_MemoryError,
469 "memory was exhausted while profiling");
470 return -1;
471 }
472 return 0;
473 }
474
475 /************************************************************/
476
477 static PyStructSequence_Field profiler_entry_fields[] = {
478 {"code", "code object or built-in function name"},
479 {"callcount", "how many times this was called"},
480 {"reccallcount", "how many times called recursively"},
481 {"totaltime", "total time in this entry"},
482 {"inlinetime", "inline time in this entry (not in subcalls)"},
483 {"calls", "details of the calls"},
484 {0}
485 };
486
487 static PyStructSequence_Field profiler_subentry_fields[] = {
488 {"code", "called code object or built-in function name"},
489 {"callcount", "how many times this is called"},
490 {"reccallcount", "how many times this is called recursively"},
491 {"totaltime", "total time spent in this call"},
492 {"inlinetime", "inline time (not in further subcalls)"},
493 {0}
494 };
495
496 static PyStructSequence_Desc profiler_entry_desc = {
497 .name = "_lsprof.profiler_entry",
498 .fields = profiler_entry_fields,
499 .doc = NULL,
500 .n_in_sequence = 6
501 };
502
503 static PyStructSequence_Desc profiler_subentry_desc = {
504 .name = "_lsprof.profiler_subentry",
505 .fields = profiler_subentry_fields,
506 .doc = NULL,
507 .n_in_sequence = 5
508 };
509
510 typedef struct {
511 PyObject *list;
512 PyObject *sublist;
513 double factor;
514 _lsprof_state *state;
515 } statscollector_t;
516
statsForSubEntry(rotating_node_t * node,void * arg)517 static int statsForSubEntry(rotating_node_t *node, void *arg)
518 {
519 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
520 statscollector_t *collect = (statscollector_t*) arg;
521 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
522 int err;
523 PyObject *sinfo;
524 sinfo = PyObject_CallFunction((PyObject*) collect->state->stats_subentry_type,
525 "((Olldd))",
526 entry->userObj,
527 sentry->callcount,
528 sentry->recursivecallcount,
529 collect->factor * sentry->tt,
530 collect->factor * sentry->it);
531 if (sinfo == NULL)
532 return -1;
533 err = PyList_Append(collect->sublist, sinfo);
534 Py_DECREF(sinfo);
535 return err;
536 }
537
statsForEntry(rotating_node_t * node,void * arg)538 static int statsForEntry(rotating_node_t *node, void *arg)
539 {
540 ProfilerEntry *entry = (ProfilerEntry*) node;
541 statscollector_t *collect = (statscollector_t*) arg;
542 PyObject *info;
543 int err;
544 if (entry->callcount == 0)
545 return 0; /* skip */
546
547 if (entry->calls != EMPTY_ROTATING_TREE) {
548 collect->sublist = PyList_New(0);
549 if (collect->sublist == NULL)
550 return -1;
551 if (RotatingTree_Enum(entry->calls,
552 statsForSubEntry, collect) != 0) {
553 Py_DECREF(collect->sublist);
554 return -1;
555 }
556 }
557 else {
558 Py_INCREF(Py_None);
559 collect->sublist = Py_None;
560 }
561
562 info = PyObject_CallFunction((PyObject*) collect->state->stats_entry_type,
563 "((OllddO))",
564 entry->userObj,
565 entry->callcount,
566 entry->recursivecallcount,
567 collect->factor * entry->tt,
568 collect->factor * entry->it,
569 collect->sublist);
570 Py_DECREF(collect->sublist);
571 if (info == NULL)
572 return -1;
573 err = PyList_Append(collect->list, info);
574 Py_DECREF(info);
575 return err;
576 }
577
578 /*[clinic input]
579 _lsprof.Profiler.getstats
580
581 cls: defining_class
582
583 list of profiler_entry objects.
584
585 getstats() -> list of profiler_entry objects
586
587 Return all information collected by the profiler.
588 Each profiler_entry is a tuple-like object with the
589 following attributes:
590
591 code code object
592 callcount how many times this was called
593 reccallcount how many times called recursively
594 totaltime total time in this entry
595 inlinetime inline time in this entry (not in subcalls)
596 calls details of the calls
597
598 The calls attribute is either None or a list of
599 profiler_subentry objects:
600
601 code called code object
602 callcount how many times this is called
603 reccallcount how many times this is called recursively
604 totaltime total time spent in this call
605 inlinetime inline time (not in further subcalls)
606 [clinic start generated code]*/
607
608 static PyObject *
_lsprof_Profiler_getstats_impl(ProfilerObject * self,PyTypeObject * cls)609 _lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls)
610 /*[clinic end generated code: output=1806ef720019ee03 input=445e193ef4522902]*/
611 {
612 statscollector_t collect;
613 collect.state = PyType_GetModuleState(cls);
614 if (pending_exception(self)) {
615 return NULL;
616 }
617 if (!self->externalTimer || self->externalTimerUnit == 0.0) {
618 _PyTime_t onesec = _PyTime_FromSeconds(1);
619 collect.factor = (double)1 / onesec;
620 }
621 else {
622 collect.factor = self->externalTimerUnit;
623 }
624
625 collect.list = PyList_New(0);
626 if (collect.list == NULL)
627 return NULL;
628 if (RotatingTree_Enum(self->profilerEntries, statsForEntry, &collect)
629 != 0) {
630 Py_DECREF(collect.list);
631 return NULL;
632 }
633 return collect.list;
634 }
635
636 static int
setSubcalls(ProfilerObject * pObj,int nvalue)637 setSubcalls(ProfilerObject *pObj, int nvalue)
638 {
639 if (nvalue == 0)
640 pObj->flags &= ~POF_SUBCALLS;
641 else if (nvalue > 0)
642 pObj->flags |= POF_SUBCALLS;
643 return 0;
644 }
645
646 static int
setBuiltins(ProfilerObject * pObj,int nvalue)647 setBuiltins(ProfilerObject *pObj, int nvalue)
648 {
649 if (nvalue == 0)
650 pObj->flags &= ~POF_BUILTINS;
651 else if (nvalue > 0) {
652 pObj->flags |= POF_BUILTINS;
653 }
654 return 0;
655 }
656
657 PyDoc_STRVAR(enable_doc, "\
658 enable(subcalls=True, builtins=True)\n\
659 \n\
660 Start collecting profiling information.\n\
661 If 'subcalls' is True, also records for each function\n\
662 statistics separated according to its current caller.\n\
663 If 'builtins' is True, records the time spent in\n\
664 built-in functions separately from their caller.\n\
665 ");
666
667 static PyObject*
profiler_enable(ProfilerObject * self,PyObject * args,PyObject * kwds)668 profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
669 {
670 int subcalls = -1;
671 int builtins = -1;
672 static char *kwlist[] = {"subcalls", "builtins", 0};
673 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
674 kwlist, &subcalls, &builtins))
675 return NULL;
676 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) {
677 return NULL;
678 }
679
680 PyThreadState *tstate = _PyThreadState_GET();
681 if (_PyEval_SetProfile(tstate, profiler_callback, (PyObject*)self) < 0) {
682 return NULL;
683 }
684
685 self->flags |= POF_ENABLED;
686 Py_RETURN_NONE;
687 }
688
689 static void
flush_unmatched(ProfilerObject * pObj)690 flush_unmatched(ProfilerObject *pObj)
691 {
692 while (pObj->currentProfilerContext) {
693 ProfilerContext *pContext = pObj->currentProfilerContext;
694 ProfilerEntry *profEntry= pContext->ctxEntry;
695 if (profEntry)
696 Stop(pObj, pContext, profEntry);
697 else
698 pObj->currentProfilerContext = pContext->previous;
699 if (pContext)
700 PyMem_Free(pContext);
701 }
702
703 }
704
705 PyDoc_STRVAR(disable_doc, "\
706 disable()\n\
707 \n\
708 Stop collecting profiling information.\n\
709 ");
710
711 static PyObject*
profiler_disable(ProfilerObject * self,PyObject * noarg)712 profiler_disable(ProfilerObject *self, PyObject* noarg)
713 {
714 PyThreadState *tstate = _PyThreadState_GET();
715 if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
716 return NULL;
717 }
718 self->flags &= ~POF_ENABLED;
719
720 flush_unmatched(self);
721 if (pending_exception(self)) {
722 return NULL;
723 }
724 Py_RETURN_NONE;
725 }
726
727 PyDoc_STRVAR(clear_doc, "\
728 clear()\n\
729 \n\
730 Clear all profiling information collected so far.\n\
731 ");
732
733 static PyObject*
profiler_clear(ProfilerObject * pObj,PyObject * noarg)734 profiler_clear(ProfilerObject *pObj, PyObject* noarg)
735 {
736 clearEntries(pObj);
737 Py_RETURN_NONE;
738 }
739
740 static int
profiler_traverse(ProfilerObject * op,visitproc visit,void * arg)741 profiler_traverse(ProfilerObject *op, visitproc visit, void *arg)
742 {
743 Py_VISIT(Py_TYPE(op));
744 return 0;
745 }
746
747 static void
profiler_dealloc(ProfilerObject * op)748 profiler_dealloc(ProfilerObject *op)
749 {
750 PyObject_GC_UnTrack(op);
751 if (op->flags & POF_ENABLED) {
752 PyThreadState *tstate = _PyThreadState_GET();
753 if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
754 _PyErr_WriteUnraisableMsg("When destroying _lsprof profiler", NULL);
755 }
756 }
757
758 flush_unmatched(op);
759 clearEntries(op);
760 Py_XDECREF(op->externalTimer);
761 PyTypeObject *tp = Py_TYPE(op);
762 tp->tp_free(op);
763 Py_DECREF(tp);
764 }
765
766 static int
profiler_init(ProfilerObject * pObj,PyObject * args,PyObject * kw)767 profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
768 {
769 PyObject *timer = NULL;
770 double timeunit = 0.0;
771 int subcalls = 1;
772 int builtins = 1;
773 static char *kwlist[] = {"timer", "timeunit",
774 "subcalls", "builtins", 0};
775
776 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
777 &timer, &timeunit,
778 &subcalls, &builtins))
779 return -1;
780
781 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
782 return -1;
783 pObj->externalTimerUnit = timeunit;
784 Py_XINCREF(timer);
785 Py_XSETREF(pObj->externalTimer, timer);
786 return 0;
787 }
788
789 static PyMethodDef profiler_methods[] = {
790 _LSPROF_PROFILER_GETSTATS_METHODDEF
791 {"enable", _PyCFunction_CAST(profiler_enable),
792 METH_VARARGS | METH_KEYWORDS, enable_doc},
793 {"disable", (PyCFunction)profiler_disable,
794 METH_NOARGS, disable_doc},
795 {"clear", (PyCFunction)profiler_clear,
796 METH_NOARGS, clear_doc},
797 {NULL, NULL}
798 };
799
800 PyDoc_STRVAR(profiler_doc, "\
801 Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\
802 \n\
803 Builds a profiler object using the specified timer function.\n\
804 The default timer is a fast built-in one based on real time.\n\
805 For custom timer functions returning integers, timeunit can\n\
806 be a float specifying a scale (i.e. how long each integer unit\n\
807 is, in seconds).\n\
808 ");
809
810 static PyType_Slot _lsprof_profiler_type_spec_slots[] = {
811 {Py_tp_doc, (void *)profiler_doc},
812 {Py_tp_methods, profiler_methods},
813 {Py_tp_dealloc, profiler_dealloc},
814 {Py_tp_init, profiler_init},
815 {Py_tp_traverse, profiler_traverse},
816 {0, 0}
817 };
818
819 static PyType_Spec _lsprof_profiler_type_spec = {
820 .name = "_lsprof.Profiler",
821 .basicsize = sizeof(ProfilerObject),
822 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
823 Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
824 .slots = _lsprof_profiler_type_spec_slots,
825 };
826
827 static PyMethodDef moduleMethods[] = {
828 {NULL, NULL}
829 };
830
831 static int
_lsprof_traverse(PyObject * module,visitproc visit,void * arg)832 _lsprof_traverse(PyObject *module, visitproc visit, void *arg)
833 {
834 _lsprof_state *state = _lsprof_get_state(module);
835 Py_VISIT(state->profiler_type);
836 Py_VISIT(state->stats_entry_type);
837 Py_VISIT(state->stats_subentry_type);
838 return 0;
839 }
840
841 static int
_lsprof_clear(PyObject * module)842 _lsprof_clear(PyObject *module)
843 {
844 _lsprof_state *state = _lsprof_get_state(module);
845 Py_CLEAR(state->profiler_type);
846 Py_CLEAR(state->stats_entry_type);
847 Py_CLEAR(state->stats_subentry_type);
848 return 0;
849 }
850
851 static void
_lsprof_free(void * module)852 _lsprof_free(void *module)
853 {
854 _lsprof_clear((PyObject *)module);
855 }
856
857 static int
_lsprof_exec(PyObject * module)858 _lsprof_exec(PyObject *module)
859 {
860 _lsprof_state *state = PyModule_GetState(module);
861
862 state->profiler_type = (PyTypeObject *)PyType_FromModuleAndSpec(
863 module, &_lsprof_profiler_type_spec, NULL);
864 if (state->profiler_type == NULL) {
865 return -1;
866 }
867
868 if (PyModule_AddType(module, state->profiler_type) < 0) {
869 return -1;
870 }
871
872 state->stats_entry_type = PyStructSequence_NewType(&profiler_entry_desc);
873 if (state->stats_entry_type == NULL) {
874 return -1;
875 }
876 if (PyModule_AddType(module, state->stats_entry_type) < 0) {
877 return -1;
878 }
879
880 state->stats_subentry_type = PyStructSequence_NewType(&profiler_subentry_desc);
881 if (state->stats_subentry_type == NULL) {
882 return -1;
883 }
884 if (PyModule_AddType(module, state->stats_subentry_type) < 0) {
885 return -1;
886 }
887
888 return 0;
889 }
890
891 static PyModuleDef_Slot _lsprofslots[] = {
892 {Py_mod_exec, _lsprof_exec},
893 {0, NULL}
894 };
895
896 static struct PyModuleDef _lsprofmodule = {
897 PyModuleDef_HEAD_INIT,
898 .m_name = "_lsprof",
899 .m_doc = "Fast profiler",
900 .m_size = sizeof(_lsprof_state),
901 .m_methods = moduleMethods,
902 .m_slots = _lsprofslots,
903 .m_traverse = _lsprof_traverse,
904 .m_clear = _lsprof_clear,
905 .m_free = _lsprof_free
906 };
907
908 PyMODINIT_FUNC
PyInit__lsprof(void)909 PyInit__lsprof(void)
910 {
911 return PyModuleDef_Init(&_lsprofmodule);
912 }
913