1/* 2 * This is the High Performance Python Profiler portion of HotShot. 3 */ 4 5#include "Python.h" 6#include "code.h" 7#include "eval.h" 8#include "frameobject.h" 9#include "structmember.h" 10 11/* 12 * Which timer to use should be made more configurable, but that should not 13 * be difficult. This will do for now. 14 */ 15#ifdef MS_WINDOWS 16#include <windows.h> 17 18#ifdef HAVE_DIRECT_H 19#include <direct.h> /* for getcwd() */ 20#endif 21 22typedef __int64 hs_time; 23#define GETTIMEOFDAY(P_HS_TIME) \ 24 { LARGE_INTEGER _temp; \ 25 QueryPerformanceCounter(&_temp); \ 26 *(P_HS_TIME) = _temp.QuadPart; } 27 28 29#else 30#ifndef HAVE_GETTIMEOFDAY 31#error "This module requires gettimeofday() on non-Windows platforms!" 32#endif 33#if (defined(PYOS_OS2) && defined(PYCC_GCC)) || defined(__QNX__) 34#include <sys/time.h> 35#else 36#include <sys/resource.h> 37#include <sys/times.h> 38#endif 39typedef struct timeval hs_time; 40#endif 41 42#if !defined(__cplusplus) && !defined(inline) 43#ifdef __GNUC__ 44#define inline __inline 45#endif 46#endif 47 48#ifndef inline 49#define inline 50#endif 51 52#define BUFFERSIZE 10240 53 54#if defined(PYOS_OS2) && defined(PYCC_GCC) 55#define PATH_MAX 260 56#endif 57 58#if defined(__sgi) && _COMPILER_VERSION>700 && !defined(PATH_MAX) 59/* fix PATH_MAX not being defined with MIPSPro 7.x 60 if mode is ANSI C (default) */ 61#define PATH_MAX 1024 62#endif 63 64#ifndef PATH_MAX 65# ifdef MAX_PATH 66# define PATH_MAX MAX_PATH 67# elif defined (_POSIX_PATH_MAX) 68# define PATH_MAX _POSIX_PATH_MAX 69# else 70# error "Need a defn. for PATH_MAX in _hotshot.c" 71# endif 72#endif 73 74typedef struct { 75 PyObject_HEAD 76 PyObject *filemap; 77 PyObject *logfilename; 78 Py_ssize_t index; 79 unsigned char buffer[BUFFERSIZE]; 80 FILE *logfp; 81 int lineevents; 82 int linetimings; 83 int frametimings; 84 /* size_t filled; */ 85 int active; 86 int next_fileno; 87 hs_time prev_timeofday; 88} ProfilerObject; 89 90typedef struct { 91 PyObject_HEAD 92 PyObject *info; 93 FILE *logfp; 94 int linetimings; 95 int frametimings; 96} LogReaderObject; 97 98static PyObject * ProfilerError = NULL; 99 100 101#ifndef MS_WINDOWS 102#ifdef GETTIMEOFDAY_NO_TZ 103#define GETTIMEOFDAY(ptv) gettimeofday((ptv)) 104#else 105#define GETTIMEOFDAY(ptv) gettimeofday((ptv), (struct timezone *)NULL) 106#endif 107#endif 108 109 110/* The log reader... */ 111 112PyDoc_STRVAR(logreader_close__doc__, 113"close()\n" 114"Close the log file, preventing additional records from being read."); 115 116static PyObject * 117logreader_close(LogReaderObject *self, PyObject *args) 118{ 119 if (self->logfp != NULL) { 120 fclose(self->logfp); 121 self->logfp = NULL; 122 } 123 Py_INCREF(Py_None); 124 125 return Py_None; 126} 127 128PyDoc_STRVAR(logreader_fileno__doc__, 129"fileno() -> file descriptor\n" 130"Returns the file descriptor for the log file, if open.\n" 131"Raises ValueError if the log file is closed."); 132 133static PyObject * 134logreader_fileno(LogReaderObject *self) 135{ 136 if (self->logfp == NULL) { 137 PyErr_SetString(PyExc_ValueError, 138 "logreader's file object already closed"); 139 return NULL; 140 } 141 return PyInt_FromLong(fileno(self->logfp)); 142} 143 144 145/* Log File Format 146 * --------------- 147 * 148 * The log file consists of a sequence of variable-length records. 149 * Each record is identified with a record type identifier in two 150 * bits of the first byte. The two bits are the "least significant" 151 * bits of the byte. 152 * 153 * Low bits: Opcode: Meaning: 154 * 0x00 ENTER enter a frame 155 * 0x01 EXIT exit a frame 156 * 0x02 LINENO execution moved onto a different line 157 * 0x03 OTHER more bits are needed to deecode 158 * 159 * If the type is OTHER, the record is not packed so tightly, and the 160 * remaining bits are used to disambiguate the record type. These 161 * records are not used as frequently so compaction is not an issue. 162 * Each of the first three record types has a highly tailored 163 * structure that allows it to be packed tightly. 164 * 165 * The OTHER records have the following identifiers: 166 * 167 * First byte: Opcode: Meaning: 168 * 0x13 ADD_INFO define a key/value pair 169 * 0x23 DEFINE_FILE define an int->filename mapping 170 * 0x33 LINE_TIMES indicates if LINENO events have tdeltas 171 * 0x43 DEFINE_FUNC define a (fileno,lineno)->funcname mapping 172 * 0x53 FRAME_TIMES indicates if ENTER/EXIT events have tdeltas 173 * 174 * Packed Integers 175 * 176 * "Packed integers" are non-negative integer values encoded as a 177 * sequence of bytes. Each byte is encoded such that the most 178 * significant bit is set if the next byte is also part of the 179 * integer. Each byte provides bits to the least-significant end of 180 * the result; the accumulated value must be shifted up to place the 181 * new bits into the result. 182 * 183 * "Modified packed integers" are packed integers where only a portion 184 * of the first byte is used. In the rest of the specification, these 185 * are referred to as "MPI(n,name)", where "n" is the number of bits 186 * discarded from the least-signicant positions of the byte, and 187 * "name" is a name being given to those "discarded" bits, since they 188 * are a field themselves. 189 * 190 * ENTER records: 191 * 192 * MPI(2,type) fileno -- type is 0x00 193 * PI lineno 194 * PI tdelta -- iff frame times are enabled 195 * 196 * EXIT records 197 * 198 * MPI(2,type) tdelta -- type is 0x01; tdelta will be 0 199 * if frame times are disabled 200 * 201 * LINENO records 202 * 203 * MPI(2,type) lineno -- type is 0x02 204 * PI tdelta -- iff LINENO includes it 205 * 206 * ADD_INFO records 207 * 208 * BYTE type -- always 0x13 209 * PI len1 -- length of first string 210 * BYTE string1[len1] -- len1 bytes of string data 211 * PI len2 -- length of second string 212 * BYTE string2[len2] -- len2 bytes of string data 213 * 214 * DEFINE_FILE records 215 * 216 * BYTE type -- always 0x23 217 * PI fileno 218 * PI len -- length of filename 219 * BYTE filename[len] -- len bytes of string data 220 * 221 * DEFINE_FUNC records 222 * 223 * BYTE type -- always 0x43 224 * PI fileno 225 * PI lineno 226 * PI len -- length of funcname 227 * BYTE funcname[len] -- len bytes of string data 228 * 229 * LINE_TIMES records 230 * 231 * This record can be used only before the start of ENTER/EXIT/LINENO 232 * records. If have_tdelta is true, LINENO records will include the 233 * tdelta field, otherwise it will be omitted. If this record is not 234 * given, LINENO records will not contain the tdelta field. 235 * 236 * BYTE type -- always 0x33 237 * BYTE have_tdelta -- 0 if LINENO does *not* have 238 * timing information 239 * FRAME_TIMES records 240 * 241 * This record can be used only before the start of ENTER/EXIT/LINENO 242 * records. If have_tdelta is true, ENTER and EXIT records will 243 * include the tdelta field, otherwise it will be omitted. If this 244 * record is not given, ENTER and EXIT records will contain the tdelta 245 * field. 246 * 247 * BYTE type -- always 0x53 248 * BYTE have_tdelta -- 0 if ENTER/EXIT do *not* have 249 * timing information 250 */ 251 252#define WHAT_ENTER 0x00 253#define WHAT_EXIT 0x01 254#define WHAT_LINENO 0x02 255#define WHAT_OTHER 0x03 /* only used in decoding */ 256#define WHAT_ADD_INFO 0x13 257#define WHAT_DEFINE_FILE 0x23 258#define WHAT_LINE_TIMES 0x33 259#define WHAT_DEFINE_FUNC 0x43 260#define WHAT_FRAME_TIMES 0x53 261 262#define ERR_NONE 0 263#define ERR_EOF -1 264#define ERR_EXCEPTION -2 265#define ERR_BAD_RECTYPE -3 266 267#define PISIZE (sizeof(int) + 1) 268#define MPISIZE (PISIZE + 1) 269 270/* Maximum size of "normal" events -- nothing that contains string data */ 271#define MAXEVENTSIZE (MPISIZE + PISIZE*2) 272 273 274/* Unpack a packed integer; if "discard" is non-zero, unpack a modified 275 * packed integer with "discard" discarded bits. 276 */ 277static int 278unpack_packed_int(LogReaderObject *self, int *pvalue, int discard) 279{ 280 int c; 281 int accum = 0; 282 int bits = 0; 283 int cont; 284 285 do { 286 /* read byte */ 287 if ((c = fgetc(self->logfp)) == EOF) 288 return ERR_EOF; 289 accum |= ((c & 0x7F) >> discard) << bits; 290 bits += (7 - discard); 291 cont = c & 0x80; 292 discard = 0; 293 } while (cont); 294 295 *pvalue = accum; 296 297 return 0; 298} 299 300/* Unpack a string, which is encoded as a packed integer giving the 301 * length of the string, followed by the string data. 302 */ 303static int 304unpack_string(LogReaderObject *self, PyObject **pvalue) 305{ 306 int i; 307 int len; 308 int err; 309 int ch; 310 char *buf; 311 312 if ((err = unpack_packed_int(self, &len, 0))) 313 return err; 314 315 buf = (char *)malloc(len); 316 if (!buf) { 317 PyErr_NoMemory(); 318 return ERR_EXCEPTION; 319 } 320 321 for (i=0; i < len; i++) { 322 ch = fgetc(self->logfp); 323 buf[i] = ch; 324 if (ch == EOF) { 325 free(buf); 326 return ERR_EOF; 327 } 328 } 329 *pvalue = PyString_FromStringAndSize(buf, len); 330 free(buf); 331 if (*pvalue == NULL) { 332 return ERR_EXCEPTION; 333 } 334 return 0; 335} 336 337 338static int 339unpack_add_info(LogReaderObject *self) 340{ 341 PyObject *key = NULL; 342 PyObject *value = NULL; 343 PyObject *list; 344 int err; 345 346 err = unpack_string(self, &key); 347 if (err) 348 goto finally; 349 err = unpack_string(self, &value); 350 if (err) 351 goto finally; 352 list = PyDict_GetItem(self->info, key); 353 if (list == NULL) { 354 list = PyList_New(0); 355 if (list == NULL) { 356 err = ERR_EXCEPTION; 357 goto finally; 358 } 359 if (PyDict_SetItem(self->info, key, list)) { 360 Py_DECREF(list); 361 err = ERR_EXCEPTION; 362 goto finally; 363 } 364 Py_DECREF(list); 365 } 366 if (PyList_Append(list, value)) 367 err = ERR_EXCEPTION; 368 369 finally: 370 Py_XDECREF(key); 371 Py_XDECREF(value); 372 return err; 373} 374 375 376static void 377eof_error(LogReaderObject *self) 378{ 379 fclose(self->logfp); 380 self->logfp = NULL; 381 PyErr_SetString(PyExc_EOFError, 382 "end of file with incomplete profile record"); 383} 384 385static PyObject * 386logreader_tp_iternext(LogReaderObject *self) 387{ 388 int c; 389 int what; 390 int err = ERR_NONE; 391 int lineno = -1; 392 int fileno = -1; 393 int tdelta = -1; 394 PyObject *s1 = NULL, *s2 = NULL; 395 PyObject *result = NULL; 396#if 0 397 unsigned char b0, b1; 398#endif 399 400 if (self->logfp == NULL) { 401 PyErr_SetString(ProfilerError, 402 "cannot iterate over closed LogReader object"); 403 return NULL; 404 } 405 406restart: 407 /* decode the record type */ 408 if ((c = fgetc(self->logfp)) == EOF) { 409 fclose(self->logfp); 410 self->logfp = NULL; 411 return NULL; 412 } 413 what = c & WHAT_OTHER; 414 if (what == WHAT_OTHER) 415 what = c; /* need all the bits for type */ 416 else 417 ungetc(c, self->logfp); /* type byte includes packed int */ 418 419 switch (what) { 420 case WHAT_ENTER: 421 err = unpack_packed_int(self, &fileno, 2); 422 if (!err) { 423 err = unpack_packed_int(self, &lineno, 0); 424 if (self->frametimings && !err) 425 err = unpack_packed_int(self, &tdelta, 0); 426 } 427 break; 428 case WHAT_EXIT: 429 err = unpack_packed_int(self, &tdelta, 2); 430 break; 431 case WHAT_LINENO: 432 err = unpack_packed_int(self, &lineno, 2); 433 if (self->linetimings && !err) 434 err = unpack_packed_int(self, &tdelta, 0); 435 break; 436 case WHAT_ADD_INFO: 437 err = unpack_add_info(self); 438 break; 439 case WHAT_DEFINE_FILE: 440 err = unpack_packed_int(self, &fileno, 0); 441 if (!err) { 442 err = unpack_string(self, &s1); 443 if (!err) { 444 Py_INCREF(Py_None); 445 s2 = Py_None; 446 } 447 } 448 break; 449 case WHAT_DEFINE_FUNC: 450 err = unpack_packed_int(self, &fileno, 0); 451 if (!err) { 452 err = unpack_packed_int(self, &lineno, 0); 453 if (!err) 454 err = unpack_string(self, &s1); 455 } 456 break; 457 case WHAT_LINE_TIMES: 458 if ((c = fgetc(self->logfp)) == EOF) 459 err = ERR_EOF; 460 else { 461 self->linetimings = c ? 1 : 0; 462 goto restart; 463 } 464 break; 465 case WHAT_FRAME_TIMES: 466 if ((c = fgetc(self->logfp)) == EOF) 467 err = ERR_EOF; 468 else { 469 self->frametimings = c ? 1 : 0; 470 goto restart; 471 } 472 break; 473 default: 474 err = ERR_BAD_RECTYPE; 475 } 476 if (err == ERR_BAD_RECTYPE) { 477 PyErr_SetString(PyExc_ValueError, 478 "unknown record type in log file"); 479 } 480 else if (err == ERR_EOF) { 481 eof_error(self); 482 } 483 else if (!err) { 484 result = PyTuple_New(4); 485 if (result == NULL) 486 return NULL; 487 PyTuple_SET_ITEM(result, 0, PyInt_FromLong(what)); 488 PyTuple_SET_ITEM(result, 2, PyInt_FromLong(fileno)); 489 if (s1 == NULL) 490 PyTuple_SET_ITEM(result, 1, PyInt_FromLong(tdelta)); 491 else 492 PyTuple_SET_ITEM(result, 1, s1); 493 if (s2 == NULL) 494 PyTuple_SET_ITEM(result, 3, PyInt_FromLong(lineno)); 495 else 496 PyTuple_SET_ITEM(result, 3, s2); 497 } 498 /* The only other case is err == ERR_EXCEPTION, in which case the 499 * exception is already set. 500 */ 501#if 0 502 b0 = self->buffer[self->index]; 503 b1 = self->buffer[self->index + 1]; 504 if (b0 & 1) { 505 /* This is a line-number event. */ 506 what = PyTrace_LINE; 507 lineno = ((b0 & ~1) << 7) + b1; 508 self->index += 2; 509 } 510 else { 511 what = (b0 & 0x0E) >> 1; 512 tdelta = ((b0 & 0xF0) << 4) + b1; 513 if (what == PyTrace_CALL) { 514 /* we know there's a 2-byte file ID & 2-byte line number */ 515 fileno = ((self->buffer[self->index + 2] << 8) 516 + self->buffer[self->index + 3]); 517 lineno = ((self->buffer[self->index + 4] << 8) 518 + self->buffer[self->index + 5]); 519 self->index += 6; 520 } 521 else 522 self->index += 2; 523 } 524#endif 525 return result; 526} 527 528static void 529logreader_dealloc(LogReaderObject *self) 530{ 531 if (self->logfp != NULL) { 532 fclose(self->logfp); 533 self->logfp = NULL; 534 } 535 Py_XDECREF(self->info); 536 PyObject_Del(self); 537} 538 539static PyObject * 540logreader_sq_item(LogReaderObject *self, Py_ssize_t index) 541{ 542 PyObject *result = logreader_tp_iternext(self); 543 if (result == NULL && !PyErr_Occurred()) { 544 PyErr_SetString(PyExc_IndexError, "no more events in log"); 545 return NULL; 546 } 547 return result; 548} 549 550static void 551do_stop(ProfilerObject *self); 552 553static int 554flush_data(ProfilerObject *self) 555{ 556 /* Need to dump data to the log file... */ 557 size_t written = fwrite(self->buffer, 1, self->index, self->logfp); 558 if (written == (size_t)self->index) 559 self->index = 0; 560 else { 561 memmove(self->buffer, &self->buffer[written], 562 self->index - written); 563 self->index -= written; 564 if (written == 0) { 565 char *s = PyString_AsString(self->logfilename); 566 PyErr_SetFromErrnoWithFilename(PyExc_IOError, s); 567 do_stop(self); 568 return -1; 569 } 570 } 571 if (written > 0) { 572 if (fflush(self->logfp)) { 573 char *s = PyString_AsString(self->logfilename); 574 PyErr_SetFromErrnoWithFilename(PyExc_IOError, s); 575 do_stop(self); 576 return -1; 577 } 578 } 579 return 0; 580} 581 582static inline int 583pack_packed_int(ProfilerObject *self, int value) 584{ 585 unsigned char partial; 586 587 do { 588 partial = value & 0x7F; 589 value >>= 7; 590 if (value) 591 partial |= 0x80; 592 self->buffer[self->index] = partial; 593 self->index++; 594 } while (value); 595 return 0; 596} 597 598/* Encode a modified packed integer, with a subfield of modsize bits 599 * containing the value "subfield". The value of subfield is not 600 * checked to ensure it actually fits in modsize bits. 601 */ 602static inline int 603pack_modified_packed_int(ProfilerObject *self, int value, 604 int modsize, int subfield) 605{ 606 const int maxvalues[] = {-1, 1, 3, 7, 15, 31, 63, 127}; 607 608 int bits = 7 - modsize; 609 int partial = value & maxvalues[bits]; 610 unsigned char b = subfield | (partial << modsize); 611 612 if (partial != value) { 613 b |= 0x80; 614 self->buffer[self->index] = b; 615 self->index++; 616 return pack_packed_int(self, value >> bits); 617 } 618 self->buffer[self->index] = b; 619 self->index++; 620 return 0; 621} 622 623static int 624pack_string(ProfilerObject *self, const char *s, Py_ssize_t len) 625{ 626 if (len + PISIZE + self->index >= BUFFERSIZE) { 627 if (flush_data(self) < 0) 628 return -1; 629 if (len + PISIZE + self->index >= BUFFERSIZE) { 630 PyErr_SetString(PyExc_ValueError, "string too large for internal buffer"); 631 return -1; 632 } 633 } 634 assert(len < INT_MAX); 635 if (pack_packed_int(self, (int)len) < 0) 636 return -1; 637 memcpy(self->buffer + self->index, s, len); 638 self->index += len; 639 return 0; 640} 641 642static int 643pack_add_info(ProfilerObject *self, const char *s1, const char *s2) 644{ 645 Py_ssize_t len1 = strlen(s1); 646 Py_ssize_t len2 = strlen(s2); 647 648 if (len1 + len2 + PISIZE*2 + 1 + self->index >= BUFFERSIZE) { 649 if (flush_data(self) < 0) 650 return -1; 651 } 652 self->buffer[self->index] = WHAT_ADD_INFO; 653 self->index++; 654 if (pack_string(self, s1, len1) < 0) 655 return -1; 656 return pack_string(self, s2, len2); 657} 658 659static int 660pack_define_file(ProfilerObject *self, int fileno, const char *filename) 661{ 662 Py_ssize_t len = strlen(filename); 663 664 if (len + PISIZE*2 + 1 + self->index >= BUFFERSIZE) { 665 if (flush_data(self) < 0) 666 return -1; 667 } 668 self->buffer[self->index] = WHAT_DEFINE_FILE; 669 self->index++; 670 if (pack_packed_int(self, fileno) < 0) 671 return -1; 672 return pack_string(self, filename, len); 673} 674 675static int 676pack_define_func(ProfilerObject *self, int fileno, int lineno, 677 const char *funcname) 678{ 679 Py_ssize_t len = strlen(funcname); 680 681 if (len + PISIZE*3 + 1 + self->index >= BUFFERSIZE) { 682 if (flush_data(self) < 0) 683 return -1; 684 } 685 self->buffer[self->index] = WHAT_DEFINE_FUNC; 686 self->index++; 687 if (pack_packed_int(self, fileno) < 0) 688 return -1; 689 if (pack_packed_int(self, lineno) < 0) 690 return -1; 691 return pack_string(self, funcname, len); 692} 693 694static int 695pack_line_times(ProfilerObject *self) 696{ 697 if (2 + self->index >= BUFFERSIZE) { 698 if (flush_data(self) < 0) 699 return -1; 700 } 701 self->buffer[self->index] = WHAT_LINE_TIMES; 702 self->buffer[self->index + 1] = self->linetimings ? 1 : 0; 703 self->index += 2; 704 return 0; 705} 706 707static int 708pack_frame_times(ProfilerObject *self) 709{ 710 if (2 + self->index >= BUFFERSIZE) { 711 if (flush_data(self) < 0) 712 return -1; 713 } 714 self->buffer[self->index] = WHAT_FRAME_TIMES; 715 self->buffer[self->index + 1] = self->frametimings ? 1 : 0; 716 self->index += 2; 717 return 0; 718} 719 720static inline int 721pack_enter(ProfilerObject *self, int fileno, int tdelta, int lineno) 722{ 723 if (MPISIZE + PISIZE*2 + self->index >= BUFFERSIZE) { 724 if (flush_data(self) < 0) 725 return -1; 726 } 727 pack_modified_packed_int(self, fileno, 2, WHAT_ENTER); 728 pack_packed_int(self, lineno); 729 if (self->frametimings) 730 return pack_packed_int(self, tdelta); 731 else 732 return 0; 733} 734 735static inline int 736pack_exit(ProfilerObject *self, int tdelta) 737{ 738 if (MPISIZE + self->index >= BUFFERSIZE) { 739 if (flush_data(self) < 0) 740 return -1; 741 } 742 if (self->frametimings) 743 return pack_modified_packed_int(self, tdelta, 2, WHAT_EXIT); 744 self->buffer[self->index] = WHAT_EXIT; 745 self->index++; 746 return 0; 747} 748 749static inline int 750pack_lineno(ProfilerObject *self, int lineno) 751{ 752 if (MPISIZE + self->index >= BUFFERSIZE) { 753 if (flush_data(self) < 0) 754 return -1; 755 } 756 return pack_modified_packed_int(self, lineno, 2, WHAT_LINENO); 757} 758 759static inline int 760pack_lineno_tdelta(ProfilerObject *self, int lineno, int tdelta) 761{ 762 if (MPISIZE + PISIZE + self->index >= BUFFERSIZE) { 763 if (flush_data(self) < 0) 764 return 0; 765 } 766 if (pack_modified_packed_int(self, lineno, 2, WHAT_LINENO) < 0) 767 return -1; 768 return pack_packed_int(self, tdelta); 769} 770 771static inline int 772get_fileno(ProfilerObject *self, PyCodeObject *fcode) 773{ 774 /* This is only used for ENTER events. */ 775 776 PyObject *obj; 777 PyObject *dict; 778 int fileno; 779 780 obj = PyDict_GetItem(self->filemap, fcode->co_filename); 781 if (obj == NULL) { 782 /* first sighting of this file */ 783 dict = PyDict_New(); 784 if (dict == NULL) { 785 return -1; 786 } 787 fileno = self->next_fileno; 788 obj = Py_BuildValue("iN", fileno, dict); 789 if (obj == NULL) { 790 return -1; 791 } 792 if (PyDict_SetItem(self->filemap, fcode->co_filename, obj)) { 793 Py_DECREF(obj); 794 return -1; 795 } 796 self->next_fileno++; 797 Py_DECREF(obj); 798 if (pack_define_file(self, fileno, 799 PyString_AS_STRING(fcode->co_filename)) < 0) 800 return -1; 801 } 802 else { 803 /* already know this ID */ 804 fileno = PyInt_AS_LONG(PyTuple_GET_ITEM(obj, 0)); 805 dict = PyTuple_GET_ITEM(obj, 1); 806 } 807 /* make sure we save a function name for this (fileno, lineno) */ 808 obj = PyInt_FromLong(fcode->co_firstlineno); 809 if (obj == NULL) { 810 /* We just won't have it saved; too bad. */ 811 PyErr_Clear(); 812 } 813 else { 814 PyObject *name = PyDict_GetItem(dict, obj); 815 if (name == NULL) { 816 if (pack_define_func(self, fileno, fcode->co_firstlineno, 817 PyString_AS_STRING(fcode->co_name)) < 0) { 818 Py_DECREF(obj); 819 return -1; 820 } 821 if (PyDict_SetItem(dict, obj, fcode->co_name)) { 822 Py_DECREF(obj); 823 return -1; 824 } 825 } 826 Py_DECREF(obj); 827 } 828 return fileno; 829} 830 831static inline int 832get_tdelta(ProfilerObject *self) 833{ 834 int tdelta; 835#ifdef MS_WINDOWS 836 hs_time tv; 837 hs_time diff; 838 839 GETTIMEOFDAY(&tv); 840 diff = tv - self->prev_timeofday; 841 tdelta = (int)diff; 842#else 843 struct timeval tv; 844 845 GETTIMEOFDAY(&tv); 846 847 tdelta = tv.tv_usec - self->prev_timeofday.tv_usec; 848 if (tv.tv_sec != self->prev_timeofday.tv_sec) 849 tdelta += (tv.tv_sec - self->prev_timeofday.tv_sec) * 1000000; 850#endif 851 /* time can go backwards on some multiprocessor systems or by NTP */ 852 if (tdelta < 0) 853 return 0; 854 855 self->prev_timeofday = tv; 856 return tdelta; 857} 858 859 860/* The workhorse: the profiler callback function. */ 861 862static int 863tracer_callback(ProfilerObject *self, PyFrameObject *frame, int what, 864 PyObject *arg) 865{ 866 int fileno; 867 868 switch (what) { 869 case PyTrace_CALL: 870 fileno = get_fileno(self, frame->f_code); 871 if (fileno < 0) 872 return -1; 873 return pack_enter(self, fileno, 874 self->frametimings ? get_tdelta(self) : -1, 875 frame->f_code->co_firstlineno); 876 877 case PyTrace_RETURN: 878 return pack_exit(self, get_tdelta(self)); 879 880 case PyTrace_LINE: /* we only get these events if we asked for them */ 881 if (self->linetimings) 882 return pack_lineno_tdelta(self, frame->f_lineno, 883 get_tdelta(self)); 884 else 885 return pack_lineno(self, frame->f_lineno); 886 887 default: 888 /* ignore PyTrace_EXCEPTION */ 889 break; 890 } 891 return 0; 892} 893 894 895/* A couple of useful helper functions. */ 896 897#ifdef MS_WINDOWS 898static LARGE_INTEGER frequency = {0, 0}; 899#endif 900 901static unsigned long timeofday_diff = 0; 902static unsigned long rusage_diff = 0; 903 904static void 905calibrate(void) 906{ 907 hs_time tv1, tv2; 908 909#ifdef MS_WINDOWS 910 hs_time diff; 911 QueryPerformanceFrequency(&frequency); 912#endif 913 914 GETTIMEOFDAY(&tv1); 915 while (1) { 916 GETTIMEOFDAY(&tv2); 917#ifdef MS_WINDOWS 918 diff = tv2 - tv1; 919 if (diff != 0) { 920 timeofday_diff = (unsigned long)diff; 921 break; 922 } 923#else 924 if (tv1.tv_sec != tv2.tv_sec || tv1.tv_usec != tv2.tv_usec) { 925 if (tv1.tv_sec == tv2.tv_sec) 926 timeofday_diff = tv2.tv_usec - tv1.tv_usec; 927 else 928 timeofday_diff = (1000000 - tv1.tv_usec) + tv2.tv_usec; 929 break; 930 } 931#endif 932 } 933#if defined(MS_WINDOWS) || defined(PYOS_OS2) || \ 934 defined(__VMS) || defined (__QNX__) 935 rusage_diff = -1; 936#else 937 { 938 struct rusage ru1, ru2; 939 940 getrusage(RUSAGE_SELF, &ru1); 941 while (1) { 942 getrusage(RUSAGE_SELF, &ru2); 943 if (ru1.ru_utime.tv_sec != ru2.ru_utime.tv_sec) { 944 rusage_diff = ((1000000 - ru1.ru_utime.tv_usec) 945 + ru2.ru_utime.tv_usec); 946 break; 947 } 948 else if (ru1.ru_utime.tv_usec != ru2.ru_utime.tv_usec) { 949 rusage_diff = ru2.ru_utime.tv_usec - ru1.ru_utime.tv_usec; 950 break; 951 } 952 else if (ru1.ru_stime.tv_sec != ru2.ru_stime.tv_sec) { 953 rusage_diff = ((1000000 - ru1.ru_stime.tv_usec) 954 + ru2.ru_stime.tv_usec); 955 break; 956 } 957 else if (ru1.ru_stime.tv_usec != ru2.ru_stime.tv_usec) { 958 rusage_diff = ru2.ru_stime.tv_usec - ru1.ru_stime.tv_usec; 959 break; 960 } 961 } 962 } 963#endif 964} 965 966static void 967do_start(ProfilerObject *self) 968{ 969 self->active = 1; 970 GETTIMEOFDAY(&self->prev_timeofday); 971 if (self->lineevents) 972 PyEval_SetTrace((Py_tracefunc) tracer_callback, (PyObject *)self); 973 else 974 PyEval_SetProfile((Py_tracefunc) tracer_callback, (PyObject *)self); 975} 976 977static void 978do_stop(ProfilerObject *self) 979{ 980 if (self->active) { 981 self->active = 0; 982 if (self->lineevents) 983 PyEval_SetTrace(NULL, NULL); 984 else 985 PyEval_SetProfile(NULL, NULL); 986 } 987 if (self->index > 0) { 988 /* Best effort to dump out any remaining data. */ 989 flush_data(self); 990 } 991} 992 993static int 994is_available(ProfilerObject *self) 995{ 996 if (self->active) { 997 PyErr_SetString(ProfilerError, "profiler already active"); 998 return 0; 999 } 1000 if (self->logfp == NULL) { 1001 PyErr_SetString(ProfilerError, "profiler already closed"); 1002 return 0; 1003 } 1004 return 1; 1005} 1006 1007 1008/* Profiler object interface methods. */ 1009 1010PyDoc_STRVAR(addinfo__doc__, 1011"addinfo(key, value)\n" 1012"Insert an ADD_INFO record into the log."); 1013 1014static PyObject * 1015profiler_addinfo(ProfilerObject *self, PyObject *args) 1016{ 1017 PyObject *result = NULL; 1018 char *key, *value; 1019 1020 if (PyArg_ParseTuple(args, "ss:addinfo", &key, &value)) { 1021 if (self->logfp == NULL) 1022 PyErr_SetString(ProfilerError, "profiler already closed"); 1023 else { 1024 if (pack_add_info(self, key, value) == 0) { 1025 result = Py_None; 1026 Py_INCREF(result); 1027 } 1028 } 1029 } 1030 return result; 1031} 1032 1033PyDoc_STRVAR(close__doc__, 1034"close()\n" 1035"Shut down this profiler and close the log files, even if its active."); 1036 1037static PyObject * 1038profiler_close(ProfilerObject *self) 1039{ 1040 do_stop(self); 1041 if (self->logfp != NULL) { 1042 fclose(self->logfp); 1043 self->logfp = NULL; 1044 } 1045 Py_INCREF(Py_None); 1046 return Py_None; 1047} 1048 1049#define fileno__doc__ logreader_fileno__doc__ 1050 1051static PyObject * 1052profiler_fileno(ProfilerObject *self) 1053{ 1054 if (self->logfp == NULL) { 1055 PyErr_SetString(PyExc_ValueError, 1056 "profiler's file object already closed"); 1057 return NULL; 1058 } 1059 return PyInt_FromLong(fileno(self->logfp)); 1060} 1061 1062PyDoc_STRVAR(runcall__doc__, 1063"runcall(callable[, args[, kw]]) -> callable()\n" 1064"Profile a specific function call, returning the result of that call."); 1065 1066static PyObject * 1067profiler_runcall(ProfilerObject *self, PyObject *args) 1068{ 1069 PyObject *result = NULL; 1070 PyObject *callargs = NULL; 1071 PyObject *callkw = NULL; 1072 PyObject *callable; 1073 1074 if (PyArg_UnpackTuple(args, "runcall", 1, 3, 1075 &callable, &callargs, &callkw)) { 1076 if (is_available(self)) { 1077 do_start(self); 1078 result = PyEval_CallObjectWithKeywords(callable, callargs, callkw); 1079 do_stop(self); 1080 } 1081 } 1082 return result; 1083} 1084 1085PyDoc_STRVAR(runcode__doc__, 1086"runcode(code, globals[, locals])\n" 1087"Execute a code object while collecting profile data. If locals is\n" 1088"omitted, globals is used for the locals as well."); 1089 1090static PyObject * 1091profiler_runcode(ProfilerObject *self, PyObject *args) 1092{ 1093 PyObject *result = NULL; 1094 PyCodeObject *code; 1095 PyObject *globals; 1096 PyObject *locals = NULL; 1097 1098 if (PyArg_ParseTuple(args, "O!O!|O:runcode", 1099 &PyCode_Type, &code, 1100 &PyDict_Type, &globals, 1101 &locals)) { 1102 if (is_available(self)) { 1103 if (locals == NULL || locals == Py_None) 1104 locals = globals; 1105 else if (!PyDict_Check(locals)) { 1106 PyErr_SetString(PyExc_TypeError, 1107 "locals must be a dictionary or None"); 1108 return NULL; 1109 } 1110 do_start(self); 1111 result = PyEval_EvalCode(code, globals, locals); 1112 do_stop(self); 1113#if 0 1114 if (!PyErr_Occurred()) { 1115 result = Py_None; 1116 Py_INCREF(result); 1117 } 1118#endif 1119 } 1120 } 1121 return result; 1122} 1123 1124PyDoc_STRVAR(start__doc__, 1125"start()\n" 1126"Install this profiler for the current thread."); 1127 1128static PyObject * 1129profiler_start(ProfilerObject *self, PyObject *args) 1130{ 1131 PyObject *result = NULL; 1132 1133 if (is_available(self)) { 1134 do_start(self); 1135 result = Py_None; 1136 Py_INCREF(result); 1137 } 1138 return result; 1139} 1140 1141PyDoc_STRVAR(stop__doc__, 1142"stop()\n" 1143"Remove this profiler from the current thread."); 1144 1145static PyObject * 1146profiler_stop(ProfilerObject *self, PyObject *args) 1147{ 1148 PyObject *result = NULL; 1149 1150 if (!self->active) 1151 PyErr_SetString(ProfilerError, "profiler not active"); 1152 else { 1153 do_stop(self); 1154 result = Py_None; 1155 Py_INCREF(result); 1156 } 1157 return result; 1158} 1159 1160 1161/* Python API support. */ 1162 1163static void 1164profiler_dealloc(ProfilerObject *self) 1165{ 1166 do_stop(self); 1167 if (self->logfp != NULL) 1168 fclose(self->logfp); 1169 Py_XDECREF(self->filemap); 1170 Py_XDECREF(self->logfilename); 1171 PyObject_Del((PyObject *)self); 1172} 1173 1174static PyMethodDef profiler_methods[] = { 1175 {"addinfo", (PyCFunction)profiler_addinfo, METH_VARARGS, addinfo__doc__}, 1176 {"close", (PyCFunction)profiler_close, METH_NOARGS, close__doc__}, 1177 {"fileno", (PyCFunction)profiler_fileno, METH_NOARGS, fileno__doc__}, 1178 {"runcall", (PyCFunction)profiler_runcall, METH_VARARGS, runcall__doc__}, 1179 {"runcode", (PyCFunction)profiler_runcode, METH_VARARGS, runcode__doc__}, 1180 {"start", (PyCFunction)profiler_start, METH_NOARGS, start__doc__}, 1181 {"stop", (PyCFunction)profiler_stop, METH_NOARGS, stop__doc__}, 1182 {NULL, NULL} 1183}; 1184 1185static PyMemberDef profiler_members[] = { 1186 {"frametimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY}, 1187 {"lineevents", T_LONG, offsetof(ProfilerObject, lineevents), READONLY}, 1188 {"linetimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY}, 1189 {NULL} 1190}; 1191 1192static PyObject * 1193profiler_get_closed(ProfilerObject *self, void *closure) 1194{ 1195 PyObject *result = (self->logfp == NULL) ? Py_True : Py_False; 1196 Py_INCREF(result); 1197 return result; 1198} 1199 1200static PyGetSetDef profiler_getsets[] = { 1201 {"closed", (getter)profiler_get_closed, NULL, 1202 PyDoc_STR("True if the profiler's output file has already been closed.")}, 1203 {NULL} 1204}; 1205 1206 1207PyDoc_STRVAR(profiler_object__doc__, 1208"High-performance profiler object.\n" 1209"\n" 1210"Methods:\n" 1211"\n" 1212"close(): Stop the profiler and close the log files.\n" 1213"fileno(): Returns the file descriptor of the log file.\n" 1214"runcall(): Run a single function call with profiling enabled.\n" 1215"runcode(): Execute a code object with profiling enabled.\n" 1216"start(): Install the profiler and return.\n" 1217"stop(): Remove the profiler.\n" 1218"\n" 1219"Attributes (read-only):\n" 1220"\n" 1221"closed: True if the profiler has already been closed.\n" 1222"frametimings: True if ENTER/EXIT events collect timing information.\n" 1223"lineevents: True if line events are reported to the profiler.\n" 1224"linetimings: True if line events collect timing information."); 1225 1226static PyTypeObject ProfilerType = { 1227 PyVarObject_HEAD_INIT(NULL, 0) 1228 "_hotshot.ProfilerType", /* tp_name */ 1229 (int) sizeof(ProfilerObject), /* tp_basicsize */ 1230 0, /* tp_itemsize */ 1231 (destructor)profiler_dealloc, /* tp_dealloc */ 1232 0, /* tp_print */ 1233 0, /* tp_getattr */ 1234 0, /* tp_setattr */ 1235 0, /* tp_compare */ 1236 0, /* tp_repr */ 1237 0, /* tp_as_number */ 1238 0, /* tp_as_sequence */ 1239 0, /* tp_as_mapping */ 1240 0, /* tp_hash */ 1241 0, /* tp_call */ 1242 0, /* tp_str */ 1243 PyObject_GenericGetAttr, /* tp_getattro */ 1244 0, /* tp_setattro */ 1245 0, /* tp_as_buffer */ 1246 Py_TPFLAGS_DEFAULT, /* tp_flags */ 1247 profiler_object__doc__, /* tp_doc */ 1248 0, /* tp_traverse */ 1249 0, /* tp_clear */ 1250 0, /* tp_richcompare */ 1251 0, /* tp_weaklistoffset */ 1252 0, /* tp_iter */ 1253 0, /* tp_iternext */ 1254 profiler_methods, /* tp_methods */ 1255 profiler_members, /* tp_members */ 1256 profiler_getsets, /* tp_getset */ 1257 0, /* tp_base */ 1258 0, /* tp_dict */ 1259 0, /* tp_descr_get */ 1260 0, /* tp_descr_set */ 1261}; 1262 1263 1264static PyMethodDef logreader_methods[] = { 1265 {"close", (PyCFunction)logreader_close, METH_NOARGS, 1266 logreader_close__doc__}, 1267 {"fileno", (PyCFunction)logreader_fileno, METH_NOARGS, 1268 logreader_fileno__doc__}, 1269 {NULL, NULL} 1270}; 1271 1272static PyMemberDef logreader_members[] = { 1273 {"info", T_OBJECT, offsetof(LogReaderObject, info), RO, 1274 PyDoc_STR("Dictionary mapping informational keys to lists of values.")}, 1275 {NULL} 1276}; 1277 1278 1279PyDoc_STRVAR(logreader__doc__, 1280"logreader(filename) --> log-iterator\n\ 1281Create a log-reader for the timing information file."); 1282 1283static PySequenceMethods logreader_as_sequence = { 1284 0, /* sq_length */ 1285 0, /* sq_concat */ 1286 0, /* sq_repeat */ 1287 (ssizeargfunc)logreader_sq_item, /* sq_item */ 1288 0, /* sq_slice */ 1289 0, /* sq_ass_item */ 1290 0, /* sq_ass_slice */ 1291 0, /* sq_contains */ 1292 0, /* sq_inplace_concat */ 1293 0, /* sq_inplace_repeat */ 1294}; 1295 1296static PyObject * 1297logreader_get_closed(LogReaderObject *self, void *closure) 1298{ 1299 PyObject *result = (self->logfp == NULL) ? Py_True : Py_False; 1300 Py_INCREF(result); 1301 return result; 1302} 1303 1304static PyGetSetDef logreader_getsets[] = { 1305 {"closed", (getter)logreader_get_closed, NULL, 1306 PyDoc_STR("True if the logreader's input file has already been closed.")}, 1307 {NULL} 1308}; 1309 1310static PyTypeObject LogReaderType = { 1311 PyVarObject_HEAD_INIT(NULL, 0) 1312 "_hotshot.LogReaderType", /* tp_name */ 1313 (int) sizeof(LogReaderObject), /* tp_basicsize */ 1314 0, /* tp_itemsize */ 1315 (destructor)logreader_dealloc, /* tp_dealloc */ 1316 0, /* tp_print */ 1317 0, /* tp_getattr */ 1318 0, /* tp_setattr */ 1319 0, /* tp_compare */ 1320 0, /* tp_repr */ 1321 0, /* tp_as_number */ 1322 &logreader_as_sequence, /* tp_as_sequence */ 1323 0, /* tp_as_mapping */ 1324 0, /* tp_hash */ 1325 0, /* tp_call */ 1326 0, /* tp_str */ 1327 PyObject_GenericGetAttr, /* tp_getattro */ 1328 0, /* tp_setattro */ 1329 0, /* tp_as_buffer */ 1330 Py_TPFLAGS_DEFAULT, /* tp_flags */ 1331 logreader__doc__, /* tp_doc */ 1332 0, /* tp_traverse */ 1333 0, /* tp_clear */ 1334 0, /* tp_richcompare */ 1335 0, /* tp_weaklistoffset */ 1336 PyObject_SelfIter, /* tp_iter */ 1337 (iternextfunc)logreader_tp_iternext,/* tp_iternext */ 1338 logreader_methods, /* tp_methods */ 1339 logreader_members, /* tp_members */ 1340 logreader_getsets, /* tp_getset */ 1341 0, /* tp_base */ 1342 0, /* tp_dict */ 1343 0, /* tp_descr_get */ 1344 0, /* tp_descr_set */ 1345}; 1346 1347static PyObject * 1348hotshot_logreader(PyObject *unused, PyObject *args) 1349{ 1350 LogReaderObject *self = NULL; 1351 char *filename; 1352 int c; 1353 int err = 0; 1354 1355 if (PyArg_ParseTuple(args, "s:logreader", &filename)) { 1356 self = PyObject_New(LogReaderObject, &LogReaderType); 1357 if (self != NULL) { 1358 self->frametimings = 1; 1359 self->linetimings = 0; 1360 self->info = NULL; 1361 self->logfp = fopen(filename, "rb"); 1362 if (self->logfp == NULL) { 1363 PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); 1364 goto error; 1365 } 1366 self->info = PyDict_New(); 1367 if (self->info == NULL) 1368 goto error; 1369 /* read initial info */ 1370 for (;;) { 1371 if ((c = fgetc(self->logfp)) == EOF) { 1372 eof_error(self); 1373 goto error; 1374 } 1375 if (c != WHAT_ADD_INFO) { 1376 ungetc(c, self->logfp); 1377 break; 1378 } 1379 err = unpack_add_info(self); 1380 if (err) { 1381 if (err == ERR_EOF) 1382 eof_error(self); 1383 else 1384 PyErr_SetString(PyExc_RuntimeError, 1385 "unexpected error"); 1386 goto error; 1387 } 1388 } 1389 } 1390 } 1391 return (PyObject *) self; 1392 error: 1393 Py_DECREF(self); 1394 return NULL; 1395} 1396 1397 1398/* Return a Python string that represents the version number without the 1399 * extra cruft added by revision control, even if the right options were 1400 * given to the "cvs export" command to make it not include the extra 1401 * cruft. 1402 */ 1403static char * 1404get_version_string(void) 1405{ 1406 static char *rcsid = "$Revision$"; 1407 char *rev = rcsid; 1408 char *buffer; 1409 int i = 0; 1410 1411 while (*rev && !isdigit(Py_CHARMASK(*rev))) 1412 ++rev; 1413 while (rev[i] != ' ' && rev[i] != '\0') 1414 ++i; 1415 buffer = (char *)malloc(i + 1); 1416 if (buffer != NULL) { 1417 memmove(buffer, rev, i); 1418 buffer[i] = '\0'; 1419 } 1420 return buffer; 1421} 1422 1423/* Write out a RFC 822-style header with various useful bits of 1424 * information to make the output easier to manage. 1425 */ 1426static int 1427write_header(ProfilerObject *self) 1428{ 1429 char *buffer; 1430 char cwdbuffer[PATH_MAX]; 1431 PyObject *temp; 1432 Py_ssize_t i, len; 1433 1434 buffer = get_version_string(); 1435 if (buffer == NULL) { 1436 PyErr_NoMemory(); 1437 return -1; 1438 } 1439 pack_add_info(self, "hotshot-version", buffer); 1440 pack_add_info(self, "requested-frame-timings", 1441 (self->frametimings ? "yes" : "no")); 1442 pack_add_info(self, "requested-line-events", 1443 (self->lineevents ? "yes" : "no")); 1444 pack_add_info(self, "requested-line-timings", 1445 (self->linetimings ? "yes" : "no")); 1446 pack_add_info(self, "platform", Py_GetPlatform()); 1447 pack_add_info(self, "executable", Py_GetProgramFullPath()); 1448 free(buffer); 1449 buffer = (char *) Py_GetVersion(); 1450 if (buffer == NULL) 1451 PyErr_Clear(); 1452 else 1453 pack_add_info(self, "executable-version", buffer); 1454 1455#ifdef MS_WINDOWS 1456 PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%I64d", frequency.QuadPart); 1457 pack_add_info(self, "reported-performance-frequency", cwdbuffer); 1458#else 1459 PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", rusage_diff); 1460 pack_add_info(self, "observed-interval-getrusage", cwdbuffer); 1461 PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", timeofday_diff); 1462 pack_add_info(self, "observed-interval-gettimeofday", cwdbuffer); 1463#endif 1464 1465 pack_add_info(self, "current-directory", 1466 getcwd(cwdbuffer, sizeof cwdbuffer)); 1467 1468 temp = PySys_GetObject("path"); 1469 if (temp == NULL || !PyList_Check(temp)) { 1470 PyErr_SetString(PyExc_RuntimeError, "sys.path must be a list"); 1471 return -1; 1472 } 1473 len = PyList_GET_SIZE(temp); 1474 for (i = 0; i < len; ++i) { 1475 PyObject *item = PyList_GET_ITEM(temp, i); 1476 buffer = PyString_AsString(item); 1477 if (buffer == NULL) { 1478 pack_add_info(self, "sys-path-entry", "<non-string-path-entry>"); 1479 PyErr_Clear(); 1480 } 1481 else { 1482 pack_add_info(self, "sys-path-entry", buffer); 1483 } 1484 } 1485 pack_frame_times(self); 1486 pack_line_times(self); 1487 1488 return 0; 1489} 1490 1491PyDoc_STRVAR(profiler__doc__, 1492"profiler(logfilename[, lineevents[, linetimes]]) -> profiler\n\ 1493Create a new profiler object."); 1494 1495static PyObject * 1496hotshot_profiler(PyObject *unused, PyObject *args) 1497{ 1498 char *logfilename; 1499 ProfilerObject *self = NULL; 1500 int lineevents = 0; 1501 int linetimings = 1; 1502 1503 if (PyArg_ParseTuple(args, "s|ii:profiler", &logfilename, 1504 &lineevents, &linetimings)) { 1505 self = PyObject_New(ProfilerObject, &ProfilerType); 1506 if (self == NULL) 1507 return NULL; 1508 self->frametimings = 1; 1509 self->lineevents = lineevents ? 1 : 0; 1510 self->linetimings = (lineevents && linetimings) ? 1 : 0; 1511 self->index = 0; 1512 self->active = 0; 1513 self->next_fileno = 0; 1514 self->logfp = NULL; 1515 self->logfilename = PyTuple_GET_ITEM(args, 0); 1516 Py_INCREF(self->logfilename); 1517 self->filemap = PyDict_New(); 1518 if (self->filemap == NULL) { 1519 Py_DECREF(self); 1520 return NULL; 1521 } 1522 self->logfp = fopen(logfilename, "wb"); 1523 if (self->logfp == NULL) { 1524 Py_DECREF(self); 1525 PyErr_SetFromErrnoWithFilename(PyExc_IOError, logfilename); 1526 return NULL; 1527 } 1528 if (timeofday_diff == 0) { 1529 /* Run this several times since sometimes the first 1530 * doesn't give the lowest values, and we're really trying 1531 * to determine the lowest. 1532 */ 1533 calibrate(); 1534 calibrate(); 1535 calibrate(); 1536 } 1537 if (write_header(self)) { 1538 /* some error occurred, exception has been set */ 1539 Py_DECREF(self); 1540 self = NULL; 1541 } 1542 } 1543 return (PyObject *) self; 1544} 1545 1546PyDoc_STRVAR(coverage__doc__, 1547"coverage(logfilename) -> profiler\n\ 1548Returns a profiler that doesn't collect any timing information, which is\n\ 1549useful in building a coverage analysis tool."); 1550 1551static PyObject * 1552hotshot_coverage(PyObject *unused, PyObject *args) 1553{ 1554 char *logfilename; 1555 PyObject *result = NULL; 1556 1557 if (PyArg_ParseTuple(args, "s:coverage", &logfilename)) { 1558 result = hotshot_profiler(unused, args); 1559 if (result != NULL) { 1560 ProfilerObject *self = (ProfilerObject *) result; 1561 self->frametimings = 0; 1562 self->linetimings = 0; 1563 self->lineevents = 1; 1564 } 1565 } 1566 return result; 1567} 1568 1569PyDoc_VAR(resolution__doc__) = 1570#ifdef MS_WINDOWS 1571PyDoc_STR( 1572"resolution() -> (performance-counter-ticks, update-frequency)\n" 1573"Return the resolution of the timer provided by the QueryPerformanceCounter()\n" 1574"function. The first value is the smallest observed change, and the second\n" 1575"is the result of QueryPerformanceFrequency()." 1576) 1577#else 1578PyDoc_STR( 1579"resolution() -> (gettimeofday-usecs, getrusage-usecs)\n" 1580"Return the resolution of the timers provided by the gettimeofday() and\n" 1581"getrusage() system calls, or -1 if the call is not supported." 1582) 1583#endif 1584; 1585 1586static PyObject * 1587hotshot_resolution(PyObject *self, PyObject *unused) 1588{ 1589 if (timeofday_diff == 0) { 1590 calibrate(); 1591 calibrate(); 1592 calibrate(); 1593 } 1594#ifdef MS_WINDOWS 1595 return Py_BuildValue("ii", timeofday_diff, frequency.LowPart); 1596#else 1597 return Py_BuildValue("ii", timeofday_diff, rusage_diff); 1598#endif 1599} 1600 1601 1602static PyMethodDef functions[] = { 1603 {"coverage", hotshot_coverage, METH_VARARGS, coverage__doc__}, 1604 {"profiler", hotshot_profiler, METH_VARARGS, profiler__doc__}, 1605 {"logreader", hotshot_logreader, METH_VARARGS, logreader__doc__}, 1606 {"resolution", hotshot_resolution, METH_NOARGS, resolution__doc__}, 1607 {NULL, NULL} 1608}; 1609 1610 1611void 1612init_hotshot(void) 1613{ 1614 PyObject *module; 1615 1616 Py_TYPE(&LogReaderType) = &PyType_Type; 1617 Py_TYPE(&ProfilerType) = &PyType_Type; 1618 module = Py_InitModule("_hotshot", functions); 1619 if (module != NULL) { 1620 char *s = get_version_string(); 1621 1622 PyModule_AddStringConstant(module, "__version__", s); 1623 free(s); 1624 Py_INCREF(&LogReaderType); 1625 PyModule_AddObject(module, "LogReaderType", 1626 (PyObject *)&LogReaderType); 1627 Py_INCREF(&ProfilerType); 1628 PyModule_AddObject(module, "ProfilerType", 1629 (PyObject *)&ProfilerType); 1630 1631 if (ProfilerError == NULL) 1632 ProfilerError = PyErr_NewException("hotshot.ProfilerError", 1633 NULL, NULL); 1634 if (ProfilerError != NULL) { 1635 Py_INCREF(ProfilerError); 1636 PyModule_AddObject(module, "ProfilerError", ProfilerError); 1637 } 1638 PyModule_AddIntConstant(module, "WHAT_ENTER", WHAT_ENTER); 1639 PyModule_AddIntConstant(module, "WHAT_EXIT", WHAT_EXIT); 1640 PyModule_AddIntConstant(module, "WHAT_LINENO", WHAT_LINENO); 1641 PyModule_AddIntConstant(module, "WHAT_OTHER", WHAT_OTHER); 1642 PyModule_AddIntConstant(module, "WHAT_ADD_INFO", WHAT_ADD_INFO); 1643 PyModule_AddIntConstant(module, "WHAT_DEFINE_FILE", WHAT_DEFINE_FILE); 1644 PyModule_AddIntConstant(module, "WHAT_DEFINE_FUNC", WHAT_DEFINE_FUNC); 1645 PyModule_AddIntConstant(module, "WHAT_LINE_TIMES", WHAT_LINE_TIMES); 1646 } 1647} 1648