Home | History | Annotate | Download | only in Modules
      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 
     22 typedef __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
     39 typedef 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 
     74 typedef 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 
     90 typedef struct {
     91     PyObject_HEAD
     92     PyObject *info;
     93     FILE *logfp;
     94     int linetimings;
     95     int frametimings;
     96 } LogReaderObject;
     97 
     98 static 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 
    112 PyDoc_STRVAR(logreader_close__doc__,
    113 "close()\n"
    114 "Close the log file, preventing additional records from being read.");
    115 
    116 static PyObject *
    117 logreader_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 
    128 PyDoc_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 
    133 static PyObject *
    134 logreader_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  */
    277 static int
    278 unpack_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  */
    303 static int
    304 unpack_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 
    338 static int
    339 unpack_add_info(LogReaderObject *self)
    340 {
    341     PyObject *key;
    342     PyObject *value = NULL;
    343     int err;
    344 
    345     err = unpack_string(self, &key);
    346     if (!err) {
    347         err = unpack_string(self, &value);
    348         if (err)
    349             Py_DECREF(key);
    350         else {
    351             PyObject *list = PyDict_GetItem(self->info, key);
    352             if (list == NULL) {
    353                 list = PyList_New(0);
    354                 if (list == NULL) {
    355                     err = ERR_EXCEPTION;
    356                     goto finally;
    357                 }
    358                 if (PyDict_SetItem(self->info, key, list)) {
    359                     Py_DECREF(list);
    360                     err = ERR_EXCEPTION;
    361                     goto finally;
    362                 }
    363                 Py_DECREF(list);
    364             }
    365             if (PyList_Append(list, value))
    366                 err = ERR_EXCEPTION;
    367         }
    368     }
    369  finally:
    370     Py_XDECREF(key);
    371     Py_XDECREF(value);
    372     return err;
    373 }
    374 
    375 
    376 static void
    377 eof_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 
    385 static PyObject *
    386 logreader_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 
    406 restart:
    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 
    528 static void
    529 logreader_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 
    539 static PyObject *
    540 logreader_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 
    550 static void
    551 do_stop(ProfilerObject *self);
    552 
    553 static int
    554 flush_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 
    582 static inline int
    583 pack_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  */
    602 static inline int
    603 pack_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 
    623 static int
    624 pack_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     }
    630     assert(len < INT_MAX);
    631     if (pack_packed_int(self, (int)len) < 0)
    632         return -1;
    633     memcpy(self->buffer + self->index, s, len);
    634     self->index += len;
    635     return 0;
    636 }
    637 
    638 static int
    639 pack_add_info(ProfilerObject *self, const char *s1, const char *s2)
    640 {
    641     Py_ssize_t len1 = strlen(s1);
    642     Py_ssize_t len2 = strlen(s2);
    643 
    644     if (len1 + len2 + PISIZE*2 + 1 + self->index >= BUFFERSIZE) {
    645         if (flush_data(self) < 0)
    646             return -1;
    647     }
    648     self->buffer[self->index] = WHAT_ADD_INFO;
    649     self->index++;
    650     if (pack_string(self, s1, len1) < 0)
    651         return -1;
    652     return pack_string(self, s2, len2);
    653 }
    654 
    655 static int
    656 pack_define_file(ProfilerObject *self, int fileno, const char *filename)
    657 {
    658     Py_ssize_t len = strlen(filename);
    659 
    660     if (len + PISIZE*2 + 1 + self->index >= BUFFERSIZE) {
    661         if (flush_data(self) < 0)
    662             return -1;
    663     }
    664     self->buffer[self->index] = WHAT_DEFINE_FILE;
    665     self->index++;
    666     if (pack_packed_int(self, fileno) < 0)
    667         return -1;
    668     return pack_string(self, filename, len);
    669 }
    670 
    671 static int
    672 pack_define_func(ProfilerObject *self, int fileno, int lineno,
    673                  const char *funcname)
    674 {
    675     Py_ssize_t len = strlen(funcname);
    676 
    677     if (len + PISIZE*3 + 1 + self->index >= BUFFERSIZE) {
    678         if (flush_data(self) < 0)
    679             return -1;
    680     }
    681     self->buffer[self->index] = WHAT_DEFINE_FUNC;
    682     self->index++;
    683     if (pack_packed_int(self, fileno) < 0)
    684         return -1;
    685     if (pack_packed_int(self, lineno) < 0)
    686         return -1;
    687     return pack_string(self, funcname, len);
    688 }
    689 
    690 static int
    691 pack_line_times(ProfilerObject *self)
    692 {
    693     if (2 + self->index >= BUFFERSIZE) {
    694         if (flush_data(self) < 0)
    695             return -1;
    696     }
    697     self->buffer[self->index] = WHAT_LINE_TIMES;
    698     self->buffer[self->index + 1] = self->linetimings ? 1 : 0;
    699     self->index += 2;
    700     return 0;
    701 }
    702 
    703 static int
    704 pack_frame_times(ProfilerObject *self)
    705 {
    706     if (2 + self->index >= BUFFERSIZE) {
    707         if (flush_data(self) < 0)
    708             return -1;
    709     }
    710     self->buffer[self->index] = WHAT_FRAME_TIMES;
    711     self->buffer[self->index + 1] = self->frametimings ? 1 : 0;
    712     self->index += 2;
    713     return 0;
    714 }
    715 
    716 static inline int
    717 pack_enter(ProfilerObject *self, int fileno, int tdelta, int lineno)
    718 {
    719     if (MPISIZE + PISIZE*2 + self->index >= BUFFERSIZE) {
    720         if (flush_data(self) < 0)
    721             return -1;
    722     }
    723     pack_modified_packed_int(self, fileno, 2, WHAT_ENTER);
    724     pack_packed_int(self, lineno);
    725     if (self->frametimings)
    726         return pack_packed_int(self, tdelta);
    727     else
    728         return 0;
    729 }
    730 
    731 static inline int
    732 pack_exit(ProfilerObject *self, int tdelta)
    733 {
    734     if (MPISIZE + self->index >= BUFFERSIZE) {
    735         if (flush_data(self) < 0)
    736             return -1;
    737     }
    738     if (self->frametimings)
    739         return pack_modified_packed_int(self, tdelta, 2, WHAT_EXIT);
    740     self->buffer[self->index] = WHAT_EXIT;
    741     self->index++;
    742     return 0;
    743 }
    744 
    745 static inline int
    746 pack_lineno(ProfilerObject *self, int lineno)
    747 {
    748     if (MPISIZE + self->index >= BUFFERSIZE) {
    749         if (flush_data(self) < 0)
    750             return -1;
    751     }
    752     return pack_modified_packed_int(self, lineno, 2, WHAT_LINENO);
    753 }
    754 
    755 static inline int
    756 pack_lineno_tdelta(ProfilerObject *self, int lineno, int tdelta)
    757 {
    758     if (MPISIZE + PISIZE + self->index >= BUFFERSIZE) {
    759         if (flush_data(self) < 0)
    760             return 0;
    761     }
    762     if (pack_modified_packed_int(self, lineno, 2, WHAT_LINENO) < 0)
    763         return -1;
    764     return pack_packed_int(self, tdelta);
    765 }
    766 
    767 static inline int
    768 get_fileno(ProfilerObject *self, PyCodeObject *fcode)
    769 {
    770     /* This is only used for ENTER events. */
    771 
    772     PyObject *obj;
    773     PyObject *dict;
    774     int fileno;
    775 
    776     obj = PyDict_GetItem(self->filemap, fcode->co_filename);
    777     if (obj == NULL) {
    778         /* first sighting of this file */
    779         dict = PyDict_New();
    780         if (dict == NULL) {
    781             return -1;
    782         }
    783         fileno = self->next_fileno;
    784         obj = Py_BuildValue("iN", fileno, dict);
    785         if (obj == NULL) {
    786             return -1;
    787         }
    788         if (PyDict_SetItem(self->filemap, fcode->co_filename, obj)) {
    789             Py_DECREF(obj);
    790             return -1;
    791         }
    792         self->next_fileno++;
    793         Py_DECREF(obj);
    794         if (pack_define_file(self, fileno,
    795                              PyString_AS_STRING(fcode->co_filename)) < 0)
    796             return -1;
    797     }
    798     else {
    799         /* already know this ID */
    800         fileno = PyInt_AS_LONG(PyTuple_GET_ITEM(obj, 0));
    801         dict = PyTuple_GET_ITEM(obj, 1);
    802     }
    803     /* make sure we save a function name for this (fileno, lineno) */
    804     obj = PyInt_FromLong(fcode->co_firstlineno);
    805     if (obj == NULL) {
    806         /* We just won't have it saved; too bad. */
    807         PyErr_Clear();
    808     }
    809     else {
    810         PyObject *name = PyDict_GetItem(dict, obj);
    811         if (name == NULL) {
    812             if (pack_define_func(self, fileno, fcode->co_firstlineno,
    813                                  PyString_AS_STRING(fcode->co_name)) < 0) {
    814                 Py_DECREF(obj);
    815                 return -1;
    816             }
    817             if (PyDict_SetItem(dict, obj, fcode->co_name)) {
    818                 Py_DECREF(obj);
    819                 return -1;
    820             }
    821         }
    822         Py_DECREF(obj);
    823     }
    824     return fileno;
    825 }
    826 
    827 static inline int
    828 get_tdelta(ProfilerObject *self)
    829 {
    830     int tdelta;
    831 #ifdef MS_WINDOWS
    832     hs_time tv;
    833     hs_time diff;
    834 
    835     GETTIMEOFDAY(&tv);
    836     diff = tv - self->prev_timeofday;
    837     tdelta = (int)diff;
    838 #else
    839     struct timeval tv;
    840 
    841     GETTIMEOFDAY(&tv);
    842 
    843     tdelta = tv.tv_usec - self->prev_timeofday.tv_usec;
    844     if (tv.tv_sec != self->prev_timeofday.tv_sec)
    845         tdelta += (tv.tv_sec - self->prev_timeofday.tv_sec) * 1000000;
    846 #endif
    847     /* time can go backwards on some multiprocessor systems or by NTP */
    848     if (tdelta < 0)
    849         return 0;
    850 
    851     self->prev_timeofday = tv;
    852     return tdelta;
    853 }
    854 
    855 
    856 /* The workhorse:  the profiler callback function. */
    857 
    858 static int
    859 tracer_callback(ProfilerObject *self, PyFrameObject *frame, int what,
    860                 PyObject *arg)
    861 {
    862     int fileno;
    863 
    864     switch (what) {
    865     case PyTrace_CALL:
    866         fileno = get_fileno(self, frame->f_code);
    867         if (fileno < 0)
    868             return -1;
    869         return pack_enter(self, fileno,
    870                           self->frametimings ? get_tdelta(self) : -1,
    871                           frame->f_code->co_firstlineno);
    872 
    873     case PyTrace_RETURN:
    874         return pack_exit(self, get_tdelta(self));
    875 
    876     case PyTrace_LINE:  /* we only get these events if we asked for them */
    877         if (self->linetimings)
    878             return pack_lineno_tdelta(self, frame->f_lineno,
    879                                       get_tdelta(self));
    880         else
    881             return pack_lineno(self, frame->f_lineno);
    882 
    883     default:
    884         /* ignore PyTrace_EXCEPTION */
    885         break;
    886     }
    887     return 0;
    888 }
    889 
    890 
    891 /* A couple of useful helper functions. */
    892 
    893 #ifdef MS_WINDOWS
    894 static LARGE_INTEGER frequency = {0, 0};
    895 #endif
    896 
    897 static unsigned long timeofday_diff = 0;
    898 static unsigned long rusage_diff = 0;
    899 
    900 static void
    901 calibrate(void)
    902 {
    903     hs_time tv1, tv2;
    904 
    905 #ifdef MS_WINDOWS
    906     hs_time diff;
    907     QueryPerformanceFrequency(&frequency);
    908 #endif
    909 
    910     GETTIMEOFDAY(&tv1);
    911     while (1) {
    912         GETTIMEOFDAY(&tv2);
    913 #ifdef MS_WINDOWS
    914         diff = tv2 - tv1;
    915         if (diff != 0) {
    916             timeofday_diff = (unsigned long)diff;
    917             break;
    918         }
    919 #else
    920         if (tv1.tv_sec != tv2.tv_sec || tv1.tv_usec != tv2.tv_usec) {
    921             if (tv1.tv_sec == tv2.tv_sec)
    922                 timeofday_diff = tv2.tv_usec - tv1.tv_usec;
    923             else
    924                 timeofday_diff = (1000000 - tv1.tv_usec) + tv2.tv_usec;
    925             break;
    926         }
    927 #endif
    928     }
    929 #if defined(MS_WINDOWS) || defined(PYOS_OS2) || \
    930     defined(__VMS) || defined (__QNX__)
    931     rusage_diff = -1;
    932 #else
    933     {
    934         struct rusage ru1, ru2;
    935 
    936         getrusage(RUSAGE_SELF, &ru1);
    937         while (1) {
    938             getrusage(RUSAGE_SELF, &ru2);
    939             if (ru1.ru_utime.tv_sec != ru2.ru_utime.tv_sec) {
    940                 rusage_diff = ((1000000 - ru1.ru_utime.tv_usec)
    941                                + ru2.ru_utime.tv_usec);
    942                 break;
    943             }
    944             else if (ru1.ru_utime.tv_usec != ru2.ru_utime.tv_usec) {
    945                 rusage_diff = ru2.ru_utime.tv_usec - ru1.ru_utime.tv_usec;
    946                 break;
    947             }
    948             else if (ru1.ru_stime.tv_sec != ru2.ru_stime.tv_sec) {
    949                 rusage_diff = ((1000000 - ru1.ru_stime.tv_usec)
    950                                + ru2.ru_stime.tv_usec);
    951                 break;
    952             }
    953             else if (ru1.ru_stime.tv_usec != ru2.ru_stime.tv_usec) {
    954                 rusage_diff = ru2.ru_stime.tv_usec - ru1.ru_stime.tv_usec;
    955                 break;
    956             }
    957         }
    958     }
    959 #endif
    960 }
    961 
    962 static void
    963 do_start(ProfilerObject *self)
    964 {
    965     self->active = 1;
    966     GETTIMEOFDAY(&self->prev_timeofday);
    967     if (self->lineevents)
    968         PyEval_SetTrace((Py_tracefunc) tracer_callback, (PyObject *)self);
    969     else
    970         PyEval_SetProfile((Py_tracefunc) tracer_callback, (PyObject *)self);
    971 }
    972 
    973 static void
    974 do_stop(ProfilerObject *self)
    975 {
    976     if (self->active) {
    977         self->active = 0;
    978         if (self->lineevents)
    979             PyEval_SetTrace(NULL, NULL);
    980         else
    981             PyEval_SetProfile(NULL, NULL);
    982     }
    983     if (self->index > 0) {
    984         /* Best effort to dump out any remaining data. */
    985         flush_data(self);
    986     }
    987 }
    988 
    989 static int
    990 is_available(ProfilerObject *self)
    991 {
    992     if (self->active) {
    993         PyErr_SetString(ProfilerError, "profiler already active");
    994         return 0;
    995     }
    996     if (self->logfp == NULL) {
    997         PyErr_SetString(ProfilerError, "profiler already closed");
    998         return 0;
    999     }
   1000     return 1;
   1001 }
   1002 
   1003 
   1004 /* Profiler object interface methods. */
   1005 
   1006 PyDoc_STRVAR(addinfo__doc__,
   1007 "addinfo(key, value)\n"
   1008 "Insert an ADD_INFO record into the log.");
   1009 
   1010 static PyObject *
   1011 profiler_addinfo(ProfilerObject *self, PyObject *args)
   1012 {
   1013     PyObject *result = NULL;
   1014     char *key, *value;
   1015 
   1016     if (PyArg_ParseTuple(args, "ss:addinfo", &key, &value)) {
   1017         if (self->logfp == NULL)
   1018             PyErr_SetString(ProfilerError, "profiler already closed");
   1019         else {
   1020             if (pack_add_info(self, key, value) == 0) {
   1021                 result = Py_None;
   1022                 Py_INCREF(result);
   1023             }
   1024         }
   1025     }
   1026     return result;
   1027 }
   1028 
   1029 PyDoc_STRVAR(close__doc__,
   1030 "close()\n"
   1031 "Shut down this profiler and close the log files, even if its active.");
   1032 
   1033 static PyObject *
   1034 profiler_close(ProfilerObject *self)
   1035 {
   1036     do_stop(self);
   1037     if (self->logfp != NULL) {
   1038         fclose(self->logfp);
   1039         self->logfp = NULL;
   1040     }
   1041     Py_INCREF(Py_None);
   1042     return Py_None;
   1043 }
   1044 
   1045 #define fileno__doc__ logreader_fileno__doc__
   1046 
   1047 static PyObject *
   1048 profiler_fileno(ProfilerObject *self)
   1049 {
   1050     if (self->logfp == NULL) {
   1051         PyErr_SetString(PyExc_ValueError,
   1052                         "profiler's file object already closed");
   1053         return NULL;
   1054     }
   1055     return PyInt_FromLong(fileno(self->logfp));
   1056 }
   1057 
   1058 PyDoc_STRVAR(runcall__doc__,
   1059 "runcall(callable[, args[, kw]]) -> callable()\n"
   1060 "Profile a specific function call, returning the result of that call.");
   1061 
   1062 static PyObject *
   1063 profiler_runcall(ProfilerObject *self, PyObject *args)
   1064 {
   1065     PyObject *result = NULL;
   1066     PyObject *callargs = NULL;
   1067     PyObject *callkw = NULL;
   1068     PyObject *callable;
   1069 
   1070     if (PyArg_UnpackTuple(args, "runcall", 1, 3,
   1071                          &callable, &callargs, &callkw)) {
   1072         if (is_available(self)) {
   1073             do_start(self);
   1074             result = PyEval_CallObjectWithKeywords(callable, callargs, callkw);
   1075             do_stop(self);
   1076         }
   1077     }
   1078     return result;
   1079 }
   1080 
   1081 PyDoc_STRVAR(runcode__doc__,
   1082 "runcode(code, globals[, locals])\n"
   1083 "Execute a code object while collecting profile data.  If locals is\n"
   1084 "omitted, globals is used for the locals as well.");
   1085 
   1086 static PyObject *
   1087 profiler_runcode(ProfilerObject *self, PyObject *args)
   1088 {
   1089     PyObject *result = NULL;
   1090     PyCodeObject *code;
   1091     PyObject *globals;
   1092     PyObject *locals = NULL;
   1093 
   1094     if (PyArg_ParseTuple(args, "O!O!|O:runcode",
   1095                          &PyCode_Type, &code,
   1096                          &PyDict_Type, &globals,
   1097                          &locals)) {
   1098         if (is_available(self)) {
   1099             if (locals == NULL || locals == Py_None)
   1100                 locals = globals;
   1101             else if (!PyDict_Check(locals)) {
   1102                 PyErr_SetString(PyExc_TypeError,
   1103                                 "locals must be a dictionary or None");
   1104                 return NULL;
   1105             }
   1106             do_start(self);
   1107             result = PyEval_EvalCode(code, globals, locals);
   1108             do_stop(self);
   1109 #if 0
   1110             if (!PyErr_Occurred()) {
   1111                 result = Py_None;
   1112                 Py_INCREF(result);
   1113             }
   1114 #endif
   1115         }
   1116     }
   1117     return result;
   1118 }
   1119 
   1120 PyDoc_STRVAR(start__doc__,
   1121 "start()\n"
   1122 "Install this profiler for the current thread.");
   1123 
   1124 static PyObject *
   1125 profiler_start(ProfilerObject *self, PyObject *args)
   1126 {
   1127     PyObject *result = NULL;
   1128 
   1129     if (is_available(self)) {
   1130         do_start(self);
   1131         result = Py_None;
   1132         Py_INCREF(result);
   1133     }
   1134     return result;
   1135 }
   1136 
   1137 PyDoc_STRVAR(stop__doc__,
   1138 "stop()\n"
   1139 "Remove this profiler from the current thread.");
   1140 
   1141 static PyObject *
   1142 profiler_stop(ProfilerObject *self, PyObject *args)
   1143 {
   1144     PyObject *result = NULL;
   1145 
   1146     if (!self->active)
   1147         PyErr_SetString(ProfilerError, "profiler not active");
   1148     else {
   1149         do_stop(self);
   1150         result = Py_None;
   1151         Py_INCREF(result);
   1152     }
   1153     return result;
   1154 }
   1155 
   1156 
   1157 /* Python API support. */
   1158 
   1159 static void
   1160 profiler_dealloc(ProfilerObject *self)
   1161 {
   1162     do_stop(self);
   1163     if (self->logfp != NULL)
   1164         fclose(self->logfp);
   1165     Py_XDECREF(self->filemap);
   1166     Py_XDECREF(self->logfilename);
   1167     PyObject_Del((PyObject *)self);
   1168 }
   1169 
   1170 static PyMethodDef profiler_methods[] = {
   1171     {"addinfo", (PyCFunction)profiler_addinfo, METH_VARARGS, addinfo__doc__},
   1172     {"close",   (PyCFunction)profiler_close,   METH_NOARGS,  close__doc__},
   1173     {"fileno",  (PyCFunction)profiler_fileno,  METH_NOARGS,  fileno__doc__},
   1174     {"runcall", (PyCFunction)profiler_runcall, METH_VARARGS, runcall__doc__},
   1175     {"runcode", (PyCFunction)profiler_runcode, METH_VARARGS, runcode__doc__},
   1176     {"start",   (PyCFunction)profiler_start,   METH_NOARGS,  start__doc__},
   1177     {"stop",    (PyCFunction)profiler_stop,    METH_NOARGS,  stop__doc__},
   1178     {NULL, NULL}
   1179 };
   1180 
   1181 static PyMemberDef profiler_members[] = {
   1182     {"frametimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
   1183     {"lineevents",   T_LONG, offsetof(ProfilerObject, lineevents), READONLY},
   1184     {"linetimings",  T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
   1185     {NULL}
   1186 };
   1187 
   1188 static PyObject *
   1189 profiler_get_closed(ProfilerObject *self, void *closure)
   1190 {
   1191     PyObject *result = (self->logfp == NULL) ? Py_True : Py_False;
   1192     Py_INCREF(result);
   1193     return result;
   1194 }
   1195 
   1196 static PyGetSetDef profiler_getsets[] = {
   1197     {"closed", (getter)profiler_get_closed, NULL,
   1198      PyDoc_STR("True if the profiler's output file has already been closed.")},
   1199     {NULL}
   1200 };
   1201 
   1202 
   1203 PyDoc_STRVAR(profiler_object__doc__,
   1204 "High-performance profiler object.\n"
   1205 "\n"
   1206 "Methods:\n"
   1207 "\n"
   1208 "close():      Stop the profiler and close the log files.\n"
   1209 "fileno():     Returns the file descriptor of the log file.\n"
   1210 "runcall():    Run a single function call with profiling enabled.\n"
   1211 "runcode():    Execute a code object with profiling enabled.\n"
   1212 "start():      Install the profiler and return.\n"
   1213 "stop():       Remove the profiler.\n"
   1214 "\n"
   1215 "Attributes (read-only):\n"
   1216 "\n"
   1217 "closed:       True if the profiler has already been closed.\n"
   1218 "frametimings: True if ENTER/EXIT events collect timing information.\n"
   1219 "lineevents:   True if line events are reported to the profiler.\n"
   1220 "linetimings:  True if line events collect timing information.");
   1221 
   1222 static PyTypeObject ProfilerType = {
   1223     PyVarObject_HEAD_INIT(NULL, 0)
   1224     "_hotshot.ProfilerType",            /* tp_name              */
   1225     (int) sizeof(ProfilerObject),       /* tp_basicsize         */
   1226     0,                                  /* tp_itemsize          */
   1227     (destructor)profiler_dealloc,       /* tp_dealloc           */
   1228     0,                                  /* tp_print             */
   1229     0,                                  /* tp_getattr           */
   1230     0,                                  /* tp_setattr           */
   1231     0,                                  /* tp_compare           */
   1232     0,                                  /* tp_repr              */
   1233     0,                                  /* tp_as_number         */
   1234     0,                                  /* tp_as_sequence       */
   1235     0,                                  /* tp_as_mapping        */
   1236     0,                                  /* tp_hash              */
   1237     0,                                  /* tp_call              */
   1238     0,                                  /* tp_str               */
   1239     PyObject_GenericGetAttr,            /* tp_getattro          */
   1240     0,                                  /* tp_setattro          */
   1241     0,                                  /* tp_as_buffer         */
   1242     Py_TPFLAGS_DEFAULT,                 /* tp_flags             */
   1243     profiler_object__doc__,             /* tp_doc               */
   1244     0,                                  /* tp_traverse          */
   1245     0,                                  /* tp_clear             */
   1246     0,                                  /* tp_richcompare       */
   1247     0,                                  /* tp_weaklistoffset    */
   1248     0,                                  /* tp_iter              */
   1249     0,                                  /* tp_iternext          */
   1250     profiler_methods,                   /* tp_methods           */
   1251     profiler_members,                   /* tp_members           */
   1252     profiler_getsets,                   /* tp_getset            */
   1253     0,                                  /* tp_base              */
   1254     0,                                  /* tp_dict              */
   1255     0,                                  /* tp_descr_get         */
   1256     0,                                  /* tp_descr_set         */
   1257 };
   1258 
   1259 
   1260 static PyMethodDef logreader_methods[] = {
   1261     {"close",   (PyCFunction)logreader_close,  METH_NOARGS,
   1262      logreader_close__doc__},
   1263     {"fileno",  (PyCFunction)logreader_fileno, METH_NOARGS,
   1264      logreader_fileno__doc__},
   1265     {NULL, NULL}
   1266 };
   1267 
   1268 static PyMemberDef logreader_members[] = {
   1269     {"info", T_OBJECT, offsetof(LogReaderObject, info), RO,
   1270      PyDoc_STR("Dictionary mapping informational keys to lists of values.")},
   1271     {NULL}
   1272 };
   1273 
   1274 
   1275 PyDoc_STRVAR(logreader__doc__,
   1276 "logreader(filename) --> log-iterator\n\
   1277 Create a log-reader for the timing information file.");
   1278 
   1279 static PySequenceMethods logreader_as_sequence = {
   1280     0,                                  /* sq_length */
   1281     0,                                  /* sq_concat */
   1282     0,                                  /* sq_repeat */
   1283     (ssizeargfunc)logreader_sq_item,    /* sq_item */
   1284     0,                                  /* sq_slice */
   1285     0,                                  /* sq_ass_item */
   1286     0,                                  /* sq_ass_slice */
   1287     0,                                  /* sq_contains */
   1288     0,                                  /* sq_inplace_concat */
   1289     0,                                  /* sq_inplace_repeat */
   1290 };
   1291 
   1292 static PyObject *
   1293 logreader_get_closed(LogReaderObject *self, void *closure)
   1294 {
   1295     PyObject *result = (self->logfp == NULL) ? Py_True : Py_False;
   1296     Py_INCREF(result);
   1297     return result;
   1298 }
   1299 
   1300 static PyGetSetDef logreader_getsets[] = {
   1301     {"closed", (getter)logreader_get_closed, NULL,
   1302      PyDoc_STR("True if the logreader's input file has already been closed.")},
   1303     {NULL}
   1304 };
   1305 
   1306 static PyTypeObject LogReaderType = {
   1307     PyVarObject_HEAD_INIT(NULL, 0)
   1308     "_hotshot.LogReaderType",           /* tp_name              */
   1309     (int) sizeof(LogReaderObject),      /* tp_basicsize         */
   1310     0,                                  /* tp_itemsize          */
   1311     (destructor)logreader_dealloc,      /* tp_dealloc           */
   1312     0,                                  /* tp_print             */
   1313     0,                                  /* tp_getattr           */
   1314     0,                                  /* tp_setattr           */
   1315     0,                                  /* tp_compare           */
   1316     0,                                  /* tp_repr              */
   1317     0,                                  /* tp_as_number         */
   1318     &logreader_as_sequence,             /* tp_as_sequence       */
   1319     0,                                  /* tp_as_mapping        */
   1320     0,                                  /* tp_hash              */
   1321     0,                                  /* tp_call              */
   1322     0,                                  /* tp_str               */
   1323     PyObject_GenericGetAttr,            /* tp_getattro          */
   1324     0,                                  /* tp_setattro          */
   1325     0,                                  /* tp_as_buffer         */
   1326     Py_TPFLAGS_DEFAULT,                 /* tp_flags             */
   1327     logreader__doc__,                   /* tp_doc               */
   1328     0,                                  /* tp_traverse          */
   1329     0,                                  /* tp_clear             */
   1330     0,                                  /* tp_richcompare       */
   1331     0,                                  /* tp_weaklistoffset    */
   1332     PyObject_SelfIter,                  /* tp_iter              */
   1333     (iternextfunc)logreader_tp_iternext,/* tp_iternext          */
   1334     logreader_methods,                  /* tp_methods           */
   1335     logreader_members,                  /* tp_members           */
   1336     logreader_getsets,                  /* tp_getset            */
   1337     0,                                  /* tp_base              */
   1338     0,                                  /* tp_dict              */
   1339     0,                                  /* tp_descr_get         */
   1340     0,                                  /* tp_descr_set         */
   1341 };
   1342 
   1343 static PyObject *
   1344 hotshot_logreader(PyObject *unused, PyObject *args)
   1345 {
   1346     LogReaderObject *self = NULL;
   1347     char *filename;
   1348     int c;
   1349     int err = 0;
   1350 
   1351     if (PyArg_ParseTuple(args, "s:logreader", &filename)) {
   1352         self = PyObject_New(LogReaderObject, &LogReaderType);
   1353         if (self != NULL) {
   1354             self->frametimings = 1;
   1355             self->linetimings = 0;
   1356             self->info = NULL;
   1357             self->logfp = fopen(filename, "rb");
   1358             if (self->logfp == NULL) {
   1359                 PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
   1360                 goto error;
   1361             }
   1362             self->info = PyDict_New();
   1363             if (self->info == NULL)
   1364                 goto error;
   1365             /* read initial info */
   1366             for (;;) {
   1367                 if ((c = fgetc(self->logfp)) == EOF) {
   1368                     eof_error(self);
   1369                     goto error;
   1370                 }
   1371                 if (c != WHAT_ADD_INFO) {
   1372                     ungetc(c, self->logfp);
   1373                     break;
   1374                 }
   1375                 err = unpack_add_info(self);
   1376                 if (err) {
   1377                     if (err == ERR_EOF)
   1378                         eof_error(self);
   1379                     else
   1380                         PyErr_SetString(PyExc_RuntimeError,
   1381                                         "unexpected error");
   1382                     goto error;
   1383                 }
   1384             }
   1385         }
   1386     }
   1387     return (PyObject *) self;
   1388   error:
   1389     Py_DECREF(self);
   1390     return NULL;
   1391 }
   1392 
   1393 
   1394 /* Return a Python string that represents the version number without the
   1395  * extra cruft added by revision control, even if the right options were
   1396  * given to the "cvs export" command to make it not include the extra
   1397  * cruft.
   1398  */
   1399 static char *
   1400 get_version_string(void)
   1401 {
   1402     static char *rcsid = "$Revision$";
   1403     char *rev = rcsid;
   1404     char *buffer;
   1405     int i = 0;
   1406 
   1407     while (*rev && !isdigit(Py_CHARMASK(*rev)))
   1408         ++rev;
   1409     while (rev[i] != ' ' && rev[i] != '\0')
   1410         ++i;
   1411     buffer = (char *)malloc(i + 1);
   1412     if (buffer != NULL) {
   1413         memmove(buffer, rev, i);
   1414         buffer[i] = '\0';
   1415     }
   1416     return buffer;
   1417 }
   1418 
   1419 /* Write out a RFC 822-style header with various useful bits of
   1420  * information to make the output easier to manage.
   1421  */
   1422 static int
   1423 write_header(ProfilerObject *self)
   1424 {
   1425     char *buffer;
   1426     char cwdbuffer[PATH_MAX];
   1427     PyObject *temp;
   1428     Py_ssize_t i, len;
   1429 
   1430     buffer = get_version_string();
   1431     if (buffer == NULL) {
   1432         PyErr_NoMemory();
   1433         return -1;
   1434     }
   1435     pack_add_info(self, "hotshot-version", buffer);
   1436     pack_add_info(self, "requested-frame-timings",
   1437                   (self->frametimings ? "yes" : "no"));
   1438     pack_add_info(self, "requested-line-events",
   1439                   (self->lineevents ? "yes" : "no"));
   1440     pack_add_info(self, "requested-line-timings",
   1441                   (self->linetimings ? "yes" : "no"));
   1442     pack_add_info(self, "platform", Py_GetPlatform());
   1443     pack_add_info(self, "executable", Py_GetProgramFullPath());
   1444     free(buffer);
   1445     buffer = (char *) Py_GetVersion();
   1446     if (buffer == NULL)
   1447         PyErr_Clear();
   1448     else
   1449         pack_add_info(self, "executable-version", buffer);
   1450 
   1451 #ifdef MS_WINDOWS
   1452     PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%I64d", frequency.QuadPart);
   1453     pack_add_info(self, "reported-performance-frequency", cwdbuffer);
   1454 #else
   1455     PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", rusage_diff);
   1456     pack_add_info(self, "observed-interval-getrusage", cwdbuffer);
   1457     PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", timeofday_diff);
   1458     pack_add_info(self, "observed-interval-gettimeofday", cwdbuffer);
   1459 #endif
   1460 
   1461     pack_add_info(self, "current-directory",
   1462                   getcwd(cwdbuffer, sizeof cwdbuffer));
   1463 
   1464     temp = PySys_GetObject("path");
   1465     if (temp == NULL || !PyList_Check(temp)) {
   1466         PyErr_SetString(PyExc_RuntimeError, "sys.path must be a list");
   1467         return -1;
   1468     }
   1469     len = PyList_GET_SIZE(temp);
   1470     for (i = 0; i < len; ++i) {
   1471         PyObject *item = PyList_GET_ITEM(temp, i);
   1472         buffer = PyString_AsString(item);
   1473         if (buffer == NULL) {
   1474             pack_add_info(self, "sys-path-entry", "<non-string-path-entry>");
   1475             PyErr_Clear();
   1476         }
   1477         else {
   1478             pack_add_info(self, "sys-path-entry", buffer);
   1479         }
   1480     }
   1481     pack_frame_times(self);
   1482     pack_line_times(self);
   1483 
   1484     return 0;
   1485 }
   1486 
   1487 PyDoc_STRVAR(profiler__doc__,
   1488 "profiler(logfilename[, lineevents[, linetimes]]) -> profiler\n\
   1489 Create a new profiler object.");
   1490 
   1491 static PyObject *
   1492 hotshot_profiler(PyObject *unused, PyObject *args)
   1493 {
   1494     char *logfilename;
   1495     ProfilerObject *self = NULL;
   1496     int lineevents = 0;
   1497     int linetimings = 1;
   1498 
   1499     if (PyArg_ParseTuple(args, "s|ii:profiler", &logfilename,
   1500                          &lineevents, &linetimings)) {
   1501         self = PyObject_New(ProfilerObject, &ProfilerType);
   1502         if (self == NULL)
   1503             return NULL;
   1504         self->frametimings = 1;
   1505         self->lineevents = lineevents ? 1 : 0;
   1506         self->linetimings = (lineevents && linetimings) ? 1 : 0;
   1507         self->index = 0;
   1508         self->active = 0;
   1509         self->next_fileno = 0;
   1510         self->logfp = NULL;
   1511         self->logfilename = PyTuple_GET_ITEM(args, 0);
   1512         Py_INCREF(self->logfilename);
   1513         self->filemap = PyDict_New();
   1514         if (self->filemap == NULL) {
   1515             Py_DECREF(self);
   1516             return NULL;
   1517         }
   1518         self->logfp = fopen(logfilename, "wb");
   1519         if (self->logfp == NULL) {
   1520             Py_DECREF(self);
   1521             PyErr_SetFromErrnoWithFilename(PyExc_IOError, logfilename);
   1522             return NULL;
   1523         }
   1524         if (timeofday_diff == 0) {
   1525             /* Run this several times since sometimes the first
   1526              * doesn't give the lowest values, and we're really trying
   1527              * to determine the lowest.
   1528              */
   1529             calibrate();
   1530             calibrate();
   1531             calibrate();
   1532         }
   1533         if (write_header(self)) {
   1534             /* some error occurred, exception has been set */
   1535             Py_DECREF(self);
   1536             self = NULL;
   1537         }
   1538     }
   1539     return (PyObject *) self;
   1540 }
   1541 
   1542 PyDoc_STRVAR(coverage__doc__,
   1543 "coverage(logfilename) -> profiler\n\
   1544 Returns a profiler that doesn't collect any timing information, which is\n\
   1545 useful in building a coverage analysis tool.");
   1546 
   1547 static PyObject *
   1548 hotshot_coverage(PyObject *unused, PyObject *args)
   1549 {
   1550     char *logfilename;
   1551     PyObject *result = NULL;
   1552 
   1553     if (PyArg_ParseTuple(args, "s:coverage", &logfilename)) {
   1554         result = hotshot_profiler(unused, args);
   1555         if (result != NULL) {
   1556             ProfilerObject *self = (ProfilerObject *) result;
   1557             self->frametimings = 0;
   1558             self->linetimings = 0;
   1559             self->lineevents = 1;
   1560         }
   1561     }
   1562     return result;
   1563 }
   1564 
   1565 PyDoc_VAR(resolution__doc__) =
   1566 #ifdef MS_WINDOWS
   1567 PyDoc_STR(
   1568 "resolution() -> (performance-counter-ticks, update-frequency)\n"
   1569 "Return the resolution of the timer provided by the QueryPerformanceCounter()\n"
   1570 "function.  The first value is the smallest observed change, and the second\n"
   1571 "is the result of QueryPerformanceFrequency()."
   1572 )
   1573 #else
   1574 PyDoc_STR(
   1575 "resolution() -> (gettimeofday-usecs, getrusage-usecs)\n"
   1576 "Return the resolution of the timers provided by the gettimeofday() and\n"
   1577 "getrusage() system calls, or -1 if the call is not supported."
   1578 )
   1579 #endif
   1580 ;
   1581 
   1582 static PyObject *
   1583 hotshot_resolution(PyObject *self, PyObject *unused)
   1584 {
   1585     if (timeofday_diff == 0) {
   1586         calibrate();
   1587         calibrate();
   1588         calibrate();
   1589     }
   1590 #ifdef MS_WINDOWS
   1591     return Py_BuildValue("ii", timeofday_diff, frequency.LowPart);
   1592 #else
   1593     return Py_BuildValue("ii", timeofday_diff, rusage_diff);
   1594 #endif
   1595 }
   1596 
   1597 
   1598 static PyMethodDef functions[] = {
   1599     {"coverage",   hotshot_coverage,   METH_VARARGS, coverage__doc__},
   1600     {"profiler",   hotshot_profiler,   METH_VARARGS, profiler__doc__},
   1601     {"logreader",  hotshot_logreader,  METH_VARARGS, logreader__doc__},
   1602     {"resolution", hotshot_resolution, METH_NOARGS,  resolution__doc__},
   1603     {NULL, NULL}
   1604 };
   1605 
   1606 
   1607 void
   1608 init_hotshot(void)
   1609 {
   1610     PyObject *module;
   1611 
   1612     Py_TYPE(&LogReaderType) = &PyType_Type;
   1613     Py_TYPE(&ProfilerType) = &PyType_Type;
   1614     module = Py_InitModule("_hotshot", functions);
   1615     if (module != NULL) {
   1616         char *s = get_version_string();
   1617 
   1618         PyModule_AddStringConstant(module, "__version__", s);
   1619         free(s);
   1620         Py_INCREF(&LogReaderType);
   1621         PyModule_AddObject(module, "LogReaderType",
   1622                            (PyObject *)&LogReaderType);
   1623         Py_INCREF(&ProfilerType);
   1624         PyModule_AddObject(module, "ProfilerType",
   1625                            (PyObject *)&ProfilerType);
   1626 
   1627         if (ProfilerError == NULL)
   1628             ProfilerError = PyErr_NewException("hotshot.ProfilerError",
   1629                                                NULL, NULL);
   1630         if (ProfilerError != NULL) {
   1631             Py_INCREF(ProfilerError);
   1632             PyModule_AddObject(module, "ProfilerError", ProfilerError);
   1633         }
   1634         PyModule_AddIntConstant(module, "WHAT_ENTER", WHAT_ENTER);
   1635         PyModule_AddIntConstant(module, "WHAT_EXIT", WHAT_EXIT);
   1636         PyModule_AddIntConstant(module, "WHAT_LINENO", WHAT_LINENO);
   1637         PyModule_AddIntConstant(module, "WHAT_OTHER", WHAT_OTHER);
   1638         PyModule_AddIntConstant(module, "WHAT_ADD_INFO", WHAT_ADD_INFO);
   1639         PyModule_AddIntConstant(module, "WHAT_DEFINE_FILE", WHAT_DEFINE_FILE);
   1640         PyModule_AddIntConstant(module, "WHAT_DEFINE_FUNC", WHAT_DEFINE_FUNC);
   1641         PyModule_AddIntConstant(module, "WHAT_LINE_TIMES", WHAT_LINE_TIMES);
   1642     }
   1643 }
   1644