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