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 13struct _ProfilerEntry; 14 15/* represents a function called from another function */ 16typedef 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 */ 26typedef 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 37typedef struct _ProfilerContext { 38 _PyTime_t t0; 39 _PyTime_t subt; 40 struct _ProfilerContext *previous; 41 ProfilerEntry *ctxEntry; 42} ProfilerContext; 43 44typedef 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] 60module _lsprof 61class _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 67typedef struct { 68 PyTypeObject *profiler_type; 69 PyTypeObject *stats_entry_type; 70 PyTypeObject *stats_subentry_type; 71} _lsprof_state; 72 73static inline _lsprof_state* 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 83static _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 112static inline _PyTime_t 113call_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 126static PyObject * 127normalizeUserObj(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 196static ProfilerEntry* 197newProfilerEntry(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 224static ProfilerEntry* 225getEntry(ProfilerObject *pObj, void *key) 226{ 227 return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key); 228} 229 230static ProfilerSubEntry * 231getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry) 232{ 233 return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls, 234 (void *)entry); 235} 236 237static ProfilerSubEntry * 238newSubEntry(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 256static int freeSubEntry(rotating_node_t *header, void *arg) 257{ 258 ProfilerSubEntry *subentry = (ProfilerSubEntry*) header; 259 PyMem_Free(subentry); 260 return 0; 261} 262 263static 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 272static 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 289static void 290initContext(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 309static void 310Stop(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 338static void 339ptrace_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 378restorePyerr: 379 PyErr_Restore(last_type, last_value, last_tb); 380} 381 382static void 383ptrace_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 405static int 406profiler_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 463static int 464pending_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 477static 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 487static 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 496static 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 503static 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 510typedef struct { 511 PyObject *list; 512 PyObject *sublist; 513 double factor; 514 _lsprof_state *state; 515} statscollector_t; 516 517static 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 538static 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 583list of profiler_entry objects. 584 585getstats() -> list of profiler_entry objects 586 587Return all information collected by the profiler. 588Each profiler_entry is a tuple-like object with the 589following 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 598The calls attribute is either None or a list of 599profiler_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 608static PyObject * 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 636static int 637setSubcalls(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 646static int 647setBuiltins(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 657PyDoc_STRVAR(enable_doc, "\ 658enable(subcalls=True, builtins=True)\n\ 659\n\ 660Start collecting profiling information.\n\ 661If 'subcalls' is True, also records for each function\n\ 662statistics separated according to its current caller.\n\ 663If 'builtins' is True, records the time spent in\n\ 664built-in functions separately from their caller.\n\ 665"); 666 667static PyObject* 668profiler_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 689static void 690flush_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 705PyDoc_STRVAR(disable_doc, "\ 706disable()\n\ 707\n\ 708Stop collecting profiling information.\n\ 709"); 710 711static PyObject* 712profiler_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 727PyDoc_STRVAR(clear_doc, "\ 728clear()\n\ 729\n\ 730Clear all profiling information collected so far.\n\ 731"); 732 733static PyObject* 734profiler_clear(ProfilerObject *pObj, PyObject* noarg) 735{ 736 clearEntries(pObj); 737 Py_RETURN_NONE; 738} 739 740static int 741profiler_traverse(ProfilerObject *op, visitproc visit, void *arg) 742{ 743 Py_VISIT(Py_TYPE(op)); 744 return 0; 745} 746 747static void 748profiler_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 766static int 767profiler_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 789static 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 800PyDoc_STRVAR(profiler_doc, "\ 801Profiler(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 810static 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 819static 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 827static PyMethodDef moduleMethods[] = { 828 {NULL, NULL} 829}; 830 831static int 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 841static int 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 851static void 852_lsprof_free(void *module) 853{ 854 _lsprof_clear((PyObject *)module); 855} 856 857static int 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 891static PyModuleDef_Slot _lsprofslots[] = { 892 {Py_mod_exec, _lsprof_exec}, 893 {0, NULL} 894}; 895 896static 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 908PyMODINIT_FUNC 909PyInit__lsprof(void) 910{ 911 return PyModuleDef_Init(&_lsprofmodule); 912} 913