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