1 #include "Python.h"
2 #include "rotatingtree.h"
3
4 /************************************************************/
5 /* Written by Brett Rosen and Ted Czotter */
6
7 struct _ProfilerEntry;
8
9 /* represents a function called from another function */
10 typedef struct _ProfilerSubEntry {
11 rotating_node_t header;
12 _PyTime_t tt;
13 _PyTime_t it;
14 long callcount;
15 long recursivecallcount;
16 long recursionLevel;
17 } ProfilerSubEntry;
18
19 /* represents a function or user defined block */
20 typedef struct _ProfilerEntry {
21 rotating_node_t header;
22 PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
23 _PyTime_t tt; /* total time in this entry */
24 _PyTime_t it; /* inline time in this entry (not in subcalls) */
25 long callcount; /* how many times this was called */
26 long recursivecallcount; /* how many times called recursively */
27 long recursionLevel;
28 rotating_node_t *calls;
29 } ProfilerEntry;
30
31 typedef struct _ProfilerContext {
32 _PyTime_t t0;
33 _PyTime_t subt;
34 struct _ProfilerContext *previous;
35 ProfilerEntry *ctxEntry;
36 } ProfilerContext;
37
38 typedef struct {
39 PyObject_HEAD
40 rotating_node_t *profilerEntries;
41 ProfilerContext *currentProfilerContext;
42 ProfilerContext *freelistProfilerContext;
43 int flags;
44 PyObject *externalTimer;
45 double externalTimerUnit;
46 } ProfilerObject;
47
48 #define POF_ENABLED 0x001
49 #define POF_SUBCALLS 0x002
50 #define POF_BUILTINS 0x004
51 #define POF_NOMEMORY 0x100
52
53 /*[clinic input]
54 module _lsprof
55 class _lsprof.Profiler "ProfilerObject *" "&ProfilerType"
56 [clinic start generated code]*/
57 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e349ac952152f336]*/
58
59 #include "clinic/_lsprof.c.h"
60
61 typedef struct {
62 PyTypeObject *profiler_type;
63 PyTypeObject *stats_entry_type;
64 PyTypeObject *stats_subentry_type;
65 } _lsprof_state;
66
67 static inline _lsprof_state*
_lsprof_get_state(PyObject * module)68 _lsprof_get_state(PyObject *module)
69 {
70 void *state = PyModule_GetState(module);
71 assert(state != NULL);
72 return (_lsprof_state *)state;
73 }
74
75 /*** External Timers ***/
76
CallExternalTimer(ProfilerObject * pObj)77 static _PyTime_t CallExternalTimer(ProfilerObject *pObj)
78 {
79 PyObject *o = _PyObject_CallNoArg(pObj->externalTimer);
80 if (o == NULL) {
81 PyErr_WriteUnraisable(pObj->externalTimer);
82 return 0;
83 }
84
85 _PyTime_t result;
86 int err;
87 if (pObj->externalTimerUnit > 0.0) {
88 /* interpret the result as an integer that will be scaled
89 in profiler_getstats() */
90 err = _PyTime_FromNanosecondsObject(&result, o);
91 }
92 else {
93 /* interpret the result as a double measured in seconds.
94 As the profiler works with _PyTime_t internally
95 we convert it to a large integer */
96 err = _PyTime_FromSecondsObject(&result, o, _PyTime_ROUND_FLOOR);
97 }
98 Py_DECREF(o);
99 if (err < 0) {
100 PyErr_WriteUnraisable(pObj->externalTimer);
101 return 0;
102 }
103 return result;
104 }
105
106 static inline _PyTime_t
call_timer(ProfilerObject * pObj)107 call_timer(ProfilerObject *pObj)
108 {
109 if (pObj->externalTimer != NULL) {
110 return CallExternalTimer(pObj);
111 }
112 else {
113 return _PyTime_GetPerfCounter();
114 }
115 }
116
117
118 /*** ProfilerObject ***/
119
120 static PyObject *
normalizeUserObj(PyObject * obj)121 normalizeUserObj(PyObject *obj)
122 {
123 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;
132
133 if (fn->m_self == NULL) {
134 /* built-in function: look up the module name */
135 PyObject *mod = fn->m_module;
136 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();
146 }
147 }
148 if (modname != NULL) {
149 if (!_PyUnicode_EqualToASCIIString(modname, "builtins")) {
150 PyObject *result;
151 result = PyUnicode_FromFormat("<%U.%s>", modname,
152 fn->m_ml->ml_name);
153 Py_DECREF(modname);
154 return result;
155 }
156 Py_DECREF(modname);
157 }
158 return PyUnicode_FromFormat("<%s>", fn->m_ml->ml_name);
159 }
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);
166 PyObject *modname = fn->m_module;
167
168 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 }
179 /* Otherwise, use __module__ */
180 PyErr_Clear();
181 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);
187 }
188 }
189
190 static ProfilerEntry*
newProfilerEntry(ProfilerObject * pObj,void * key,PyObject * userObj)191 newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
192 {
193 ProfilerEntry *self;
194 self = (ProfilerEntry*) PyMem_Malloc(sizeof(ProfilerEntry));
195 if (self == NULL) {
196 pObj->flags |= POF_NOMEMORY;
197 return NULL;
198 }
199 userObj = normalizeUserObj(userObj);
200 if (userObj == NULL) {
201 PyErr_Clear();
202 PyMem_Free(self);
203 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;
216 }
217
218 static ProfilerEntry*
getEntry(ProfilerObject * pObj,void * key)219 getEntry(ProfilerObject *pObj, void *key)
220 {
221 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
222 }
223
224 static ProfilerSubEntry *
getSubEntry(ProfilerObject * pObj,ProfilerEntry * caller,ProfilerEntry * entry)225 getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
226 {
227 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
228 (void *)entry);
229 }
230
231 static ProfilerSubEntry *
newSubEntry(ProfilerObject * pObj,ProfilerEntry * caller,ProfilerEntry * entry)232 newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
233 {
234 ProfilerSubEntry *self;
235 self = (ProfilerSubEntry*) PyMem_Malloc(sizeof(ProfilerSubEntry));
236 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;
248 }
249
freeSubEntry(rotating_node_t * header,void * arg)250 static int freeSubEntry(rotating_node_t *header, void *arg)
251 {
252 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
253 PyMem_Free(subentry);
254 return 0;
255 }
256
freeEntry(rotating_node_t * header,void * arg)257 static int freeEntry(rotating_node_t *header, void *arg)
258 {
259 ProfilerEntry *entry = (ProfilerEntry*) header;
260 RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
261 Py_DECREF(entry->userObj);
262 PyMem_Free(entry);
263 return 0;
264 }
265
clearEntries(ProfilerObject * pObj)266 static void clearEntries(ProfilerObject *pObj)
267 {
268 RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
269 pObj->profilerEntries = EMPTY_ROTATING_TREE;
270 /* release the memory hold by the ProfilerContexts */
271 if (pObj->currentProfilerContext) {
272 PyMem_Free(pObj->currentProfilerContext);
273 pObj->currentProfilerContext = NULL;
274 }
275 while (pObj->freelistProfilerContext) {
276 ProfilerContext *c = pObj->freelistProfilerContext;
277 pObj->freelistProfilerContext = c->previous;
278 PyMem_Free(c);
279 }
280 pObj->freelistProfilerContext = NULL;
281 }
282
283 static void
initContext(ProfilerObject * pObj,ProfilerContext * self,ProfilerEntry * entry)284 initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
285 {
286 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 }
300 self->t0 = call_timer(pObj);
301 }
302
303 static void
Stop(ProfilerObject * pObj,ProfilerContext * self,ProfilerEntry * entry)304 Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
305 {
306 _PyTime_t tt = call_timer(pObj) - self->t0;
307 _PyTime_t it = tt - self->subt;
308 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 }
330 }
331
332 static void
ptrace_enter_call(PyObject * self,void * key,PyObject * userObj)333 ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
334 {
335 /* 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;
340
341 /* 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);
349
350 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*)
364 PyMem_Malloc(sizeof(ProfilerContext));
365 if (pContext == NULL) {
366 pObj->flags |= POF_NOMEMORY;
367 goto restorePyerr;
368 }
369 }
370 initContext(pObj, pContext, profEntry);
371
372 restorePyerr:
373 PyErr_Restore(last_type, last_value, last_tb);
374 }
375
376 static void
ptrace_leave_call(PyObject * self,void * key)377 ptrace_leave_call(PyObject *self, void *key)
378 {
379 /* leaving a call to the function identified by 'key' */
380 ProfilerObject *pObj = (ProfilerObject*)self;
381 ProfilerEntry *profEntry;
382 ProfilerContext *pContext;
383
384 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;
397 }
398
399 static int
profiler_callback(PyObject * self,PyFrameObject * frame,int what,PyObject * arg)400 profiler_callback(PyObject *self, PyFrameObject *frame, int what,
401 PyObject *arg)
402 {
403 switch (what) {
404
405 /* the 'frame' of a called function is about to start its execution */
406 case PyTrace_CALL:
407 {
408 PyCodeObject *code = PyFrame_GetCode(frame);
409 ptrace_enter_call(self, (void *)code, (PyObject *)code);
410 Py_DECREF(code);
411 break;
412 }
413
414 /* the 'frame' of a called function is about to finish
415 (either normally or with an exception) */
416 case PyTrace_RETURN:
417 {
418 PyCodeObject *code = PyFrame_GetCode(frame);
419 ptrace_leave_call(self, (void *)code);
420 Py_DECREF(code);
421 break;
422 }
423
424 /* 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. */
428
429 /* 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;
439
440 /* 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;
450
451 default:
452 break;
453 }
454 return 0;
455 }
456
457 static int
pending_exception(ProfilerObject * pObj)458 pending_exception(ProfilerObject *pObj)
459 {
460 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;
467 }
468
469 /************************************************************/
470
471 static PyStructSequence_Field profiler_entry_fields[] = {
472 {"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}
479 };
480
481 static PyStructSequence_Field profiler_subentry_fields[] = {
482 {"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}
488 };
489
490 static PyStructSequence_Desc profiler_entry_desc = {
491 .name = "_lsprof.profiler_entry",
492 .fields = profiler_entry_fields,
493 .doc = NULL,
494 .n_in_sequence = 6
495 };
496
497 static PyStructSequence_Desc profiler_subentry_desc = {
498 .name = "_lsprof.profiler_subentry",
499 .fields = profiler_subentry_fields,
500 .doc = NULL,
501 .n_in_sequence = 5
502 };
503
504 typedef struct {
505 PyObject *list;
506 PyObject *sublist;
507 double factor;
508 _lsprof_state *state;
509 } statscollector_t;
510
statsForSubEntry(rotating_node_t * node,void * arg)511 static int statsForSubEntry(rotating_node_t *node, void *arg)
512 {
513 ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
514 statscollector_t *collect = (statscollector_t*) arg;
515 ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
516 int err;
517 PyObject *sinfo;
518 sinfo = PyObject_CallFunction((PyObject*) collect->state->stats_subentry_type,
519 "((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;
530 }
531
statsForEntry(rotating_node_t * node,void * arg)532 static int statsForEntry(rotating_node_t *node, void *arg)
533 {
534 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 */
540
541 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 }
555
556 info = PyObject_CallFunction((PyObject*) collect->state->stats_entry_type,
557 "((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;
570 }
571
572 /*[clinic input]
573 _lsprof.Profiler.getstats
574
575 cls: defining_class
576
577 list of profiler_entry objects.
578
579 getstats() -> list of profiler_entry objects
580
581 Return all information collected by the profiler.
582 Each profiler_entry is a tuple-like object with the
583 following 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
592 The calls attribute is either None or a list of
593 profiler_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
602 static PyObject *
_lsprof_Profiler_getstats_impl(ProfilerObject * self,PyTypeObject * cls)603 _lsprof_Profiler_getstats_impl(ProfilerObject *self, PyTypeObject *cls)
604 /*[clinic end generated code: output=1806ef720019ee03 input=445e193ef4522902]*/
605 {
606 statscollector_t collect;
607 collect.state = PyType_GetModuleState(cls);
608 if (pending_exception(self)) {
609 return NULL;
610 }
611 if (!self->externalTimer || self->externalTimerUnit == 0.0) {
612 _PyTime_t onesec = _PyTime_FromSeconds(1);
613 collect.factor = (double)1 / onesec;
614 }
615 else {
616 collect.factor = self->externalTimerUnit;
617 }
618
619 collect.list = PyList_New(0);
620 if (collect.list == NULL)
621 return NULL;
622 if (RotatingTree_Enum(self->profilerEntries, statsForEntry, &collect)
623 != 0) {
624 Py_DECREF(collect.list);
625 return NULL;
626 }
627 return collect.list;
628 }
629
630 static int
setSubcalls(ProfilerObject * pObj,int nvalue)631 setSubcalls(ProfilerObject *pObj, int nvalue)
632 {
633 if (nvalue == 0)
634 pObj->flags &= ~POF_SUBCALLS;
635 else if (nvalue > 0)
636 pObj->flags |= POF_SUBCALLS;
637 return 0;
638 }
639
640 static int
setBuiltins(ProfilerObject * pObj,int nvalue)641 setBuiltins(ProfilerObject *pObj, int nvalue)
642 {
643 if (nvalue == 0)
644 pObj->flags &= ~POF_BUILTINS;
645 else if (nvalue > 0) {
646 pObj->flags |= POF_BUILTINS;
647 }
648 return 0;
649 }
650
651 PyDoc_STRVAR(enable_doc, "\
652 enable(subcalls=True, builtins=True)\n\
653 \n\
654 Start collecting profiling information.\n\
655 If 'subcalls' is True, also records for each function\n\
656 statistics separated according to its current caller.\n\
657 If 'builtins' is True, records the time spent in\n\
658 built-in functions separately from their caller.\n\
659 ");
660
661 static PyObject*
profiler_enable(ProfilerObject * self,PyObject * args,PyObject * kwds)662 profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
663 {
664 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;
670 if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) {
671 return NULL;
672 }
673
674 PyThreadState *tstate = PyThreadState_GET();
675 if (_PyEval_SetProfile(tstate, profiler_callback, (PyObject*)self) < 0) {
676 return NULL;
677 }
678
679 self->flags |= POF_ENABLED;
680 Py_RETURN_NONE;
681 }
682
683 static void
flush_unmatched(ProfilerObject * pObj)684 flush_unmatched(ProfilerObject *pObj)
685 {
686 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)
694 PyMem_Free(pContext);
695 }
696
697 }
698
699 PyDoc_STRVAR(disable_doc, "\
700 disable()\n\
701 \n\
702 Stop collecting profiling information.\n\
703 ");
704
705 static PyObject*
profiler_disable(ProfilerObject * self,PyObject * noarg)706 profiler_disable(ProfilerObject *self, PyObject* noarg)
707 {
708 PyThreadState *tstate = PyThreadState_GET();
709 if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
710 return NULL;
711 }
712 self->flags &= ~POF_ENABLED;
713
714 flush_unmatched(self);
715 if (pending_exception(self)) {
716 return NULL;
717 }
718 Py_RETURN_NONE;
719 }
720
721 PyDoc_STRVAR(clear_doc, "\
722 clear()\n\
723 \n\
724 Clear all profiling information collected so far.\n\
725 ");
726
727 static PyObject*
profiler_clear(ProfilerObject * pObj,PyObject * noarg)728 profiler_clear(ProfilerObject *pObj, PyObject* noarg)
729 {
730 clearEntries(pObj);
731 Py_RETURN_NONE;
732 }
733
734 static int
profiler_traverse(ProfilerObject * op,visitproc visit,void * arg)735 profiler_traverse(ProfilerObject *op, visitproc visit, void *arg)
736 {
737 Py_VISIT(Py_TYPE(op));
738 return 0;
739 }
740
741 static void
profiler_dealloc(ProfilerObject * op)742 profiler_dealloc(ProfilerObject *op)
743 {
744 if (op->flags & POF_ENABLED) {
745 PyThreadState *tstate = PyThreadState_GET();
746 if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
747 PyErr_WriteUnraisable((PyObject *)op);
748 }
749 }
750
751 flush_unmatched(op);
752 clearEntries(op);
753 Py_XDECREF(op->externalTimer);
754 PyTypeObject *tp = Py_TYPE(op);
755 tp->tp_free(op);
756 Py_DECREF(tp);
757 }
758
759 static int
profiler_init(ProfilerObject * pObj,PyObject * args,PyObject * kw)760 profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
761 {
762 PyObject *timer = NULL;
763 double timeunit = 0.0;
764 int subcalls = 1;
765 int builtins = 1;
766 static char *kwlist[] = {"timer", "timeunit",
767 "subcalls", "builtins", 0};
768
769 if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
770 &timer, &timeunit,
771 &subcalls, &builtins))
772 return -1;
773
774 if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
775 return -1;
776 pObj->externalTimerUnit = timeunit;
777 Py_XINCREF(timer);
778 Py_XSETREF(pObj->externalTimer, timer);
779 return 0;
780 }
781
782 static PyMethodDef profiler_methods[] = {
783 _LSPROF_PROFILER_GETSTATS_METHODDEF
784 {"enable", (PyCFunction)(void(*)(void))profiler_enable,
785 METH_VARARGS | METH_KEYWORDS, enable_doc},
786 {"disable", (PyCFunction)profiler_disable,
787 METH_NOARGS, disable_doc},
788 {"clear", (PyCFunction)profiler_clear,
789 METH_NOARGS, clear_doc},
790 {NULL, NULL}
791 };
792
793 PyDoc_STRVAR(profiler_doc, "\
794 Profiler(timer=None, timeunit=None, subcalls=True, builtins=True)\n\
795 \n\
796 Builds a profiler object using the specified timer function.\n\
797 The default timer is a fast built-in one based on real time.\n\
798 For custom timer functions returning integers, timeunit can\n\
799 be a float specifying a scale (i.e. how long each integer unit\n\
800 is, in seconds).\n\
801 ");
802
803 static PyType_Slot _lsprof_profiler_type_spec_slots[] = {
804 {Py_tp_doc, (void *)profiler_doc},
805 {Py_tp_methods, profiler_methods},
806 {Py_tp_dealloc, profiler_dealloc},
807 {Py_tp_init, profiler_init},
808 {Py_tp_traverse, profiler_traverse},
809 {0, 0}
810 };
811
812 static PyType_Spec _lsprof_profiler_type_spec = {
813 .name = "_lsprof.Profiler",
814 .basicsize = sizeof(ProfilerObject),
815 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
816 Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
817 .slots = _lsprof_profiler_type_spec_slots,
818 };
819
820 static PyMethodDef moduleMethods[] = {
821 {NULL, NULL}
822 };
823
824 static int
_lsprof_traverse(PyObject * module,visitproc visit,void * arg)825 _lsprof_traverse(PyObject *module, visitproc visit, void *arg)
826 {
827 _lsprof_state *state = _lsprof_get_state(module);
828 Py_VISIT(state->profiler_type);
829 Py_VISIT(state->stats_entry_type);
830 Py_VISIT(state->stats_subentry_type);
831 return 0;
832 }
833
834 static int
_lsprof_clear(PyObject * module)835 _lsprof_clear(PyObject *module)
836 {
837 _lsprof_state *state = _lsprof_get_state(module);
838 Py_CLEAR(state->profiler_type);
839 Py_CLEAR(state->stats_entry_type);
840 Py_CLEAR(state->stats_subentry_type);
841 return 0;
842 }
843
844 static void
_lsprof_free(void * module)845 _lsprof_free(void *module)
846 {
847 _lsprof_clear((PyObject *)module);
848 }
849
850 static int
_lsprof_exec(PyObject * module)851 _lsprof_exec(PyObject *module)
852 {
853 _lsprof_state *state = PyModule_GetState(module);
854
855 state->profiler_type = (PyTypeObject *)PyType_FromModuleAndSpec(
856 module, &_lsprof_profiler_type_spec, NULL);
857 if (state->profiler_type == NULL) {
858 return -1;
859 }
860
861 if (PyModule_AddType(module, state->profiler_type) < 0) {
862 return -1;
863 }
864
865 state->stats_entry_type = PyStructSequence_NewType(&profiler_entry_desc);
866 if (state->stats_entry_type == NULL) {
867 return -1;
868 }
869 if (PyModule_AddType(module, state->stats_entry_type) < 0) {
870 return -1;
871 }
872
873 state->stats_subentry_type = PyStructSequence_NewType(&profiler_subentry_desc);
874 if (state->stats_subentry_type == NULL) {
875 return -1;
876 }
877 if (PyModule_AddType(module, state->stats_subentry_type) < 0) {
878 return -1;
879 }
880
881 return 0;
882 }
883
884 static PyModuleDef_Slot _lsprofslots[] = {
885 {Py_mod_exec, _lsprof_exec},
886 {0, NULL}
887 };
888
889 static struct PyModuleDef _lsprofmodule = {
890 PyModuleDef_HEAD_INIT,
891 .m_name = "_lsprof",
892 .m_doc = "Fast profiler",
893 .m_size = sizeof(_lsprof_state),
894 .m_methods = moduleMethods,
895 .m_slots = _lsprofslots,
896 .m_traverse = _lsprof_traverse,
897 .m_clear = _lsprof_clear,
898 .m_free = _lsprof_free
899 };
900
901 PyMODINIT_FUNC
PyInit__lsprof(void)902 PyInit__lsprof(void)
903 {
904 return PyModuleDef_Init(&_lsprofmodule);
905 }
906