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