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 = 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 
    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         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 
    642 static int
    643 pack_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 
    659 static int
    660 pack_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 
    675 static int
    676 pack_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 
    694 static int
    695 pack_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 
    707 static int
    708 pack_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 
    720 static inline int
    721 pack_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 
    735 static inline int
    736 pack_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 
    749 static inline int
    750 pack_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 
    759 static inline int
    760 pack_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 
    771 static inline int
    772 get_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 
    831 static inline int
    832 get_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 
    862 static int
    863 tracer_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
    898 static LARGE_INTEGER frequency = {0, 0};
    899 #endif
    900 
    901 static unsigned long timeofday_diff = 0;
    902 static unsigned long rusage_diff = 0;
    903 
    904 static void
    905 calibrate(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 
    966 static void
    967 do_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 
    977 static void
    978 do_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 
    993 static int
    994 is_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 
   1010 PyDoc_STRVAR(addinfo__doc__,
   1011 "addinfo(key, value)\n"
   1012 "Insert an ADD_INFO record into the log.");
   1013 
   1014 static PyObject *
   1015 profiler_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 
   1033 PyDoc_STRVAR(close__doc__,
   1034 "close()\n"
   1035 "Shut down this profiler and close the log files, even if its active.");
   1036 
   1037 static PyObject *
   1038 profiler_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 
   1051 static PyObject *
   1052 profiler_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 
   1062 PyDoc_STRVAR(runcall__doc__,
   1063 "runcall(callable[, args[, kw]]) -> callable()\n"
   1064 "Profile a specific function call, returning the result of that call.");
   1065 
   1066 static PyObject *
   1067 profiler_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 
   1085 PyDoc_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 
   1090 static PyObject *
   1091 profiler_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 
   1124 PyDoc_STRVAR(start__doc__,
   1125 "start()\n"
   1126 "Install this profiler for the current thread.");
   1127 
   1128 static PyObject *
   1129 profiler_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 
   1141 PyDoc_STRVAR(stop__doc__,
   1142 "stop()\n"
   1143 "Remove this profiler from the current thread.");
   1144 
   1145 static PyObject *
   1146 profiler_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 
   1163 static void
   1164 profiler_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 
   1174 static 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 
   1185 static 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 
   1192 static PyObject *
   1193 profiler_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 
   1200 static 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 
   1207 PyDoc_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 
   1226 static 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 
   1264 static 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 
   1272 static 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 
   1279 PyDoc_STRVAR(logreader__doc__,
   1280 "logreader(filename) --> log-iterator\n\
   1281 Create a log-reader for the timing information file.");
   1282 
   1283 static 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 
   1296 static PyObject *
   1297 logreader_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 
   1304 static 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 
   1310 static 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 
   1347 static PyObject *
   1348 hotshot_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  */
   1403 static char *
   1404 get_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  */
   1426 static int
   1427 write_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 
   1491 PyDoc_STRVAR(profiler__doc__,
   1492 "profiler(logfilename[, lineevents[, linetimes]]) -> profiler\n\
   1493 Create a new profiler object.");
   1494 
   1495 static PyObject *
   1496 hotshot_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 
   1546 PyDoc_STRVAR(coverage__doc__,
   1547 "coverage(logfilename) -> profiler\n\
   1548 Returns a profiler that doesn't collect any timing information, which is\n\
   1549 useful in building a coverage analysis tool.");
   1550 
   1551 static PyObject *
   1552 hotshot_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 
   1569 PyDoc_VAR(resolution__doc__) =
   1570 #ifdef MS_WINDOWS
   1571 PyDoc_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
   1578 PyDoc_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 
   1586 static PyObject *
   1587 hotshot_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 
   1602 static 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 
   1611 void
   1612 init_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