blob: 4a0fbd806530c8225fa6fdac9577f465262b32c8 [file] [log] [blame]
Fred Drake8c081a12001-10-12 20:57:55 +00001/*
2 * This is the High Performance Python Profiler portion of HotShot.
3 */
4
Tim Peters885d4572001-11-28 20:27:42 +00005#include "Python.h"
6#include "compile.h"
7#include "eval.h"
8#include "frameobject.h"
9#include "structmember.h"
Fred Drake8c081a12001-10-12 20:57:55 +000010
Fred Drake8c081a12001-10-12 20:57:55 +000011/*
12 * Which timer to use should be made more configurable, but that should not
Tim Petersfeab23f2001-10-13 00:11:10 +000013 * be difficult. This will do for now.
Fred Drake8c081a12001-10-12 20:57:55 +000014 */
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000015#ifdef MS_WINDOWS
Fred Drake8c081a12001-10-12 20:57:55 +000016#include <windows.h>
Tim Peters1566a172001-10-12 22:08:39 +000017#include <direct.h> /* for getcwd() */
Tim Peters7d99ff22001-10-13 07:37:52 +000018typedef __int64 hs_time;
19#define GETTIMEOFDAY(P_HS_TIME) \
20 { LARGE_INTEGER _temp; \
21 QueryPerformanceCounter(&_temp); \
22 *(P_HS_TIME) = _temp.QuadPart; }
23
Tim Petersfeab23f2001-10-13 00:11:10 +000024
Fred Drake8c081a12001-10-12 20:57:55 +000025#else
26#ifndef HAVE_GETTIMEOFDAY
27#error "This module requires gettimeofday() on non-Windows platforms!"
28#endif
Andrew MacIntyre7bf68332002-03-03 02:59:16 +000029#if defined(macintosh) || (defined(PYOS_OS2) && defined(PYCC_GCC))
Jack Jansen963659a2001-10-23 22:26:16 +000030#include <sys/time.h>
31#else
Fred Drake8c081a12001-10-12 20:57:55 +000032#include <sys/resource.h>
33#include <sys/times.h>
Jack Jansen963659a2001-10-23 22:26:16 +000034#endif
Fred Drake8c081a12001-10-12 20:57:55 +000035typedef 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 Jansen963659a2001-10-23 22:26:16 +000050#ifdef macintosh
51#define PATH_MAX 254
52#endif
53
Andrew MacIntyre7bf68332002-03-03 02:59:16 +000054#if defined(PYOS_OS2) && defined(PYCC_GCC)
55#define PATH_MAX 260
56#endif
57
Tim Peters1566a172001-10-12 22:08:39 +000058#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 Drake8c081a12001-10-12 20:57:55 +000066typedef 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 Drake30d1c752001-10-15 22:11:02 +000075 int frametimings;
Fred Drake8c081a12001-10-12 20:57:55 +000076 /* size_t filled; */
77 int active;
78 int next_fileno;
Fred Drake8c081a12001-10-12 20:57:55 +000079 hs_time prev_timeofday;
80} ProfilerObject;
81
82typedef struct {
83 PyObject_HEAD
Fred Drake4c2e1af2001-10-29 20:45:57 +000084 PyObject *info;
Fred Drake8c081a12001-10-12 20:57:55 +000085 FILE *logfp;
Fred Drake8c081a12001-10-12 20:57:55 +000086 int linetimings;
Fred Drake30d1c752001-10-15 22:11:02 +000087 int frametimings;
Fred Drake8c081a12001-10-12 20:57:55 +000088} LogReaderObject;
89
90static PyObject * ProfilerError = NULL;
91
92
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000093#ifndef MS_WINDOWS
Fred Drake8c081a12001-10-12 20:57:55 +000094#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öwis14f8b4c2002-06-13 20:33:02 +0000104PyDoc_STRVAR(logreader_close__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +0000105"close()\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000106"Close the log file, preventing additional records from being read.");
Fred Drake8c081a12001-10-12 20:57:55 +0000107
108static PyObject *
109logreader_close(LogReaderObject *self, PyObject *args)
110{
111 PyObject *result = NULL;
112 if (PyArg_ParseTuple(args, ":close")) {
113 if (self->logfp != NULL) {
114 fclose(self->logfp);
115 self->logfp = NULL;
116 }
117 result = Py_None;
118 Py_INCREF(result);
119 }
120 return result;
121}
122
Fred Drake8c081a12001-10-12 20:57:55 +0000123static PyObject *
124logreader_tp_iter(LogReaderObject *self)
125{
126 Py_INCREF(self);
127 return (PyObject *) self;
128}
Fred Drake8c081a12001-10-12 20:57:55 +0000129
130
131/* Log File Format
132 * ---------------
133 *
134 * The log file consists of a sequence of variable-length records.
135 * Each record is identified with a record type identifier in two
136 * bits of the first byte. The two bits are the "least significant"
137 * bits of the byte.
138 *
139 * Low bits: Opcode: Meaning:
140 * 0x00 ENTER enter a frame
141 * 0x01 EXIT exit a frame
142 * 0x02 LINENO SET_LINENO instruction was executed
143 * 0x03 OTHER more bits are needed to deecode
144 *
145 * If the type is OTHER, the record is not packed so tightly, and the
146 * remaining bits are used to disambiguate the record type. These
147 * records are not used as frequently so compaction is not an issue.
148 * Each of the first three record types has a highly tailored
149 * structure that allows it to be packed tightly.
150 *
151 * The OTHER records have the following identifiers:
152 *
153 * First byte: Opcode: Meaning:
154 * 0x13 ADD_INFO define a key/value pair
155 * 0x23 DEFINE_FILE define an int->filename mapping
156 * 0x33 LINE_TIMES indicates if LINENO events have tdeltas
Fred Drake30d1c752001-10-15 22:11:02 +0000157 * 0x43 DEFINE_FUNC define a (fileno,lineno)->funcname mapping
158 * 0x53 FRAME_TIMES indicates if ENTER/EXIT events have tdeltas
Fred Drake8c081a12001-10-12 20:57:55 +0000159 *
160 * Packed Integers
161 *
162 * "Packed integers" are non-negative integer values encoded as a
163 * sequence of bytes. Each byte is encoded such that the most
164 * significant bit is set if the next byte is also part of the
165 * integer. Each byte provides bits to the least-significant end of
166 * the result; the accumulated value must be shifted up to place the
167 * new bits into the result.
168 *
169 * "Modified packed integers" are packed integers where only a portion
170 * of the first byte is used. In the rest of the specification, these
171 * are referred to as "MPI(n,name)", where "n" is the number of bits
172 * discarded from the least-signicant positions of the byte, and
173 * "name" is a name being given to those "discarded" bits, since they
174 * are a field themselves.
175 *
176 * ENTER records:
177 *
178 * MPI(2,type) fileno -- type is 0x00
Fred Drake8c081a12001-10-12 20:57:55 +0000179 * PI lineno
Fred Drake30d1c752001-10-15 22:11:02 +0000180 * PI tdelta -- iff frame times are enabled
Fred Drake8c081a12001-10-12 20:57:55 +0000181 *
182 * EXIT records
183 *
Fred Drake30d1c752001-10-15 22:11:02 +0000184 * MPI(2,type) tdelta -- type is 0x01; tdelta will be 0
185 * if frame times are disabled
Fred Drake8c081a12001-10-12 20:57:55 +0000186 *
187 * LINENO records
188 *
189 * MPI(2,type) lineno -- type is 0x02
190 * PI tdelta -- iff LINENO includes it
191 *
192 * ADD_INFO records
193 *
Fred Drake30d1c752001-10-15 22:11:02 +0000194 * BYTE type -- always 0x13
Fred Drake8c081a12001-10-12 20:57:55 +0000195 * PI len1 -- length of first string
196 * BYTE string1[len1] -- len1 bytes of string data
197 * PI len2 -- length of second string
198 * BYTE string2[len2] -- len2 bytes of string data
199 *
200 * DEFINE_FILE records
201 *
Fred Drake30d1c752001-10-15 22:11:02 +0000202 * BYTE type -- always 0x23
Fred Drake8c081a12001-10-12 20:57:55 +0000203 * PI fileno
204 * PI len -- length of filename
205 * BYTE filename[len] -- len bytes of string data
206 *
Fred Drake30d1c752001-10-15 22:11:02 +0000207 * DEFINE_FUNC records
208 *
209 * BYTE type -- always 0x43
210 * PI fileno
211 * PI lineno
212 * PI len -- length of funcname
213 * BYTE funcname[len] -- len bytes of string data
214 *
Fred Drake8c081a12001-10-12 20:57:55 +0000215 * LINE_TIMES records
Fred Drake30d1c752001-10-15 22:11:02 +0000216 *
217 * This record can be used only before the start of ENTER/EXIT/LINENO
218 * records. If have_tdelta is true, LINENO records will include the
219 * tdelta field, otherwise it will be omitted. If this record is not
220 * given, LINENO records will not contain the tdelta field.
221 *
222 * BYTE type -- always 0x33
Fred Drake8c081a12001-10-12 20:57:55 +0000223 * BYTE have_tdelta -- 0 if LINENO does *not* have
224 * timing information
Fred Drake30d1c752001-10-15 22:11:02 +0000225 * FRAME_TIMES records
226 *
227 * This record can be used only before the start of ENTER/EXIT/LINENO
228 * records. If have_tdelta is true, ENTER and EXIT records will
229 * include the tdelta field, otherwise it will be omitted. If this
230 * record is not given, ENTER and EXIT records will contain the tdelta
231 * field.
232 *
233 * BYTE type -- always 0x53
234 * BYTE have_tdelta -- 0 if ENTER/EXIT do *not* have
235 * timing information
Fred Drake8c081a12001-10-12 20:57:55 +0000236 */
237
238#define WHAT_ENTER 0x00
239#define WHAT_EXIT 0x01
240#define WHAT_LINENO 0x02
241#define WHAT_OTHER 0x03 /* only used in decoding */
242#define WHAT_ADD_INFO 0x13
243#define WHAT_DEFINE_FILE 0x23
244#define WHAT_LINE_TIMES 0x33
Fred Drake30d1c752001-10-15 22:11:02 +0000245#define WHAT_DEFINE_FUNC 0x43
246#define WHAT_FRAME_TIMES 0x53
Fred Drake8c081a12001-10-12 20:57:55 +0000247
248#define ERR_NONE 0
249#define ERR_EOF -1
250#define ERR_EXCEPTION -2
Fred Drake4c2e1af2001-10-29 20:45:57 +0000251#define ERR_BAD_RECTYPE -3
Fred Drake8c081a12001-10-12 20:57:55 +0000252
253#define PISIZE (sizeof(int) + 1)
254#define MPISIZE (PISIZE + 1)
255
256/* Maximum size of "normal" events -- nothing that contains string data */
257#define MAXEVENTSIZE (MPISIZE + PISIZE*2)
258
259
260/* Unpack a packed integer; if "discard" is non-zero, unpack a modified
261 * packed integer with "discard" discarded bits.
262 */
263static int
264unpack_packed_int(LogReaderObject *self, int *pvalue, int discard)
265{
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000266 int c;
Fred Drake8c081a12001-10-12 20:57:55 +0000267 int accum = 0;
268 int bits = 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000269 int cont;
270
271 do {
Fred Drake8c081a12001-10-12 20:57:55 +0000272 /* read byte */
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000273 if ((c = fgetc(self->logfp)) == EOF)
274 return ERR_EOF;
275 accum |= ((c & 0x7F) >> discard) << bits;
Fred Drake8c081a12001-10-12 20:57:55 +0000276 bits += (7 - discard);
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000277 cont = c & 0x80;
Fred Drake8c081a12001-10-12 20:57:55 +0000278 discard = 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000279 } while (cont);
280
Fred Drake8c081a12001-10-12 20:57:55 +0000281 *pvalue = accum;
282
283 return 0;
284}
285
286/* Unpack a string, which is encoded as a packed integer giving the
287 * length of the string, followed by the string data.
288 */
289static int
290unpack_string(LogReaderObject *self, PyObject **pvalue)
291{
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000292 int i;
Fred Drake8c081a12001-10-12 20:57:55 +0000293 int len;
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000294 int err;
295 char *buf;
296
297 if ((err = unpack_packed_int(self, &len, 0)))
298 return err;
Fred Drake8c081a12001-10-12 20:57:55 +0000299
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000300 buf = malloc(len);
301 for (i=0; i < len; i++) {
302 if ((buf[i] = fgetc(self->logfp)) == EOF) {
303 free(buf);
304 return ERR_EOF;
Fred Drake8c081a12001-10-12 20:57:55 +0000305 }
306 }
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000307 *pvalue = PyString_FromStringAndSize(buf, len);
308 free(buf);
309 if (*pvalue == NULL) {
310 return ERR_EXCEPTION;
311 }
312 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000313}
314
315
Fred Drake4c2e1af2001-10-29 20:45:57 +0000316static int
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000317unpack_add_info(LogReaderObject *self)
Fred Drake4c2e1af2001-10-29 20:45:57 +0000318{
319 PyObject *key;
320 PyObject *value = NULL;
321 int err;
322
Fred Drake4c2e1af2001-10-29 20:45:57 +0000323 err = unpack_string(self, &key);
324 if (!err) {
325 err = unpack_string(self, &value);
326 if (err)
327 Py_DECREF(key);
328 else {
329 PyObject *list = PyDict_GetItem(self->info, key);
330 if (list == NULL) {
331 list = PyList_New(0);
332 if (list == NULL) {
333 err = ERR_EXCEPTION;
334 goto finally;
335 }
336 if (PyDict_SetItem(self->info, key, list)) {
337 err = ERR_EXCEPTION;
338 goto finally;
339 }
340 }
341 if (PyList_Append(list, value))
342 err = ERR_EXCEPTION;
343 }
344 }
345 finally:
346 Py_XDECREF(key);
347 Py_XDECREF(value);
348 return err;
349}
350
351
352static void
Fred Drake4c2e1af2001-10-29 20:45:57 +0000353eof_error(void)
354{
355 PyErr_SetString(PyExc_EOFError,
356 "end of file with incomplete profile record");
357}
358
Fred Drake8c081a12001-10-12 20:57:55 +0000359static PyObject *
360logreader_tp_iternext(LogReaderObject *self)
361{
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000362 int c;
363 int what;
Fred Drake8c081a12001-10-12 20:57:55 +0000364 int err = ERR_NONE;
365 int lineno = -1;
366 int fileno = -1;
367 int tdelta = -1;
368 PyObject *s1 = NULL, *s2 = NULL;
369 PyObject *result = NULL;
370#if 0
371 unsigned char b0, b1;
372#endif
373
374 if (self->logfp == NULL) {
375 PyErr_SetString(ProfilerError,
376 "cannot iterate over closed LogReader object");
377 return NULL;
378 }
Fred Drake4c2e1af2001-10-29 20:45:57 +0000379
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000380restart:
381 /* decode the record type */
382 if ((c = fgetc(self->logfp)) == EOF)
Fred Drake8c081a12001-10-12 20:57:55 +0000383 return NULL;
384
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000385 what = c & WHAT_OTHER;
386 if (what == WHAT_OTHER)
387 what = c; /* need all the bits for type */
388 else
389 ungetc(c, self->logfp); /* type byte includes packed int */
Fred Drake8c081a12001-10-12 20:57:55 +0000390
Fred Drake8c081a12001-10-12 20:57:55 +0000391 switch (what) {
392 case WHAT_ENTER:
393 err = unpack_packed_int(self, &fileno, 2);
394 if (!err) {
Fred Drake30d1c752001-10-15 22:11:02 +0000395 err = unpack_packed_int(self, &lineno, 0);
396 if (self->frametimings && !err)
397 err = unpack_packed_int(self, &tdelta, 0);
Fred Drake8c081a12001-10-12 20:57:55 +0000398 }
399 break;
400 case WHAT_EXIT:
401 err = unpack_packed_int(self, &tdelta, 2);
402 break;
403 case WHAT_LINENO:
404 err = unpack_packed_int(self, &lineno, 2);
405 if (self->linetimings && !err)
406 err = unpack_packed_int(self, &tdelta, 0);
407 break;
408 case WHAT_ADD_INFO:
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000409 err = unpack_add_info(self);
Fred Drake8c081a12001-10-12 20:57:55 +0000410 break;
411 case WHAT_DEFINE_FILE:
412 err = unpack_packed_int(self, &fileno, 0);
413 if (!err) {
414 err = unpack_string(self, &s1);
415 if (!err) {
416 Py_INCREF(Py_None);
417 s2 = Py_None;
418 }
419 }
420 break;
Fred Drake30d1c752001-10-15 22:11:02 +0000421 case WHAT_DEFINE_FUNC:
422 err = unpack_packed_int(self, &fileno, 0);
423 if (!err) {
424 err = unpack_packed_int(self, &lineno, 0);
425 if (!err)
426 err = unpack_string(self, &s1);
427 }
428 break;
Fred Drake8c081a12001-10-12 20:57:55 +0000429 case WHAT_LINE_TIMES:
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000430 if ((c = fgetc(self->logfp)) == EOF)
Fred Drake8c081a12001-10-12 20:57:55 +0000431 err = ERR_EOF;
432 else {
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000433 self->linetimings = c ? 1 : 0;
434 goto restart;
435 }
Fred Drake4c2e1af2001-10-29 20:45:57 +0000436 break;
Fred Drake30d1c752001-10-15 22:11:02 +0000437 case WHAT_FRAME_TIMES:
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000438 if ((c = fgetc(self->logfp)) == EOF)
Fred Drake30d1c752001-10-15 22:11:02 +0000439 err = ERR_EOF;
440 else {
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000441 self->frametimings = c ? 1 : 0;
442 goto restart;
443 }
Fred Drake4c2e1af2001-10-29 20:45:57 +0000444 break;
Fred Drake8c081a12001-10-12 20:57:55 +0000445 default:
Fred Drake4c2e1af2001-10-29 20:45:57 +0000446 err = ERR_BAD_RECTYPE;
Fred Drake8c081a12001-10-12 20:57:55 +0000447 }
Fred Drake4c2e1af2001-10-29 20:45:57 +0000448 if (err == ERR_BAD_RECTYPE) {
449 PyErr_SetString(PyExc_ValueError,
450 "unknown record type in log file");
451 }
452 else if (err == ERR_EOF) {
Fred Drake4c2e1af2001-10-29 20:45:57 +0000453 eof_error();
Fred Drake8c081a12001-10-12 20:57:55 +0000454 }
455 else if (!err) {
456 result = PyTuple_New(4);
457 PyTuple_SET_ITEM(result, 0, PyInt_FromLong(what));
458 PyTuple_SET_ITEM(result, 2, PyInt_FromLong(fileno));
Fred Drake30d1c752001-10-15 22:11:02 +0000459 if (s1 == NULL)
Fred Drake8c081a12001-10-12 20:57:55 +0000460 PyTuple_SET_ITEM(result, 1, PyInt_FromLong(tdelta));
Fred Drake30d1c752001-10-15 22:11:02 +0000461 else
Fred Drake8c081a12001-10-12 20:57:55 +0000462 PyTuple_SET_ITEM(result, 1, s1);
Fred Drake30d1c752001-10-15 22:11:02 +0000463 if (s2 == NULL)
464 PyTuple_SET_ITEM(result, 3, PyInt_FromLong(lineno));
465 else
Fred Drake8c081a12001-10-12 20:57:55 +0000466 PyTuple_SET_ITEM(result, 3, s2);
Fred Drake8c081a12001-10-12 20:57:55 +0000467 }
468 /* The only other case is err == ERR_EXCEPTION, in which case the
469 * exception is already set.
470 */
471#if 0
472 b0 = self->buffer[self->index];
473 b1 = self->buffer[self->index + 1];
474 if (b0 & 1) {
475 /* This is a line-number event. */
476 what = PyTrace_LINE;
477 lineno = ((b0 & ~1) << 7) + b1;
478 self->index += 2;
479 }
480 else {
481 what = (b0 & 0x0E) >> 1;
482 tdelta = ((b0 & 0xF0) << 4) + b1;
483 if (what == PyTrace_CALL) {
484 /* we know there's a 2-byte file ID & 2-byte line number */
485 fileno = ((self->buffer[self->index + 2] << 8)
486 + self->buffer[self->index + 3]);
487 lineno = ((self->buffer[self->index + 4] << 8)
488 + self->buffer[self->index + 5]);
489 self->index += 6;
490 }
491 else
492 self->index += 2;
493 }
494#endif
495 return result;
496}
497
498static void
499logreader_dealloc(LogReaderObject *self)
500{
501 if (self->logfp != NULL) {
502 fclose(self->logfp);
503 self->logfp = NULL;
504 }
505 PyObject_Del(self);
506}
507
508static PyObject *
509logreader_sq_item(LogReaderObject *self, int index)
510{
511 PyObject *result = logreader_tp_iternext(self);
512 if (result == NULL && !PyErr_Occurred()) {
513 PyErr_SetString(PyExc_IndexError, "no more events in log");
514 return NULL;
515 }
516 return result;
517}
518
Fred Drake62c1e3c2001-12-04 21:40:53 +0000519static void
520do_stop(ProfilerObject *self);
Fred Drake8c081a12001-10-12 20:57:55 +0000521
522static int
523flush_data(ProfilerObject *self)
524{
525 /* Need to dump data to the log file... */
526 size_t written = fwrite(self->buffer, 1, self->index, self->logfp);
Tim Peters1566a172001-10-12 22:08:39 +0000527 if (written == (size_t)self->index)
Fred Drake8c081a12001-10-12 20:57:55 +0000528 self->index = 0;
529 else {
530 memmove(self->buffer, &self->buffer[written],
531 self->index - written);
532 self->index -= written;
533 if (written == 0) {
534 char *s = PyString_AsString(self->logfilename);
535 PyErr_SetFromErrnoWithFilename(PyExc_IOError, s);
Fred Drake62c1e3c2001-12-04 21:40:53 +0000536 do_stop(self);
Fred Drake8c081a12001-10-12 20:57:55 +0000537 return -1;
538 }
539 }
540 if (written > 0) {
541 if (fflush(self->logfp)) {
542 char *s = PyString_AsString(self->logfilename);
543 PyErr_SetFromErrnoWithFilename(PyExc_IOError, s);
Fred Drake62c1e3c2001-12-04 21:40:53 +0000544 do_stop(self);
Fred Drake8c081a12001-10-12 20:57:55 +0000545 return -1;
546 }
547 }
548 return 0;
549}
550
Fred Drake62c1e3c2001-12-04 21:40:53 +0000551static inline int
Fred Drake8c081a12001-10-12 20:57:55 +0000552pack_packed_int(ProfilerObject *self, int value)
553{
554 unsigned char partial;
555
556 do {
557 partial = value & 0x7F;
558 value >>= 7;
559 if (value)
560 partial |= 0x80;
561 self->buffer[self->index] = partial;
562 self->index++;
563 } while (value);
Fred Drake62c1e3c2001-12-04 21:40:53 +0000564 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000565}
566
567/* Encode a modified packed integer, with a subfield of modsize bits
568 * containing the value "subfield". The value of subfield is not
569 * checked to ensure it actually fits in modsize bits.
570 */
Fred Drake62c1e3c2001-12-04 21:40:53 +0000571static inline int
Fred Drake8c081a12001-10-12 20:57:55 +0000572pack_modified_packed_int(ProfilerObject *self, int value,
573 int modsize, int subfield)
574{
575 const int maxvalues[] = {-1, 1, 3, 7, 15, 31, 63, 127};
576
577 int bits = 7 - modsize;
578 int partial = value & maxvalues[bits];
579 unsigned char b = subfield | (partial << modsize);
580
581 if (partial != value) {
582 b |= 0x80;
583 self->buffer[self->index] = b;
584 self->index++;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000585 return pack_packed_int(self, value >> bits);
Fred Drake8c081a12001-10-12 20:57:55 +0000586 }
Fred Drake62c1e3c2001-12-04 21:40:53 +0000587 self->buffer[self->index] = b;
588 self->index++;
589 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000590}
591
Fred Drake62c1e3c2001-12-04 21:40:53 +0000592static int
Fred Drake30d1c752001-10-15 22:11:02 +0000593pack_string(ProfilerObject *self, const char *s, int len)
Fred Drake8c081a12001-10-12 20:57:55 +0000594{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000595 if (len + PISIZE + self->index >= BUFFERSIZE) {
596 if (flush_data(self) < 0)
597 return -1;
598 }
599 if (pack_packed_int(self, len) < 0)
600 return -1;
Fred Drake8c081a12001-10-12 20:57:55 +0000601 memcpy(self->buffer + self->index, s, len);
602 self->index += len;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000603 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000604}
605
Fred Drake62c1e3c2001-12-04 21:40:53 +0000606static int
Fred Drake8c081a12001-10-12 20:57:55 +0000607pack_add_info(ProfilerObject *self, const char *s1, const char *s2)
608{
609 int len1 = strlen(s1);
610 int len2 = strlen(s2);
611
Fred Drake62c1e3c2001-12-04 21:40:53 +0000612 if (len1 + len2 + PISIZE*2 + 1 + self->index >= BUFFERSIZE) {
613 if (flush_data(self) < 0)
614 return -1;
615 }
Fred Drake8c081a12001-10-12 20:57:55 +0000616 self->buffer[self->index] = WHAT_ADD_INFO;
617 self->index++;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000618 if (pack_string(self, s1, len1) < 0)
619 return -1;
620 return pack_string(self, s2, len2);
Fred Drake8c081a12001-10-12 20:57:55 +0000621}
622
Fred Drake62c1e3c2001-12-04 21:40:53 +0000623static int
Fred Drake8c081a12001-10-12 20:57:55 +0000624pack_define_file(ProfilerObject *self, int fileno, const char *filename)
625{
626 int len = strlen(filename);
627
Fred Drake62c1e3c2001-12-04 21:40:53 +0000628 if (len + PISIZE*2 + 1 + self->index >= BUFFERSIZE) {
629 if (flush_data(self) < 0)
630 return -1;
631 }
Fred Drake8c081a12001-10-12 20:57:55 +0000632 self->buffer[self->index] = WHAT_DEFINE_FILE;
633 self->index++;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000634 if (pack_packed_int(self, fileno) < 0)
635 return -1;
636 return pack_string(self, filename, len);
Fred Drake30d1c752001-10-15 22:11:02 +0000637}
638
Fred Drake62c1e3c2001-12-04 21:40:53 +0000639static int
Fred Drake30d1c752001-10-15 22:11:02 +0000640pack_define_func(ProfilerObject *self, int fileno, int lineno,
641 const char *funcname)
642{
643 int len = strlen(funcname);
644
Fred Drake62c1e3c2001-12-04 21:40:53 +0000645 if (len + PISIZE*3 + 1 + self->index >= BUFFERSIZE) {
646 if (flush_data(self) < 0)
647 return -1;
648 }
Fred Drake30d1c752001-10-15 22:11:02 +0000649 self->buffer[self->index] = WHAT_DEFINE_FUNC;
650 self->index++;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000651 if (pack_packed_int(self, fileno) < 0)
652 return -1;
653 if (pack_packed_int(self, lineno) < 0)
654 return -1;
655 return pack_string(self, funcname, len);
Fred Drake8c081a12001-10-12 20:57:55 +0000656}
657
Fred Drake62c1e3c2001-12-04 21:40:53 +0000658static int
Fred Drake8c081a12001-10-12 20:57:55 +0000659pack_line_times(ProfilerObject *self)
660{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000661 if (2 + self->index >= BUFFERSIZE) {
662 if (flush_data(self) < 0)
663 return -1;
664 }
Fred Drake8c081a12001-10-12 20:57:55 +0000665 self->buffer[self->index] = WHAT_LINE_TIMES;
666 self->buffer[self->index + 1] = self->linetimings ? 1 : 0;
667 self->index += 2;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000668 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000669}
670
Fred Drake62c1e3c2001-12-04 21:40:53 +0000671static int
Fred Drake30d1c752001-10-15 22:11:02 +0000672pack_frame_times(ProfilerObject *self)
673{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000674 if (2 + self->index >= BUFFERSIZE) {
675 if (flush_data(self) < 0)
676 return -1;
677 }
Fred Drake30d1c752001-10-15 22:11:02 +0000678 self->buffer[self->index] = WHAT_FRAME_TIMES;
679 self->buffer[self->index + 1] = self->frametimings ? 1 : 0;
680 self->index += 2;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000681 return 0;
Fred Drake30d1c752001-10-15 22:11:02 +0000682}
683
Fred Drake62c1e3c2001-12-04 21:40:53 +0000684static inline int
Fred Drake8c081a12001-10-12 20:57:55 +0000685pack_enter(ProfilerObject *self, int fileno, int tdelta, int lineno)
686{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000687 if (MPISIZE + PISIZE*2 + self->index >= BUFFERSIZE) {
688 if (flush_data(self) < 0)
689 return -1;
690 }
Fred Drake8c081a12001-10-12 20:57:55 +0000691 pack_modified_packed_int(self, fileno, 2, WHAT_ENTER);
Fred Drake8c081a12001-10-12 20:57:55 +0000692 pack_packed_int(self, lineno);
Fred Drake30d1c752001-10-15 22:11:02 +0000693 if (self->frametimings)
Fred Drake62c1e3c2001-12-04 21:40:53 +0000694 return pack_packed_int(self, tdelta);
695 else
696 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000697}
698
Fred Drake62c1e3c2001-12-04 21:40:53 +0000699static inline int
Fred Drake8c081a12001-10-12 20:57:55 +0000700pack_exit(ProfilerObject *self, int tdelta)
701{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000702 if (MPISIZE + self->index >= BUFFERSIZE) {
703 if (flush_data(self) < 0)
704 return -1;
Fred Drake30d1c752001-10-15 22:11:02 +0000705 }
Fred Drake62c1e3c2001-12-04 21:40:53 +0000706 if (self->frametimings)
707 return pack_modified_packed_int(self, tdelta, 2, WHAT_EXIT);
708 self->buffer[self->index] = WHAT_EXIT;
709 self->index++;
710 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000711}
712
Fred Drake62c1e3c2001-12-04 21:40:53 +0000713static inline int
Fred Drake8c081a12001-10-12 20:57:55 +0000714pack_lineno(ProfilerObject *self, int lineno)
715{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000716 if (MPISIZE + self->index >= BUFFERSIZE) {
717 if (flush_data(self) < 0)
718 return -1;
719 }
720 return pack_modified_packed_int(self, lineno, 2, WHAT_LINENO);
Fred Drake8c081a12001-10-12 20:57:55 +0000721}
722
Fred Drake62c1e3c2001-12-04 21:40:53 +0000723static inline int
Fred Drake8c081a12001-10-12 20:57:55 +0000724pack_lineno_tdelta(ProfilerObject *self, int lineno, int tdelta)
725{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000726 if (MPISIZE + PISIZE + self->index >= BUFFERSIZE) {
727 if (flush_data(self) < 0)
728 return 0;
729 }
730 if (pack_modified_packed_int(self, lineno, 2, WHAT_LINENO) < 0)
731 return -1;
732 return pack_packed_int(self, tdelta);
Fred Drake8c081a12001-10-12 20:57:55 +0000733}
734
735static inline int
736get_fileno(ProfilerObject *self, PyCodeObject *fcode)
737{
Fred Drake30d1c752001-10-15 22:11:02 +0000738 /* This is only used for ENTER events. */
739
740 PyObject *obj;
741 PyObject *dict;
Fred Drake8c081a12001-10-12 20:57:55 +0000742 int fileno;
743
Fred Drake30d1c752001-10-15 22:11:02 +0000744 obj = PyDict_GetItem(self->filemap, fcode->co_filename);
745 if (obj == NULL) {
Fred Drake8c081a12001-10-12 20:57:55 +0000746 /* first sighting of this file */
Fred Drake30d1c752001-10-15 22:11:02 +0000747 dict = PyDict_New();
748 if (dict == NULL) {
Fred Drake8c081a12001-10-12 20:57:55 +0000749 return -1;
750 }
Fred Drake30d1c752001-10-15 22:11:02 +0000751 fileno = self->next_fileno;
752 obj = Py_BuildValue("iN", fileno, dict);
753 if (obj == NULL) {
754 return -1;
755 }
756 if (PyDict_SetItem(self->filemap, fcode->co_filename, obj)) {
757 Py_DECREF(obj);
Fred Drake8c081a12001-10-12 20:57:55 +0000758 return -1;
759 }
760 self->next_fileno++;
Fred Drake30d1c752001-10-15 22:11:02 +0000761 Py_DECREF(obj);
Fred Drake62c1e3c2001-12-04 21:40:53 +0000762 if (pack_define_file(self, fileno,
763 PyString_AS_STRING(fcode->co_filename)) < 0)
764 return -1;
Fred Drake8c081a12001-10-12 20:57:55 +0000765 }
766 else {
767 /* already know this ID */
Fred Drake30d1c752001-10-15 22:11:02 +0000768 fileno = PyInt_AS_LONG(PyTuple_GET_ITEM(obj, 0));
769 dict = PyTuple_GET_ITEM(obj, 1);
770 }
771 /* make sure we save a function name for this (fileno, lineno) */
772 obj = PyInt_FromLong(fcode->co_firstlineno);
773 if (obj == NULL) {
774 /* We just won't have it saved; too bad. */
775 PyErr_Clear();
776 }
777 else {
778 PyObject *name = PyDict_GetItem(dict, obj);
779 if (name == NULL) {
Fred Drake62c1e3c2001-12-04 21:40:53 +0000780 if (pack_define_func(self, fileno, fcode->co_firstlineno,
781 PyString_AS_STRING(fcode->co_name)) < 0)
782 return -1;
Fred Drake30d1c752001-10-15 22:11:02 +0000783 if (PyDict_SetItem(dict, obj, fcode->co_name))
784 return -1;
785 }
Fred Drake8c081a12001-10-12 20:57:55 +0000786 }
787 return fileno;
788}
789
790static inline int
791get_tdelta(ProfilerObject *self)
792{
793 int tdelta;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000794#ifdef MS_WINDOWS
Fred Drake8c081a12001-10-12 20:57:55 +0000795 hs_time tv;
Tim Peters7d99ff22001-10-13 07:37:52 +0000796 hs_time diff;
Fred Drake8c081a12001-10-12 20:57:55 +0000797
Tim Peters7d99ff22001-10-13 07:37:52 +0000798 GETTIMEOFDAY(&tv);
799 diff = tv - self->prev_timeofday;
800 tdelta = (int)diff;
Fred Drake8c081a12001-10-12 20:57:55 +0000801#else
802 struct timeval tv;
803
804 GETTIMEOFDAY(&tv);
805
806 if (tv.tv_sec == self->prev_timeofday.tv_sec)
807 tdelta = tv.tv_usec - self->prev_timeofday.tv_usec;
808 else
809 tdelta = ((tv.tv_sec - self->prev_timeofday.tv_sec) * 1000000
810 + tv.tv_usec);
811#endif
812 self->prev_timeofday = tv;
813 return tdelta;
814}
815
816
817/* The workhorse: the profiler callback function. */
818
819static int
820profiler_callback(ProfilerObject *self, PyFrameObject *frame, int what,
821 PyObject *arg)
822{
Fred Drake30d1c752001-10-15 22:11:02 +0000823 int tdelta = -1;
Fred Drake8c081a12001-10-12 20:57:55 +0000824 int fileno;
825
Fred Drake30d1c752001-10-15 22:11:02 +0000826 if (self->frametimings)
827 tdelta = get_tdelta(self);
Fred Drake8c081a12001-10-12 20:57:55 +0000828 switch (what) {
829 case PyTrace_CALL:
830 fileno = get_fileno(self, frame->f_code);
831 if (fileno < 0)
832 return -1;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000833 if (pack_enter(self, fileno, tdelta,
834 frame->f_code->co_firstlineno) < 0)
835 return -1;
Fred Drake8c081a12001-10-12 20:57:55 +0000836 break;
837 case PyTrace_RETURN:
Fred Drake62c1e3c2001-12-04 21:40:53 +0000838 if (pack_exit(self, tdelta) < 0)
839 return -1;
Fred Drake8c081a12001-10-12 20:57:55 +0000840 break;
841 default:
842 /* should never get here */
843 break;
844 }
845 return 0;
846}
847
848
849/* Alternate callback when we want PyTrace_LINE events */
850
851static int
852tracer_callback(ProfilerObject *self, PyFrameObject *frame, int what,
853 PyObject *arg)
854{
855 int fileno;
856
Fred Drake8c081a12001-10-12 20:57:55 +0000857 switch (what) {
858 case PyTrace_CALL:
859 fileno = get_fileno(self, frame->f_code);
860 if (fileno < 0)
861 return -1;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000862 return pack_enter(self, fileno,
863 self->frametimings ? get_tdelta(self) : -1,
864 frame->f_code->co_firstlineno);
865
Fred Drake8c081a12001-10-12 20:57:55 +0000866 case PyTrace_RETURN:
Fred Drake62c1e3c2001-12-04 21:40:53 +0000867 return pack_exit(self, get_tdelta(self));
868
Tim Peters1566a172001-10-12 22:08:39 +0000869 case PyTrace_LINE:
Fred Drake8c081a12001-10-12 20:57:55 +0000870 if (self->linetimings)
Fred Drake62c1e3c2001-12-04 21:40:53 +0000871 return pack_lineno_tdelta(self, frame->f_lineno, get_tdelta(self));
Fred Drake8c081a12001-10-12 20:57:55 +0000872 else
Fred Drake62c1e3c2001-12-04 21:40:53 +0000873 return pack_lineno(self, frame->f_lineno);
874
Fred Drake8c081a12001-10-12 20:57:55 +0000875 default:
876 /* ignore PyTrace_EXCEPTION */
877 break;
878 }
879 return 0;
880}
881
882
883/* A couple of useful helper functions. */
884
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000885#ifdef MS_WINDOWS
Tim Petersfeab23f2001-10-13 00:11:10 +0000886static LARGE_INTEGER frequency = {0, 0};
Fred Drake8c081a12001-10-12 20:57:55 +0000887#endif
888
889static unsigned long timeofday_diff = 0;
890static unsigned long rusage_diff = 0;
891
892static void
893calibrate(void)
894{
895 hs_time tv1, tv2;
896
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000897#ifdef MS_WINDOWS
Tim Peters7d99ff22001-10-13 07:37:52 +0000898 hs_time diff;
Fred Drake8c081a12001-10-12 20:57:55 +0000899 QueryPerformanceFrequency(&frequency);
900#endif
901
902 GETTIMEOFDAY(&tv1);
903 while (1) {
904 GETTIMEOFDAY(&tv2);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000905#ifdef MS_WINDOWS
Tim Peters7d99ff22001-10-13 07:37:52 +0000906 diff = tv2 - tv1;
907 if (diff != 0) {
908 timeofday_diff = (unsigned long)diff;
Fred Drake8c081a12001-10-12 20:57:55 +0000909 break;
910 }
911#else
912 if (tv1.tv_sec != tv2.tv_sec || tv1.tv_usec != tv2.tv_usec) {
913 if (tv1.tv_sec == tv2.tv_sec)
914 timeofday_diff = tv2.tv_usec - tv1.tv_usec;
915 else
916 timeofday_diff = (1000000 - tv1.tv_usec) + tv2.tv_usec;
917 break;
918 }
919#endif
920 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000921#if defined(MS_WINDOWS) || defined(macintosh) || defined(PYOS_OS2)
Fred Drake8c081a12001-10-12 20:57:55 +0000922 rusage_diff = -1;
923#else
924 {
925 struct rusage ru1, ru2;
926
927 getrusage(RUSAGE_SELF, &ru1);
928 while (1) {
929 getrusage(RUSAGE_SELF, &ru2);
930 if (ru1.ru_utime.tv_sec != ru2.ru_utime.tv_sec) {
931 rusage_diff = ((1000000 - ru1.ru_utime.tv_usec)
932 + ru2.ru_utime.tv_usec);
933 break;
934 }
935 else if (ru1.ru_utime.tv_usec != ru2.ru_utime.tv_usec) {
936 rusage_diff = ru2.ru_utime.tv_usec - ru1.ru_utime.tv_usec;
937 break;
938 }
939 else if (ru1.ru_stime.tv_sec != ru2.ru_stime.tv_sec) {
940 rusage_diff = ((1000000 - ru1.ru_stime.tv_usec)
941 + ru2.ru_stime.tv_usec);
942 break;
943 }
944 else if (ru1.ru_stime.tv_usec != ru2.ru_stime.tv_usec) {
945 rusage_diff = ru2.ru_stime.tv_usec - ru1.ru_stime.tv_usec;
946 break;
947 }
948 }
949 }
950#endif
951}
952
953static void
954do_start(ProfilerObject *self)
955{
956 self->active = 1;
957 GETTIMEOFDAY(&self->prev_timeofday);
958 if (self->lineevents)
959 PyEval_SetTrace((Py_tracefunc) tracer_callback, (PyObject *)self);
960 else
961 PyEval_SetProfile((Py_tracefunc) profiler_callback, (PyObject *)self);
962}
963
964static void
965do_stop(ProfilerObject *self)
966{
967 if (self->active) {
968 self->active = 0;
969 if (self->lineevents)
970 PyEval_SetTrace(NULL, NULL);
971 else
972 PyEval_SetProfile(NULL, NULL);
973 }
974 if (self->index > 0) {
975 /* Best effort to dump out any remaining data. */
976 flush_data(self);
977 }
978}
979
980static int
981is_available(ProfilerObject *self)
982{
983 if (self->active) {
984 PyErr_SetString(ProfilerError, "profiler already active");
985 return 0;
986 }
987 if (self->logfp == NULL) {
988 PyErr_SetString(ProfilerError, "profiler already closed");
989 return 0;
990 }
991 return 1;
992}
993
994
995/* Profiler object interface methods. */
996
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000997PyDoc_STRVAR(addinfo__doc__,
Fred Drake4c2e1af2001-10-29 20:45:57 +0000998"addinfo(key, value)\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000999"Insert an ADD_INFO record into the log.");
Fred Drake4c2e1af2001-10-29 20:45:57 +00001000
1001static PyObject *
1002profiler_addinfo(ProfilerObject *self, PyObject *args)
1003{
1004 PyObject *result = NULL;
1005 char *key, *value;
1006
1007 if (PyArg_ParseTuple(args, "ss:addinfo", &key, &value)) {
1008 if (self->logfp == NULL)
1009 PyErr_SetString(ProfilerError, "profiler already closed");
1010 else {
Fred Drake62c1e3c2001-12-04 21:40:53 +00001011 if (pack_add_info(self, key, value) == 0) {
1012 result = Py_None;
1013 Py_INCREF(result);
1014 }
Fred Drake4c2e1af2001-10-29 20:45:57 +00001015 }
1016 }
1017 return result;
1018}
1019
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001020PyDoc_STRVAR(close__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +00001021"close()\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001022"Shut down this profiler and close the log files, even if its active.");
Fred Drake8c081a12001-10-12 20:57:55 +00001023
1024static PyObject *
1025profiler_close(ProfilerObject *self, PyObject *args)
1026{
1027 PyObject *result = NULL;
1028
1029 if (PyArg_ParseTuple(args, ":close")) {
1030 do_stop(self);
1031 if (self->logfp != NULL) {
1032 fclose(self->logfp);
1033 self->logfp = NULL;
1034 }
1035 Py_INCREF(Py_None);
1036 result = Py_None;
1037 }
1038 return result;
1039}
1040
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001041PyDoc_STRVAR(runcall__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +00001042"runcall(callable[, args[, kw]]) -> callable()\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001043"Profile a specific function call, returning the result of that call.");
Fred Drake8c081a12001-10-12 20:57:55 +00001044
1045static PyObject *
1046profiler_runcall(ProfilerObject *self, PyObject *args)
1047{
1048 PyObject *result = NULL;
1049 PyObject *callargs = NULL;
1050 PyObject *callkw = NULL;
1051 PyObject *callable;
1052
1053 if (PyArg_ParseTuple(args, "O|OO:runcall",
1054 &callable, &callargs, &callkw)) {
1055 if (is_available(self)) {
1056 do_start(self);
1057 result = PyEval_CallObjectWithKeywords(callable, callargs, callkw);
1058 do_stop(self);
1059 }
1060 }
1061 return result;
1062}
1063
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001064PyDoc_STRVAR(runcode__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +00001065"runcode(code, globals[, locals])\n"
1066"Execute a code object while collecting profile data. If locals is\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001067"omitted, globals is used for the locals as well.");
Fred Drake8c081a12001-10-12 20:57:55 +00001068
1069static PyObject *
1070profiler_runcode(ProfilerObject *self, PyObject *args)
1071{
1072 PyObject *result = NULL;
1073 PyCodeObject *code;
1074 PyObject *globals;
1075 PyObject *locals = NULL;
1076
1077 if (PyArg_ParseTuple(args, "O!O!|O:runcode",
1078 &PyCode_Type, &code,
1079 &PyDict_Type, &globals,
1080 &locals)) {
1081 if (is_available(self)) {
1082 if (locals == NULL || locals == Py_None)
1083 locals = globals;
1084 else if (!PyDict_Check(locals)) {
1085 PyErr_SetString(PyExc_TypeError,
1086 "locals must be a dictionary or None");
1087 return NULL;
1088 }
1089 do_start(self);
1090 result = PyEval_EvalCode(code, globals, locals);
1091 do_stop(self);
1092#if 0
1093 if (!PyErr_Occurred()) {
1094 result = Py_None;
1095 Py_INCREF(result);
1096 }
1097#endif
1098 }
1099 }
1100 return result;
1101}
1102
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001103PyDoc_STRVAR(start__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +00001104"start()\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001105"Install this profiler for the current thread.");
Fred Drake8c081a12001-10-12 20:57:55 +00001106
1107static PyObject *
1108profiler_start(ProfilerObject *self, PyObject *args)
1109{
1110 PyObject *result = NULL;
1111
1112 if (PyArg_ParseTuple(args, ":start")) {
Fred Drake2c146bf2002-02-08 21:27:50 +00001113 if (is_available(self)) {
Fred Drake8c081a12001-10-12 20:57:55 +00001114 do_start(self);
Fred Drake2c146bf2002-02-08 21:27:50 +00001115 result = Py_None;
1116 Py_INCREF(result);
1117 }
Fred Drake8c081a12001-10-12 20:57:55 +00001118 }
1119 return result;
1120}
1121
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001122PyDoc_STRVAR(stop__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +00001123"stop()\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001124"Remove this profiler from the current thread.");
Fred Drake8c081a12001-10-12 20:57:55 +00001125
1126static PyObject *
1127profiler_stop(ProfilerObject *self, PyObject *args)
1128{
1129 PyObject *result = NULL;
1130
1131 if (PyArg_ParseTuple(args, ":stop")) {
1132 if (!self->active)
1133 PyErr_SetString(ProfilerError, "profiler not active");
Fred Drake2c146bf2002-02-08 21:27:50 +00001134 else {
Fred Drake8c081a12001-10-12 20:57:55 +00001135 do_stop(self);
Fred Drake2c146bf2002-02-08 21:27:50 +00001136 result = Py_None;
1137 Py_INCREF(result);
1138 }
Fred Drake8c081a12001-10-12 20:57:55 +00001139 }
1140 return result;
1141}
1142
1143
1144/* Python API support. */
1145
1146static void
1147profiler_dealloc(ProfilerObject *self)
1148{
1149 do_stop(self);
1150 if (self->logfp != NULL)
1151 fclose(self->logfp);
1152 Py_XDECREF(self->filemap);
1153 Py_XDECREF(self->logfilename);
1154 PyObject_Del((PyObject *)self);
1155}
1156
Fred Drake8c081a12001-10-12 20:57:55 +00001157static PyMethodDef profiler_methods[] = {
Fred Drake4c2e1af2001-10-29 20:45:57 +00001158 {"addinfo", (PyCFunction)profiler_addinfo, METH_VARARGS, addinfo__doc__},
Fred Drake8c081a12001-10-12 20:57:55 +00001159 {"close", (PyCFunction)profiler_close, METH_VARARGS, close__doc__},
1160 {"runcall", (PyCFunction)profiler_runcall, METH_VARARGS, runcall__doc__},
1161 {"runcode", (PyCFunction)profiler_runcode, METH_VARARGS, runcode__doc__},
1162 {"start", (PyCFunction)profiler_start, METH_VARARGS, start__doc__},
1163 {"stop", (PyCFunction)profiler_stop, METH_VARARGS, stop__doc__},
1164 {NULL, NULL}
1165};
1166
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001167static PyMemberDef profiler_members[] = {
Fred Drake30d1c752001-10-15 22:11:02 +00001168 {"frametimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
1169 {"lineevents", T_LONG, offsetof(ProfilerObject, lineevents), READONLY},
1170 {"linetimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
Fred Drake8c081a12001-10-12 20:57:55 +00001171 {NULL}
1172};
1173
1174static PyObject *
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001175profiler_get_closed(ProfilerObject *self, void *closure)
Fred Drake8c081a12001-10-12 20:57:55 +00001176{
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001177 PyObject *result = (self->logfp == NULL) ? Py_True : Py_False;
1178 Py_INCREF(result);
Fred Drake8c081a12001-10-12 20:57:55 +00001179 return result;
1180}
1181
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001182static PyGetSetDef profiler_getsets[] = {
1183 {"closed", (getter)profiler_get_closed, NULL},
1184 {NULL}
1185};
1186
Fred Drake8c081a12001-10-12 20:57:55 +00001187
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001188PyDoc_STRVAR(profiler_object__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +00001189"High-performance profiler object.\n"
1190"\n"
1191"Methods:\n"
1192"\n"
Fred Drake30d1c752001-10-15 22:11:02 +00001193"close(): Stop the profiler and close the log files.\n"
1194"runcall(): Run a single function call with profiling enabled.\n"
1195"runcode(): Execute a code object with profiling enabled.\n"
1196"start(): Install the profiler and return.\n"
1197"stop(): Remove the profiler.\n"
Tim Petersfeab23f2001-10-13 00:11:10 +00001198"\n"
1199"Attributes (read-only):\n"
1200"\n"
Fred Drake30d1c752001-10-15 22:11:02 +00001201"closed: True if the profiler has already been closed.\n"
1202"frametimings: True if ENTER/EXIT events collect timing information.\n"
1203"lineevents: True if SET_LINENO events are reported to the profiler.\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001204"linetimings: True if SET_LINENO events collect timing information.");
Fred Drake8c081a12001-10-12 20:57:55 +00001205
1206static PyTypeObject ProfilerType = {
1207 PyObject_HEAD_INIT(NULL)
1208 0, /* ob_size */
Fred Drake4c2e1af2001-10-29 20:45:57 +00001209 "_hotshot.ProfilerType", /* tp_name */
Fred Drake8c081a12001-10-12 20:57:55 +00001210 (int) sizeof(ProfilerObject), /* tp_basicsize */
1211 0, /* tp_itemsize */
1212 (destructor)profiler_dealloc, /* tp_dealloc */
1213 0, /* tp_print */
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001214 0, /* tp_getattr */
Fred Drake8c081a12001-10-12 20:57:55 +00001215 0, /* tp_setattr */
1216 0, /* tp_compare */
1217 0, /* tp_repr */
1218 0, /* tp_as_number */
1219 0, /* tp_as_sequence */
1220 0, /* tp_as_mapping */
1221 0, /* tp_hash */
1222 0, /* tp_call */
1223 0, /* tp_str */
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001224 PyObject_GenericGetAttr, /* tp_getattro */
Fred Drake8c081a12001-10-12 20:57:55 +00001225 0, /* tp_setattro */
1226 0, /* tp_as_buffer */
Fred Drake4c2e1af2001-10-29 20:45:57 +00001227 Py_TPFLAGS_DEFAULT, /* tp_flags */
Fred Drake8c081a12001-10-12 20:57:55 +00001228 profiler_object__doc__, /* tp_doc */
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001229 0, /* tp_traverse */
1230 0, /* tp_clear */
1231 0, /* tp_richcompare */
1232 0, /* tp_weaklistoffset */
1233 0, /* tp_iter */
1234 0, /* tp_iternext */
1235 profiler_methods, /* tp_methods */
1236 profiler_members, /* tp_members */
1237 profiler_getsets, /* tp_getset */
1238 0, /* tp_base */
1239 0, /* tp_dict */
1240 0, /* tp_descr_get */
1241 0, /* tp_descr_set */
Fred Drake8c081a12001-10-12 20:57:55 +00001242};
1243
1244
1245static PyMethodDef logreader_methods[] = {
1246 {"close", (PyCFunction)logreader_close, METH_VARARGS,
1247 logreader_close__doc__},
Fred Drake8c081a12001-10-12 20:57:55 +00001248 {NULL, NULL}
1249};
1250
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001251static PyMemberDef logreader_members[] = {
1252 {"info", T_OBJECT, offsetof(LogReaderObject, info), RO},
1253 {NULL}
1254};
Fred Drake8c081a12001-10-12 20:57:55 +00001255
1256
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001257PyDoc_STRVAR(logreader__doc__,
1258"logreader(filename) --> log-iterator\n\
1259Create a log-reader for the timing information file.");
Fred Drake8c081a12001-10-12 20:57:55 +00001260
1261static PySequenceMethods logreader_as_sequence = {
1262 0, /* sq_length */
1263 0, /* sq_concat */
1264 0, /* sq_repeat */
1265 (intargfunc)logreader_sq_item, /* sq_item */
1266 0, /* sq_slice */
1267 0, /* sq_ass_item */
1268 0, /* sq_ass_slice */
1269 0, /* sq_contains */
1270 0, /* sq_inplace_concat */
1271 0, /* sq_inplace_repeat */
1272};
1273
1274static PyTypeObject LogReaderType = {
1275 PyObject_HEAD_INIT(NULL)
1276 0, /* ob_size */
Fred Drake4c2e1af2001-10-29 20:45:57 +00001277 "_hotshot.LogReaderType", /* tp_name */
Fred Drake8c081a12001-10-12 20:57:55 +00001278 (int) sizeof(LogReaderObject), /* tp_basicsize */
1279 0, /* tp_itemsize */
1280 (destructor)logreader_dealloc, /* tp_dealloc */
1281 0, /* tp_print */
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001282 0, /* tp_getattr */
Fred Drake8c081a12001-10-12 20:57:55 +00001283 0, /* tp_setattr */
1284 0, /* tp_compare */
1285 0, /* tp_repr */
1286 0, /* tp_as_number */
1287 &logreader_as_sequence, /* tp_as_sequence */
1288 0, /* tp_as_mapping */
1289 0, /* tp_hash */
1290 0, /* tp_call */
1291 0, /* tp_str */
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001292 PyObject_GenericGetAttr, /* tp_getattro */
Fred Drake8c081a12001-10-12 20:57:55 +00001293 0, /* tp_setattro */
1294 0, /* tp_as_buffer */
Fred Drake4c2e1af2001-10-29 20:45:57 +00001295 Py_TPFLAGS_DEFAULT, /* tp_flags */
Fred Drake8c081a12001-10-12 20:57:55 +00001296 logreader__doc__, /* tp_doc */
Fred Drake8c081a12001-10-12 20:57:55 +00001297 0, /* tp_traverse */
1298 0, /* tp_clear */
1299 0, /* tp_richcompare */
1300 0, /* tp_weaklistoffset */
1301 (getiterfunc)logreader_tp_iter, /* tp_iter */
1302 (iternextfunc)logreader_tp_iternext,/* tp_iternext */
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001303 logreader_methods, /* tp_methods */
1304 logreader_members, /* tp_members */
1305 0, /* tp_getset */
1306 0, /* tp_base */
1307 0, /* tp_dict */
1308 0, /* tp_descr_get */
1309 0, /* tp_descr_set */
Fred Drake8c081a12001-10-12 20:57:55 +00001310};
1311
1312static PyObject *
1313hotshot_logreader(PyObject *unused, PyObject *args)
1314{
1315 LogReaderObject *self = NULL;
1316 char *filename;
Neil Schemenauer8b6b4912002-05-29 18:19:14 +00001317 int c;
1318 int err = 0;
Fred Drake8c081a12001-10-12 20:57:55 +00001319
1320 if (PyArg_ParseTuple(args, "s:logreader", &filename)) {
1321 self = PyObject_New(LogReaderObject, &LogReaderType);
1322 if (self != NULL) {
Fred Drake30d1c752001-10-15 22:11:02 +00001323 self->frametimings = 1;
Fred Drake8c081a12001-10-12 20:57:55 +00001324 self->linetimings = 0;
Fred Drake4c2e1af2001-10-29 20:45:57 +00001325 self->info = NULL;
Fred Drake8c081a12001-10-12 20:57:55 +00001326 self->logfp = fopen(filename, "rb");
1327 if (self->logfp == NULL) {
1328 PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
1329 Py_DECREF(self);
1330 self = NULL;
Fred Drake4c2e1af2001-10-29 20:45:57 +00001331 goto finally;
1332 }
1333 self->info = PyDict_New();
1334 if (self->info == NULL) {
1335 Py_DECREF(self);
1336 goto finally;
1337 }
Neil Schemenauer8b6b4912002-05-29 18:19:14 +00001338 /* read initial info */
1339 for (;;) {
1340 if ((c = fgetc(self->logfp)) == EOF) {
1341 eof_error();
1342 break;
1343 }
1344 if (c != WHAT_ADD_INFO) {
1345 ungetc(c, self->logfp);
1346 break;
1347 }
1348 err = unpack_add_info(self);
Fred Drake4c2e1af2001-10-29 20:45:57 +00001349 if (err) {
1350 if (err == ERR_EOF)
1351 eof_error();
1352 else
1353 PyErr_SetString(PyExc_RuntimeError,
1354 "unexpected error");
1355 break;
1356 }
Fred Drake8c081a12001-10-12 20:57:55 +00001357 }
1358 }
1359 }
Fred Drake4c2e1af2001-10-29 20:45:57 +00001360 finally:
Fred Drake8c081a12001-10-12 20:57:55 +00001361 return (PyObject *) self;
1362}
1363
1364
1365/* Return a Python string that represents the version number without the
1366 * extra cruft added by revision control, even if the right options were
1367 * given to the "cvs export" command to make it not include the extra
1368 * cruft.
1369 */
1370static char *
1371get_version_string(void)
1372{
1373 static char *rcsid = "$Revision$";
1374 char *rev = rcsid;
1375 char *buffer;
1376 int i = 0;
1377
Neal Norwitz3afb2d22002-03-20 21:32:07 +00001378 while (*rev && !isdigit((int)*rev))
Fred Drake8c081a12001-10-12 20:57:55 +00001379 ++rev;
1380 while (rev[i] != ' ' && rev[i] != '\0')
1381 ++i;
1382 buffer = malloc(i + 1);
1383 if (buffer != NULL) {
1384 memmove(buffer, rev, i);
1385 buffer[i] = '\0';
1386 }
1387 return buffer;
1388}
1389
1390/* Write out a RFC 822-style header with various useful bits of
1391 * information to make the output easier to manage.
1392 */
1393static int
1394write_header(ProfilerObject *self)
1395{
1396 char *buffer;
1397 char cwdbuffer[PATH_MAX];
1398 PyObject *temp;
1399 int i, len;
1400
1401 buffer = get_version_string();
1402 if (buffer == NULL) {
1403 PyErr_NoMemory();
1404 return -1;
1405 }
Fred Drake4c2e1af2001-10-29 20:45:57 +00001406 pack_add_info(self, "hotshot-version", buffer);
1407 pack_add_info(self, "requested-frame-timings",
1408 (self->frametimings ? "yes" : "no"));
1409 pack_add_info(self, "requested-line-events",
Fred Drake8c081a12001-10-12 20:57:55 +00001410 (self->lineevents ? "yes" : "no"));
Fred Drake4c2e1af2001-10-29 20:45:57 +00001411 pack_add_info(self, "requested-line-timings",
1412 (self->linetimings ? "yes" : "no"));
1413 pack_add_info(self, "platform", Py_GetPlatform());
1414 pack_add_info(self, "executable", Py_GetProgramFullPath());
Fred Drakef12a68c2001-11-09 15:59:36 +00001415 free(buffer);
Fred Drake8c081a12001-10-12 20:57:55 +00001416 buffer = (char *) Py_GetVersion();
1417 if (buffer == NULL)
1418 PyErr_Clear();
1419 else
Fred Drake4c2e1af2001-10-29 20:45:57 +00001420 pack_add_info(self, "executable-version", buffer);
Fred Drake8c081a12001-10-12 20:57:55 +00001421
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001422#ifdef MS_WINDOWS
Tim Peters885d4572001-11-28 20:27:42 +00001423 PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%I64d", frequency.QuadPart);
Fred Drake4c2e1af2001-10-29 20:45:57 +00001424 pack_add_info(self, "reported-performance-frequency", cwdbuffer);
Fred Drake8c081a12001-10-12 20:57:55 +00001425#else
Tim Peters885d4572001-11-28 20:27:42 +00001426 PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", rusage_diff);
Fred Drake4c2e1af2001-10-29 20:45:57 +00001427 pack_add_info(self, "observed-interval-getrusage", cwdbuffer);
Tim Peters885d4572001-11-28 20:27:42 +00001428 PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", timeofday_diff);
Fred Drake4c2e1af2001-10-29 20:45:57 +00001429 pack_add_info(self, "observed-interval-gettimeofday", cwdbuffer);
Fred Drake8c081a12001-10-12 20:57:55 +00001430#endif
Fred Drake8c081a12001-10-12 20:57:55 +00001431
Fred Drake4c2e1af2001-10-29 20:45:57 +00001432 pack_add_info(self, "current-directory",
Fred Drake8c081a12001-10-12 20:57:55 +00001433 getcwd(cwdbuffer, sizeof cwdbuffer));
1434
1435 temp = PySys_GetObject("path");
1436 len = PyList_GET_SIZE(temp);
1437 for (i = 0; i < len; ++i) {
1438 PyObject *item = PyList_GET_ITEM(temp, i);
1439 buffer = PyString_AsString(item);
1440 if (buffer == NULL)
1441 return -1;
Fred Drake4c2e1af2001-10-29 20:45:57 +00001442 pack_add_info(self, "sys-path-entry", buffer);
Fred Drake8c081a12001-10-12 20:57:55 +00001443 }
Fred Drake4c2e1af2001-10-29 20:45:57 +00001444 pack_frame_times(self);
1445 pack_line_times(self);
1446
Fred Drake8c081a12001-10-12 20:57:55 +00001447 return 0;
1448}
1449
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001450PyDoc_STRVAR(profiler__doc__,
1451"profiler(logfilename[, lineevents[, linetimes]]) -> profiler\n\
1452Create a new profiler object.");
Fred Drake8c081a12001-10-12 20:57:55 +00001453
1454static PyObject *
1455hotshot_profiler(PyObject *unused, PyObject *args)
1456{
1457 char *logfilename;
1458 ProfilerObject *self = NULL;
1459 int lineevents = 0;
1460 int linetimings = 1;
1461
1462 if (PyArg_ParseTuple(args, "s|ii:profiler", &logfilename,
1463 &lineevents, &linetimings)) {
1464 self = PyObject_New(ProfilerObject, &ProfilerType);
1465 if (self == NULL)
1466 return NULL;
Fred Drake30d1c752001-10-15 22:11:02 +00001467 self->frametimings = 1;
Fred Drake8c081a12001-10-12 20:57:55 +00001468 self->lineevents = lineevents ? 1 : 0;
1469 self->linetimings = (lineevents && linetimings) ? 1 : 0;
1470 self->index = 0;
1471 self->active = 0;
1472 self->next_fileno = 0;
Tim Peters1566a172001-10-12 22:08:39 +00001473 self->logfp = NULL;
Fred Drake8c081a12001-10-12 20:57:55 +00001474 self->logfilename = PyTuple_GET_ITEM(args, 0);
1475 Py_INCREF(self->logfilename);
1476 self->filemap = PyDict_New();
1477 if (self->filemap == NULL) {
1478 Py_DECREF(self);
1479 return NULL;
1480 }
1481 self->logfp = fopen(logfilename, "wb");
1482 if (self->logfp == NULL) {
1483 Py_DECREF(self);
1484 PyErr_SetFromErrnoWithFilename(PyExc_IOError, logfilename);
1485 return NULL;
1486 }
1487 if (timeofday_diff == 0) {
1488 /* Run this several times since sometimes the first
1489 * doesn't give the lowest values, and we're really trying
1490 * to determine the lowest.
1491 */
1492 calibrate();
1493 calibrate();
1494 calibrate();
1495 }
1496 if (write_header(self))
1497 /* some error occurred, exception has been set */
1498 self = NULL;
1499 }
1500 return (PyObject *) self;
1501}
1502
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001503PyDoc_STRVAR(coverage__doc__,
1504"coverage(logfilename) -> profiler\n\
Fred Drake30d1c752001-10-15 22:11:02 +00001505Returns a profiler that doesn't collect any timing information, which is\n\
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001506useful in building a coverage analysis tool.");
Fred Drake30d1c752001-10-15 22:11:02 +00001507
1508static PyObject *
1509hotshot_coverage(PyObject *unused, PyObject *args)
1510{
1511 char *logfilename;
1512 PyObject *result = NULL;
1513
1514 if (PyArg_ParseTuple(args, "s:coverage", &logfilename)) {
1515 result = hotshot_profiler(unused, args);
1516 if (result != NULL) {
1517 ProfilerObject *self = (ProfilerObject *) result;
1518 self->frametimings = 0;
1519 self->linetimings = 0;
1520 self->lineevents = 1;
1521 }
1522 }
1523 return result;
1524}
1525
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001526PyDoc_VAR(resolution__doc__) =
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001527#ifdef MS_WINDOWS
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001528PyDoc_STR(
Tim Petersfeab23f2001-10-13 00:11:10 +00001529"resolution() -> (performance-counter-ticks, update-frequency)\n"
1530"Return the resolution of the timer provided by the QueryPerformanceCounter()\n"
1531"function. The first value is the smallest observed change, and the second\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001532"is the result of QueryPerformanceFrequency()."
1533)
Fred Drake8c081a12001-10-12 20:57:55 +00001534#else
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001535PyDoc_STR(
Tim Petersfeab23f2001-10-13 00:11:10 +00001536"resolution() -> (gettimeofday-usecs, getrusage-usecs)\n"
1537"Return the resolution of the timers provided by the gettimeofday() and\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001538"getrusage() system calls, or -1 if the call is not supported."
1539)
Fred Drake8c081a12001-10-12 20:57:55 +00001540#endif
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001541;
Fred Drake8c081a12001-10-12 20:57:55 +00001542
1543static PyObject *
1544hotshot_resolution(PyObject *unused, PyObject *args)
1545{
1546 PyObject *result = NULL;
1547
1548 if (PyArg_ParseTuple(args, ":resolution")) {
1549 if (timeofday_diff == 0) {
1550 calibrate();
1551 calibrate();
1552 calibrate();
1553 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001554#ifdef MS_WINDOWS
Fred Drake8c081a12001-10-12 20:57:55 +00001555 result = Py_BuildValue("ii", timeofday_diff, frequency.LowPart);
1556#else
1557 result = Py_BuildValue("ii", timeofday_diff, rusage_diff);
1558#endif
1559 }
1560 return result;
1561}
1562
1563
1564static PyMethodDef functions[] = {
Fred Drake30d1c752001-10-15 22:11:02 +00001565 {"coverage", hotshot_coverage, METH_VARARGS, coverage__doc__},
Fred Drake8c081a12001-10-12 20:57:55 +00001566 {"profiler", hotshot_profiler, METH_VARARGS, profiler__doc__},
1567 {"logreader", hotshot_logreader, METH_VARARGS, logreader__doc__},
1568 {"resolution", hotshot_resolution, METH_VARARGS, resolution__doc__},
1569 {NULL, NULL}
1570};
1571
1572
1573void
1574init_hotshot(void)
1575{
1576 PyObject *module;
1577
1578 LogReaderType.ob_type = &PyType_Type;
1579 ProfilerType.ob_type = &PyType_Type;
1580 module = Py_InitModule("_hotshot", functions);
1581 if (module != NULL) {
1582 char *s = get_version_string();
1583
1584 PyModule_AddStringConstant(module, "__version__", s);
1585 free(s);
1586 Py_INCREF(&LogReaderType);
1587 PyModule_AddObject(module, "LogReaderType",
1588 (PyObject *)&LogReaderType);
1589 Py_INCREF(&ProfilerType);
1590 PyModule_AddObject(module, "ProfilerType",
1591 (PyObject *)&ProfilerType);
1592
1593 if (ProfilerError == NULL)
1594 ProfilerError = PyErr_NewException("hotshot.ProfilerError",
1595 NULL, NULL);
1596 if (ProfilerError != NULL) {
1597 Py_INCREF(ProfilerError);
1598 PyModule_AddObject(module, "ProfilerError", ProfilerError);
1599 }
1600 PyModule_AddIntConstant(module, "WHAT_ENTER", WHAT_ENTER);
1601 PyModule_AddIntConstant(module, "WHAT_EXIT", WHAT_EXIT);
1602 PyModule_AddIntConstant(module, "WHAT_LINENO", WHAT_LINENO);
1603 PyModule_AddIntConstant(module, "WHAT_OTHER", WHAT_OTHER);
1604 PyModule_AddIntConstant(module, "WHAT_ADD_INFO", WHAT_ADD_INFO);
1605 PyModule_AddIntConstant(module, "WHAT_DEFINE_FILE", WHAT_DEFINE_FILE);
Fred Drake30d1c752001-10-15 22:11:02 +00001606 PyModule_AddIntConstant(module, "WHAT_DEFINE_FUNC", WHAT_DEFINE_FUNC);
Fred Drake8c081a12001-10-12 20:57:55 +00001607 PyModule_AddIntConstant(module, "WHAT_LINE_TIMES", WHAT_LINE_TIMES);
1608 }
1609}