blob: 1908a2db653d902c9cab0565108bc5e6c625b262 [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
Martin v. Löwis8eb92a02002-09-19 08:03:21 +000058#if defined(__sgi) && _COMPILER_VERSION>700 && !defined(PATH_MAX)
59/* fix PATH_MAX not being defined with MIPSPro 7.x
60 if mode is ANSI C (default) */
61#define PATH_MAX 1024
62#endif
63
Tim Peters1566a172001-10-12 22:08:39 +000064#ifndef PATH_MAX
65# ifdef MAX_PATH
66# define PATH_MAX MAX_PATH
67# else
68# error "Need a defn. for PATH_MAX in _hotshot.c"
69# endif
70#endif
71
Fred Drake8c081a12001-10-12 20:57:55 +000072typedef struct {
73 PyObject_HEAD
74 PyObject *filemap;
75 PyObject *logfilename;
76 int index;
77 unsigned char buffer[BUFFERSIZE];
78 FILE *logfp;
79 int lineevents;
80 int linetimings;
Fred Drake30d1c752001-10-15 22:11:02 +000081 int frametimings;
Fred Drake8c081a12001-10-12 20:57:55 +000082 /* size_t filled; */
83 int active;
84 int next_fileno;
Fred Drake8c081a12001-10-12 20:57:55 +000085 hs_time prev_timeofday;
86} ProfilerObject;
87
88typedef struct {
89 PyObject_HEAD
Fred Drake4c2e1af2001-10-29 20:45:57 +000090 PyObject *info;
Fred Drake8c081a12001-10-12 20:57:55 +000091 FILE *logfp;
Fred Drake8c081a12001-10-12 20:57:55 +000092 int linetimings;
Fred Drake30d1c752001-10-15 22:11:02 +000093 int frametimings;
Fred Drake8c081a12001-10-12 20:57:55 +000094} LogReaderObject;
95
96static PyObject * ProfilerError = NULL;
97
98
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000099#ifndef MS_WINDOWS
Fred Drake8c081a12001-10-12 20:57:55 +0000100#ifdef GETTIMEOFDAY_NO_TZ
101#define GETTIMEOFDAY(ptv) gettimeofday((ptv))
102#else
103#define GETTIMEOFDAY(ptv) gettimeofday((ptv), (struct timezone *)NULL)
104#endif
105#endif
106
107
108/* The log reader... */
109
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000110PyDoc_STRVAR(logreader_close__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +0000111"close()\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000112"Close the log file, preventing additional records from being read.");
Fred Drake8c081a12001-10-12 20:57:55 +0000113
114static PyObject *
115logreader_close(LogReaderObject *self, PyObject *args)
116{
Fred Drake666bf522002-07-18 19:11:44 +0000117 if (self->logfp != NULL) {
118 fclose(self->logfp);
119 self->logfp = NULL;
Fred Drake8c081a12001-10-12 20:57:55 +0000120 }
Fred Drake666bf522002-07-18 19:11:44 +0000121 Py_INCREF(Py_None);
122
123 return Py_None;
124}
125
126PyDoc_STRVAR(logreader_fileno__doc__,
127"fileno() -> file descriptor\n"
128"Returns the file descriptor for the log file, if open.\n"
129"Raises ValueError if the log file is closed.");
130
131static PyObject *
132logreader_fileno(LogReaderObject *self)
133{
134 if (self->logfp == NULL) {
135 PyErr_SetString(PyExc_ValueError,
136 "logreader's file object already closed");
137 return NULL;
138 }
139 return PyInt_FromLong(fileno(self->logfp));
Fred Drake8c081a12001-10-12 20:57:55 +0000140}
141
Fred Drake8c081a12001-10-12 20:57:55 +0000142static PyObject *
143logreader_tp_iter(LogReaderObject *self)
144{
145 Py_INCREF(self);
146 return (PyObject *) self;
147}
Fred Drake8c081a12001-10-12 20:57:55 +0000148
149
150/* Log File Format
151 * ---------------
152 *
153 * The log file consists of a sequence of variable-length records.
154 * Each record is identified with a record type identifier in two
155 * bits of the first byte. The two bits are the "least significant"
156 * bits of the byte.
157 *
158 * Low bits: Opcode: Meaning:
159 * 0x00 ENTER enter a frame
160 * 0x01 EXIT exit a frame
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000161 * 0x02 LINENO execution moved onto a different line
Fred Drake8c081a12001-10-12 20:57:55 +0000162 * 0x03 OTHER more bits are needed to deecode
163 *
164 * If the type is OTHER, the record is not packed so tightly, and the
165 * remaining bits are used to disambiguate the record type. These
166 * records are not used as frequently so compaction is not an issue.
167 * Each of the first three record types has a highly tailored
168 * structure that allows it to be packed tightly.
169 *
170 * The OTHER records have the following identifiers:
171 *
172 * First byte: Opcode: Meaning:
173 * 0x13 ADD_INFO define a key/value pair
174 * 0x23 DEFINE_FILE define an int->filename mapping
175 * 0x33 LINE_TIMES indicates if LINENO events have tdeltas
Fred Drake30d1c752001-10-15 22:11:02 +0000176 * 0x43 DEFINE_FUNC define a (fileno,lineno)->funcname mapping
177 * 0x53 FRAME_TIMES indicates if ENTER/EXIT events have tdeltas
Fred Drake8c081a12001-10-12 20:57:55 +0000178 *
179 * Packed Integers
180 *
181 * "Packed integers" are non-negative integer values encoded as a
182 * sequence of bytes. Each byte is encoded such that the most
183 * significant bit is set if the next byte is also part of the
184 * integer. Each byte provides bits to the least-significant end of
185 * the result; the accumulated value must be shifted up to place the
186 * new bits into the result.
187 *
188 * "Modified packed integers" are packed integers where only a portion
189 * of the first byte is used. In the rest of the specification, these
190 * are referred to as "MPI(n,name)", where "n" is the number of bits
191 * discarded from the least-signicant positions of the byte, and
192 * "name" is a name being given to those "discarded" bits, since they
193 * are a field themselves.
194 *
195 * ENTER records:
196 *
197 * MPI(2,type) fileno -- type is 0x00
Fred Drake8c081a12001-10-12 20:57:55 +0000198 * PI lineno
Fred Drake30d1c752001-10-15 22:11:02 +0000199 * PI tdelta -- iff frame times are enabled
Fred Drake8c081a12001-10-12 20:57:55 +0000200 *
201 * EXIT records
202 *
Fred Drake30d1c752001-10-15 22:11:02 +0000203 * MPI(2,type) tdelta -- type is 0x01; tdelta will be 0
204 * if frame times are disabled
Fred Drake8c081a12001-10-12 20:57:55 +0000205 *
206 * LINENO records
207 *
208 * MPI(2,type) lineno -- type is 0x02
209 * PI tdelta -- iff LINENO includes it
210 *
211 * ADD_INFO records
212 *
Fred Drake30d1c752001-10-15 22:11:02 +0000213 * BYTE type -- always 0x13
Fred Drake8c081a12001-10-12 20:57:55 +0000214 * PI len1 -- length of first string
215 * BYTE string1[len1] -- len1 bytes of string data
216 * PI len2 -- length of second string
217 * BYTE string2[len2] -- len2 bytes of string data
218 *
219 * DEFINE_FILE records
220 *
Fred Drake30d1c752001-10-15 22:11:02 +0000221 * BYTE type -- always 0x23
Fred Drake8c081a12001-10-12 20:57:55 +0000222 * PI fileno
223 * PI len -- length of filename
224 * BYTE filename[len] -- len bytes of string data
225 *
Fred Drake30d1c752001-10-15 22:11:02 +0000226 * DEFINE_FUNC records
227 *
228 * BYTE type -- always 0x43
229 * PI fileno
230 * PI lineno
231 * PI len -- length of funcname
232 * BYTE funcname[len] -- len bytes of string data
233 *
Fred Drake8c081a12001-10-12 20:57:55 +0000234 * LINE_TIMES records
Fred Drake30d1c752001-10-15 22:11:02 +0000235 *
236 * This record can be used only before the start of ENTER/EXIT/LINENO
237 * records. If have_tdelta is true, LINENO records will include the
238 * tdelta field, otherwise it will be omitted. If this record is not
239 * given, LINENO records will not contain the tdelta field.
240 *
241 * BYTE type -- always 0x33
Fred Drake8c081a12001-10-12 20:57:55 +0000242 * BYTE have_tdelta -- 0 if LINENO does *not* have
243 * timing information
Fred Drake30d1c752001-10-15 22:11:02 +0000244 * FRAME_TIMES records
245 *
246 * This record can be used only before the start of ENTER/EXIT/LINENO
247 * records. If have_tdelta is true, ENTER and EXIT records will
248 * include the tdelta field, otherwise it will be omitted. If this
249 * record is not given, ENTER and EXIT records will contain the tdelta
250 * field.
251 *
252 * BYTE type -- always 0x53
253 * BYTE have_tdelta -- 0 if ENTER/EXIT do *not* have
254 * timing information
Fred Drake8c081a12001-10-12 20:57:55 +0000255 */
256
257#define WHAT_ENTER 0x00
258#define WHAT_EXIT 0x01
259#define WHAT_LINENO 0x02
260#define WHAT_OTHER 0x03 /* only used in decoding */
261#define WHAT_ADD_INFO 0x13
262#define WHAT_DEFINE_FILE 0x23
263#define WHAT_LINE_TIMES 0x33
Fred Drake30d1c752001-10-15 22:11:02 +0000264#define WHAT_DEFINE_FUNC 0x43
265#define WHAT_FRAME_TIMES 0x53
Fred Drake8c081a12001-10-12 20:57:55 +0000266
267#define ERR_NONE 0
268#define ERR_EOF -1
269#define ERR_EXCEPTION -2
Fred Drake4c2e1af2001-10-29 20:45:57 +0000270#define ERR_BAD_RECTYPE -3
Fred Drake8c081a12001-10-12 20:57:55 +0000271
272#define PISIZE (sizeof(int) + 1)
273#define MPISIZE (PISIZE + 1)
274
275/* Maximum size of "normal" events -- nothing that contains string data */
276#define MAXEVENTSIZE (MPISIZE + PISIZE*2)
277
278
279/* Unpack a packed integer; if "discard" is non-zero, unpack a modified
280 * packed integer with "discard" discarded bits.
281 */
282static int
283unpack_packed_int(LogReaderObject *self, int *pvalue, int discard)
284{
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000285 int c;
Fred Drake8c081a12001-10-12 20:57:55 +0000286 int accum = 0;
287 int bits = 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000288 int cont;
289
290 do {
Fred Drake8c081a12001-10-12 20:57:55 +0000291 /* read byte */
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000292 if ((c = fgetc(self->logfp)) == EOF)
293 return ERR_EOF;
294 accum |= ((c & 0x7F) >> discard) << bits;
Fred Drake8c081a12001-10-12 20:57:55 +0000295 bits += (7 - discard);
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000296 cont = c & 0x80;
Fred Drake8c081a12001-10-12 20:57:55 +0000297 discard = 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000298 } while (cont);
299
Fred Drake8c081a12001-10-12 20:57:55 +0000300 *pvalue = accum;
301
302 return 0;
303}
304
305/* Unpack a string, which is encoded as a packed integer giving the
306 * length of the string, followed by the string data.
307 */
308static int
309unpack_string(LogReaderObject *self, PyObject **pvalue)
310{
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000311 int i;
Fred Drake8c081a12001-10-12 20:57:55 +0000312 int len;
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000313 int err;
Guido van Rossum0b624f62002-07-20 00:38:01 +0000314 int ch;
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000315 char *buf;
316
317 if ((err = unpack_packed_int(self, &len, 0)))
318 return err;
Fred Drake8c081a12001-10-12 20:57:55 +0000319
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000320 buf = malloc(len);
321 for (i=0; i < len; i++) {
Guido van Rossum0b624f62002-07-20 00:38:01 +0000322 ch = fgetc(self->logfp);
323 buf[i] = ch;
324 if (ch == EOF) {
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000325 free(buf);
326 return ERR_EOF;
Fred Drake8c081a12001-10-12 20:57:55 +0000327 }
328 }
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000329 *pvalue = PyString_FromStringAndSize(buf, len);
330 free(buf);
331 if (*pvalue == NULL) {
332 return ERR_EXCEPTION;
333 }
334 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000335}
336
337
Fred Drake4c2e1af2001-10-29 20:45:57 +0000338static int
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000339unpack_add_info(LogReaderObject *self)
Fred Drake4c2e1af2001-10-29 20:45:57 +0000340{
341 PyObject *key;
342 PyObject *value = NULL;
343 int err;
344
Fred Drake4c2e1af2001-10-29 20:45:57 +0000345 err = unpack_string(self, &key);
346 if (!err) {
347 err = unpack_string(self, &value);
348 if (err)
349 Py_DECREF(key);
350 else {
351 PyObject *list = PyDict_GetItem(self->info, key);
352 if (list == NULL) {
353 list = PyList_New(0);
354 if (list == NULL) {
355 err = ERR_EXCEPTION;
356 goto finally;
357 }
358 if (PyDict_SetItem(self->info, key, list)) {
359 err = ERR_EXCEPTION;
360 goto finally;
361 }
362 }
363 if (PyList_Append(list, value))
364 err = ERR_EXCEPTION;
365 }
366 }
367 finally:
368 Py_XDECREF(key);
369 Py_XDECREF(value);
370 return err;
371}
372
373
374static void
Fred Drake666bf522002-07-18 19:11:44 +0000375eof_error(LogReaderObject *self)
Fred Drake4c2e1af2001-10-29 20:45:57 +0000376{
Fred Drake666bf522002-07-18 19:11:44 +0000377 fclose(self->logfp);
378 self->logfp = NULL;
Fred Drake4c2e1af2001-10-29 20:45:57 +0000379 PyErr_SetString(PyExc_EOFError,
380 "end of file with incomplete profile record");
381}
382
Fred Drake8c081a12001-10-12 20:57:55 +0000383static PyObject *
384logreader_tp_iternext(LogReaderObject *self)
385{
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000386 int c;
387 int what;
Fred Drake8c081a12001-10-12 20:57:55 +0000388 int err = ERR_NONE;
389 int lineno = -1;
390 int fileno = -1;
391 int tdelta = -1;
392 PyObject *s1 = NULL, *s2 = NULL;
393 PyObject *result = NULL;
394#if 0
395 unsigned char b0, b1;
396#endif
397
398 if (self->logfp == NULL) {
399 PyErr_SetString(ProfilerError,
400 "cannot iterate over closed LogReader object");
401 return NULL;
402 }
Fred Drake4c2e1af2001-10-29 20:45:57 +0000403
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000404restart:
405 /* decode the record type */
Fred Drake666bf522002-07-18 19:11:44 +0000406 if ((c = fgetc(self->logfp)) == EOF) {
407 fclose(self->logfp);
408 self->logfp = NULL;
Fred Drake8c081a12001-10-12 20:57:55 +0000409 return NULL;
Fred Drake666bf522002-07-18 19:11:44 +0000410 }
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000411 what = c & WHAT_OTHER;
412 if (what == WHAT_OTHER)
413 what = c; /* need all the bits for type */
414 else
415 ungetc(c, self->logfp); /* type byte includes packed int */
Fred Drake8c081a12001-10-12 20:57:55 +0000416
Fred Drake8c081a12001-10-12 20:57:55 +0000417 switch (what) {
418 case WHAT_ENTER:
419 err = unpack_packed_int(self, &fileno, 2);
420 if (!err) {
Fred Drake30d1c752001-10-15 22:11:02 +0000421 err = unpack_packed_int(self, &lineno, 0);
422 if (self->frametimings && !err)
423 err = unpack_packed_int(self, &tdelta, 0);
Fred Drake8c081a12001-10-12 20:57:55 +0000424 }
425 break;
426 case WHAT_EXIT:
427 err = unpack_packed_int(self, &tdelta, 2);
428 break;
429 case WHAT_LINENO:
430 err = unpack_packed_int(self, &lineno, 2);
431 if (self->linetimings && !err)
432 err = unpack_packed_int(self, &tdelta, 0);
433 break;
434 case WHAT_ADD_INFO:
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000435 err = unpack_add_info(self);
Fred Drake8c081a12001-10-12 20:57:55 +0000436 break;
437 case WHAT_DEFINE_FILE:
438 err = unpack_packed_int(self, &fileno, 0);
439 if (!err) {
440 err = unpack_string(self, &s1);
441 if (!err) {
442 Py_INCREF(Py_None);
443 s2 = Py_None;
444 }
445 }
446 break;
Fred Drake30d1c752001-10-15 22:11:02 +0000447 case WHAT_DEFINE_FUNC:
448 err = unpack_packed_int(self, &fileno, 0);
449 if (!err) {
450 err = unpack_packed_int(self, &lineno, 0);
451 if (!err)
452 err = unpack_string(self, &s1);
453 }
454 break;
Fred Drake8c081a12001-10-12 20:57:55 +0000455 case WHAT_LINE_TIMES:
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000456 if ((c = fgetc(self->logfp)) == EOF)
Fred Drake8c081a12001-10-12 20:57:55 +0000457 err = ERR_EOF;
458 else {
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000459 self->linetimings = c ? 1 : 0;
460 goto restart;
461 }
Fred Drake4c2e1af2001-10-29 20:45:57 +0000462 break;
Fred Drake30d1c752001-10-15 22:11:02 +0000463 case WHAT_FRAME_TIMES:
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000464 if ((c = fgetc(self->logfp)) == EOF)
Fred Drake30d1c752001-10-15 22:11:02 +0000465 err = ERR_EOF;
466 else {
Neil Schemenauer8b6b4912002-05-29 18:19:14 +0000467 self->frametimings = c ? 1 : 0;
468 goto restart;
469 }
Fred Drake4c2e1af2001-10-29 20:45:57 +0000470 break;
Fred Drake8c081a12001-10-12 20:57:55 +0000471 default:
Fred Drake4c2e1af2001-10-29 20:45:57 +0000472 err = ERR_BAD_RECTYPE;
Fred Drake8c081a12001-10-12 20:57:55 +0000473 }
Fred Drake4c2e1af2001-10-29 20:45:57 +0000474 if (err == ERR_BAD_RECTYPE) {
475 PyErr_SetString(PyExc_ValueError,
476 "unknown record type in log file");
477 }
478 else if (err == ERR_EOF) {
Fred Drake666bf522002-07-18 19:11:44 +0000479 eof_error(self);
Fred Drake8c081a12001-10-12 20:57:55 +0000480 }
481 else if (!err) {
482 result = PyTuple_New(4);
483 PyTuple_SET_ITEM(result, 0, PyInt_FromLong(what));
484 PyTuple_SET_ITEM(result, 2, PyInt_FromLong(fileno));
Fred Drake30d1c752001-10-15 22:11:02 +0000485 if (s1 == NULL)
Fred Drake8c081a12001-10-12 20:57:55 +0000486 PyTuple_SET_ITEM(result, 1, PyInt_FromLong(tdelta));
Fred Drake30d1c752001-10-15 22:11:02 +0000487 else
Fred Drake8c081a12001-10-12 20:57:55 +0000488 PyTuple_SET_ITEM(result, 1, s1);
Fred Drake30d1c752001-10-15 22:11:02 +0000489 if (s2 == NULL)
490 PyTuple_SET_ITEM(result, 3, PyInt_FromLong(lineno));
491 else
Fred Drake8c081a12001-10-12 20:57:55 +0000492 PyTuple_SET_ITEM(result, 3, s2);
Fred Drake8c081a12001-10-12 20:57:55 +0000493 }
494 /* The only other case is err == ERR_EXCEPTION, in which case the
495 * exception is already set.
496 */
497#if 0
498 b0 = self->buffer[self->index];
499 b1 = self->buffer[self->index + 1];
500 if (b0 & 1) {
501 /* This is a line-number event. */
502 what = PyTrace_LINE;
503 lineno = ((b0 & ~1) << 7) + b1;
504 self->index += 2;
505 }
506 else {
507 what = (b0 & 0x0E) >> 1;
508 tdelta = ((b0 & 0xF0) << 4) + b1;
509 if (what == PyTrace_CALL) {
510 /* we know there's a 2-byte file ID & 2-byte line number */
511 fileno = ((self->buffer[self->index + 2] << 8)
512 + self->buffer[self->index + 3]);
513 lineno = ((self->buffer[self->index + 4] << 8)
514 + self->buffer[self->index + 5]);
515 self->index += 6;
516 }
517 else
518 self->index += 2;
519 }
520#endif
521 return result;
522}
523
524static void
525logreader_dealloc(LogReaderObject *self)
526{
527 if (self->logfp != NULL) {
528 fclose(self->logfp);
529 self->logfp = NULL;
530 }
531 PyObject_Del(self);
532}
533
534static PyObject *
535logreader_sq_item(LogReaderObject *self, int index)
536{
537 PyObject *result = logreader_tp_iternext(self);
538 if (result == NULL && !PyErr_Occurred()) {
539 PyErr_SetString(PyExc_IndexError, "no more events in log");
540 return NULL;
541 }
542 return result;
543}
544
Fred Drake62c1e3c2001-12-04 21:40:53 +0000545static void
546do_stop(ProfilerObject *self);
Fred Drake8c081a12001-10-12 20:57:55 +0000547
548static int
549flush_data(ProfilerObject *self)
550{
551 /* Need to dump data to the log file... */
552 size_t written = fwrite(self->buffer, 1, self->index, self->logfp);
Tim Peters1566a172001-10-12 22:08:39 +0000553 if (written == (size_t)self->index)
Fred Drake8c081a12001-10-12 20:57:55 +0000554 self->index = 0;
555 else {
556 memmove(self->buffer, &self->buffer[written],
557 self->index - written);
558 self->index -= written;
559 if (written == 0) {
560 char *s = PyString_AsString(self->logfilename);
561 PyErr_SetFromErrnoWithFilename(PyExc_IOError, s);
Fred Drake62c1e3c2001-12-04 21:40:53 +0000562 do_stop(self);
Fred Drake8c081a12001-10-12 20:57:55 +0000563 return -1;
564 }
565 }
566 if (written > 0) {
567 if (fflush(self->logfp)) {
568 char *s = PyString_AsString(self->logfilename);
569 PyErr_SetFromErrnoWithFilename(PyExc_IOError, s);
Fred Drake62c1e3c2001-12-04 21:40:53 +0000570 do_stop(self);
Fred Drake8c081a12001-10-12 20:57:55 +0000571 return -1;
572 }
573 }
574 return 0;
575}
576
Fred Drake62c1e3c2001-12-04 21:40:53 +0000577static inline int
Fred Drake8c081a12001-10-12 20:57:55 +0000578pack_packed_int(ProfilerObject *self, int value)
579{
580 unsigned char partial;
581
582 do {
583 partial = value & 0x7F;
584 value >>= 7;
585 if (value)
586 partial |= 0x80;
587 self->buffer[self->index] = partial;
588 self->index++;
589 } while (value);
Fred Drake62c1e3c2001-12-04 21:40:53 +0000590 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000591}
592
593/* Encode a modified packed integer, with a subfield of modsize bits
594 * containing the value "subfield". The value of subfield is not
595 * checked to ensure it actually fits in modsize bits.
596 */
Fred Drake62c1e3c2001-12-04 21:40:53 +0000597static inline int
Fred Drake8c081a12001-10-12 20:57:55 +0000598pack_modified_packed_int(ProfilerObject *self, int value,
599 int modsize, int subfield)
600{
601 const int maxvalues[] = {-1, 1, 3, 7, 15, 31, 63, 127};
602
603 int bits = 7 - modsize;
604 int partial = value & maxvalues[bits];
605 unsigned char b = subfield | (partial << modsize);
606
607 if (partial != value) {
608 b |= 0x80;
609 self->buffer[self->index] = b;
610 self->index++;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000611 return pack_packed_int(self, value >> bits);
Fred Drake8c081a12001-10-12 20:57:55 +0000612 }
Fred Drake62c1e3c2001-12-04 21:40:53 +0000613 self->buffer[self->index] = b;
614 self->index++;
615 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000616}
617
Fred Drake62c1e3c2001-12-04 21:40:53 +0000618static int
Fred Drake30d1c752001-10-15 22:11:02 +0000619pack_string(ProfilerObject *self, const char *s, int len)
Fred Drake8c081a12001-10-12 20:57:55 +0000620{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000621 if (len + PISIZE + self->index >= BUFFERSIZE) {
622 if (flush_data(self) < 0)
623 return -1;
624 }
625 if (pack_packed_int(self, len) < 0)
626 return -1;
Fred Drake8c081a12001-10-12 20:57:55 +0000627 memcpy(self->buffer + self->index, s, len);
628 self->index += len;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000629 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000630}
631
Fred Drake62c1e3c2001-12-04 21:40:53 +0000632static int
Fred Drake8c081a12001-10-12 20:57:55 +0000633pack_add_info(ProfilerObject *self, const char *s1, const char *s2)
634{
635 int len1 = strlen(s1);
636 int len2 = strlen(s2);
637
Fred Drake62c1e3c2001-12-04 21:40:53 +0000638 if (len1 + len2 + PISIZE*2 + 1 + self->index >= BUFFERSIZE) {
639 if (flush_data(self) < 0)
640 return -1;
641 }
Fred Drake8c081a12001-10-12 20:57:55 +0000642 self->buffer[self->index] = WHAT_ADD_INFO;
643 self->index++;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000644 if (pack_string(self, s1, len1) < 0)
645 return -1;
646 return pack_string(self, s2, len2);
Fred Drake8c081a12001-10-12 20:57:55 +0000647}
648
Fred Drake62c1e3c2001-12-04 21:40:53 +0000649static int
Fred Drake8c081a12001-10-12 20:57:55 +0000650pack_define_file(ProfilerObject *self, int fileno, const char *filename)
651{
652 int len = strlen(filename);
653
Fred Drake62c1e3c2001-12-04 21:40:53 +0000654 if (len + PISIZE*2 + 1 + self->index >= BUFFERSIZE) {
655 if (flush_data(self) < 0)
656 return -1;
657 }
Fred Drake8c081a12001-10-12 20:57:55 +0000658 self->buffer[self->index] = WHAT_DEFINE_FILE;
659 self->index++;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000660 if (pack_packed_int(self, fileno) < 0)
661 return -1;
662 return pack_string(self, filename, len);
Fred Drake30d1c752001-10-15 22:11:02 +0000663}
664
Fred Drake62c1e3c2001-12-04 21:40:53 +0000665static int
Fred Drake30d1c752001-10-15 22:11:02 +0000666pack_define_func(ProfilerObject *self, int fileno, int lineno,
667 const char *funcname)
668{
669 int len = strlen(funcname);
670
Fred Drake62c1e3c2001-12-04 21:40:53 +0000671 if (len + PISIZE*3 + 1 + self->index >= BUFFERSIZE) {
672 if (flush_data(self) < 0)
673 return -1;
674 }
Fred Drake30d1c752001-10-15 22:11:02 +0000675 self->buffer[self->index] = WHAT_DEFINE_FUNC;
676 self->index++;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000677 if (pack_packed_int(self, fileno) < 0)
678 return -1;
679 if (pack_packed_int(self, lineno) < 0)
680 return -1;
681 return pack_string(self, funcname, len);
Fred Drake8c081a12001-10-12 20:57:55 +0000682}
683
Fred Drake62c1e3c2001-12-04 21:40:53 +0000684static int
Fred Drake8c081a12001-10-12 20:57:55 +0000685pack_line_times(ProfilerObject *self)
686{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000687 if (2 + self->index >= BUFFERSIZE) {
688 if (flush_data(self) < 0)
689 return -1;
690 }
Fred Drake8c081a12001-10-12 20:57:55 +0000691 self->buffer[self->index] = WHAT_LINE_TIMES;
692 self->buffer[self->index + 1] = self->linetimings ? 1 : 0;
693 self->index += 2;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000694 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000695}
696
Fred Drake62c1e3c2001-12-04 21:40:53 +0000697static int
Fred Drake30d1c752001-10-15 22:11:02 +0000698pack_frame_times(ProfilerObject *self)
699{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000700 if (2 + self->index >= BUFFERSIZE) {
701 if (flush_data(self) < 0)
702 return -1;
703 }
Fred Drake30d1c752001-10-15 22:11:02 +0000704 self->buffer[self->index] = WHAT_FRAME_TIMES;
705 self->buffer[self->index + 1] = self->frametimings ? 1 : 0;
706 self->index += 2;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000707 return 0;
Fred Drake30d1c752001-10-15 22:11:02 +0000708}
709
Fred Drake62c1e3c2001-12-04 21:40:53 +0000710static inline int
Fred Drake8c081a12001-10-12 20:57:55 +0000711pack_enter(ProfilerObject *self, int fileno, int tdelta, int lineno)
712{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000713 if (MPISIZE + PISIZE*2 + self->index >= BUFFERSIZE) {
714 if (flush_data(self) < 0)
715 return -1;
716 }
Fred Drake8c081a12001-10-12 20:57:55 +0000717 pack_modified_packed_int(self, fileno, 2, WHAT_ENTER);
Fred Drake8c081a12001-10-12 20:57:55 +0000718 pack_packed_int(self, lineno);
Fred Drake30d1c752001-10-15 22:11:02 +0000719 if (self->frametimings)
Fred Drake62c1e3c2001-12-04 21:40:53 +0000720 return pack_packed_int(self, tdelta);
721 else
722 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000723}
724
Fred Drake62c1e3c2001-12-04 21:40:53 +0000725static inline int
Fred Drake8c081a12001-10-12 20:57:55 +0000726pack_exit(ProfilerObject *self, int tdelta)
727{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000728 if (MPISIZE + self->index >= BUFFERSIZE) {
729 if (flush_data(self) < 0)
730 return -1;
Fred Drake30d1c752001-10-15 22:11:02 +0000731 }
Fred Drake62c1e3c2001-12-04 21:40:53 +0000732 if (self->frametimings)
733 return pack_modified_packed_int(self, tdelta, 2, WHAT_EXIT);
734 self->buffer[self->index] = WHAT_EXIT;
735 self->index++;
736 return 0;
Fred Drake8c081a12001-10-12 20:57:55 +0000737}
738
Fred Drake62c1e3c2001-12-04 21:40:53 +0000739static inline int
Fred Drake8c081a12001-10-12 20:57:55 +0000740pack_lineno(ProfilerObject *self, int lineno)
741{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000742 if (MPISIZE + self->index >= BUFFERSIZE) {
743 if (flush_data(self) < 0)
744 return -1;
745 }
746 return pack_modified_packed_int(self, lineno, 2, WHAT_LINENO);
Fred Drake8c081a12001-10-12 20:57:55 +0000747}
748
Fred Drake62c1e3c2001-12-04 21:40:53 +0000749static inline int
Fred Drake8c081a12001-10-12 20:57:55 +0000750pack_lineno_tdelta(ProfilerObject *self, int lineno, int tdelta)
751{
Fred Drake62c1e3c2001-12-04 21:40:53 +0000752 if (MPISIZE + PISIZE + self->index >= BUFFERSIZE) {
753 if (flush_data(self) < 0)
754 return 0;
755 }
756 if (pack_modified_packed_int(self, lineno, 2, WHAT_LINENO) < 0)
757 return -1;
758 return pack_packed_int(self, tdelta);
Fred Drake8c081a12001-10-12 20:57:55 +0000759}
760
761static inline int
762get_fileno(ProfilerObject *self, PyCodeObject *fcode)
763{
Fred Drake30d1c752001-10-15 22:11:02 +0000764 /* This is only used for ENTER events. */
765
766 PyObject *obj;
767 PyObject *dict;
Fred Drake8c081a12001-10-12 20:57:55 +0000768 int fileno;
769
Fred Drake30d1c752001-10-15 22:11:02 +0000770 obj = PyDict_GetItem(self->filemap, fcode->co_filename);
771 if (obj == NULL) {
Fred Drake8c081a12001-10-12 20:57:55 +0000772 /* first sighting of this file */
Fred Drake30d1c752001-10-15 22:11:02 +0000773 dict = PyDict_New();
774 if (dict == NULL) {
Fred Drake8c081a12001-10-12 20:57:55 +0000775 return -1;
776 }
Fred Drake30d1c752001-10-15 22:11:02 +0000777 fileno = self->next_fileno;
778 obj = Py_BuildValue("iN", fileno, dict);
779 if (obj == NULL) {
780 return -1;
781 }
782 if (PyDict_SetItem(self->filemap, fcode->co_filename, obj)) {
783 Py_DECREF(obj);
Fred Drake8c081a12001-10-12 20:57:55 +0000784 return -1;
785 }
786 self->next_fileno++;
Fred Drake30d1c752001-10-15 22:11:02 +0000787 Py_DECREF(obj);
Fred Drake62c1e3c2001-12-04 21:40:53 +0000788 if (pack_define_file(self, fileno,
789 PyString_AS_STRING(fcode->co_filename)) < 0)
790 return -1;
Fred Drake8c081a12001-10-12 20:57:55 +0000791 }
792 else {
793 /* already know this ID */
Fred Drake30d1c752001-10-15 22:11:02 +0000794 fileno = PyInt_AS_LONG(PyTuple_GET_ITEM(obj, 0));
795 dict = PyTuple_GET_ITEM(obj, 1);
796 }
797 /* make sure we save a function name for this (fileno, lineno) */
798 obj = PyInt_FromLong(fcode->co_firstlineno);
799 if (obj == NULL) {
800 /* We just won't have it saved; too bad. */
801 PyErr_Clear();
802 }
803 else {
804 PyObject *name = PyDict_GetItem(dict, obj);
805 if (name == NULL) {
Fred Drake62c1e3c2001-12-04 21:40:53 +0000806 if (pack_define_func(self, fileno, fcode->co_firstlineno,
807 PyString_AS_STRING(fcode->co_name)) < 0)
808 return -1;
Fred Drake30d1c752001-10-15 22:11:02 +0000809 if (PyDict_SetItem(dict, obj, fcode->co_name))
810 return -1;
811 }
Fred Drake8c081a12001-10-12 20:57:55 +0000812 }
813 return fileno;
814}
815
816static inline int
817get_tdelta(ProfilerObject *self)
818{
819 int tdelta;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000820#ifdef MS_WINDOWS
Fred Drake8c081a12001-10-12 20:57:55 +0000821 hs_time tv;
Tim Peters7d99ff22001-10-13 07:37:52 +0000822 hs_time diff;
Fred Drake8c081a12001-10-12 20:57:55 +0000823
Tim Peters7d99ff22001-10-13 07:37:52 +0000824 GETTIMEOFDAY(&tv);
825 diff = tv - self->prev_timeofday;
826 tdelta = (int)diff;
Fred Drake8c081a12001-10-12 20:57:55 +0000827#else
828 struct timeval tv;
829
830 GETTIMEOFDAY(&tv);
831
832 if (tv.tv_sec == self->prev_timeofday.tv_sec)
833 tdelta = tv.tv_usec - self->prev_timeofday.tv_usec;
834 else
835 tdelta = ((tv.tv_sec - self->prev_timeofday.tv_sec) * 1000000
836 + tv.tv_usec);
837#endif
838 self->prev_timeofday = tv;
839 return tdelta;
840}
841
842
843/* The workhorse: the profiler callback function. */
844
845static int
846profiler_callback(ProfilerObject *self, PyFrameObject *frame, int what,
847 PyObject *arg)
848{
Fred Drake30d1c752001-10-15 22:11:02 +0000849 int tdelta = -1;
Fred Drake8c081a12001-10-12 20:57:55 +0000850 int fileno;
851
Fred Drake30d1c752001-10-15 22:11:02 +0000852 if (self->frametimings)
853 tdelta = get_tdelta(self);
Fred Drake8c081a12001-10-12 20:57:55 +0000854 switch (what) {
855 case PyTrace_CALL:
856 fileno = get_fileno(self, frame->f_code);
857 if (fileno < 0)
858 return -1;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000859 if (pack_enter(self, fileno, tdelta,
860 frame->f_code->co_firstlineno) < 0)
861 return -1;
Fred Drake8c081a12001-10-12 20:57:55 +0000862 break;
863 case PyTrace_RETURN:
Fred Drake62c1e3c2001-12-04 21:40:53 +0000864 if (pack_exit(self, tdelta) < 0)
865 return -1;
Fred Drake8c081a12001-10-12 20:57:55 +0000866 break;
867 default:
868 /* should never get here */
869 break;
870 }
871 return 0;
872}
873
874
875/* Alternate callback when we want PyTrace_LINE events */
876
877static int
878tracer_callback(ProfilerObject *self, PyFrameObject *frame, int what,
879 PyObject *arg)
880{
881 int fileno;
882
Fred Drake8c081a12001-10-12 20:57:55 +0000883 switch (what) {
884 case PyTrace_CALL:
885 fileno = get_fileno(self, frame->f_code);
886 if (fileno < 0)
887 return -1;
Fred Drake62c1e3c2001-12-04 21:40:53 +0000888 return pack_enter(self, fileno,
889 self->frametimings ? get_tdelta(self) : -1,
890 frame->f_code->co_firstlineno);
891
Fred Drake8c081a12001-10-12 20:57:55 +0000892 case PyTrace_RETURN:
Fred Drake62c1e3c2001-12-04 21:40:53 +0000893 return pack_exit(self, get_tdelta(self));
894
Tim Peters1566a172001-10-12 22:08:39 +0000895 case PyTrace_LINE:
Fred Drake8c081a12001-10-12 20:57:55 +0000896 if (self->linetimings)
Michael W. Hudson806d1c82002-09-11 17:09:45 +0000897 return pack_lineno_tdelta(self, frame->f_lineno,
Michael W. Hudsondd32a912002-08-15 14:59:02 +0000898 get_tdelta(self));
Fred Drake8c081a12001-10-12 20:57:55 +0000899 else
Michael W. Hudson02ff6a92002-09-11 15:36:32 +0000900 return pack_lineno(self, frame->f_lineno);
Fred Drake62c1e3c2001-12-04 21:40:53 +0000901
Fred Drake8c081a12001-10-12 20:57:55 +0000902 default:
903 /* ignore PyTrace_EXCEPTION */
904 break;
905 }
906 return 0;
907}
908
909
910/* A couple of useful helper functions. */
911
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000912#ifdef MS_WINDOWS
Tim Petersfeab23f2001-10-13 00:11:10 +0000913static LARGE_INTEGER frequency = {0, 0};
Fred Drake8c081a12001-10-12 20:57:55 +0000914#endif
915
916static unsigned long timeofday_diff = 0;
917static unsigned long rusage_diff = 0;
918
919static void
920calibrate(void)
921{
922 hs_time tv1, tv2;
923
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000924#ifdef MS_WINDOWS
Tim Peters7d99ff22001-10-13 07:37:52 +0000925 hs_time diff;
Fred Drake8c081a12001-10-12 20:57:55 +0000926 QueryPerformanceFrequency(&frequency);
927#endif
928
929 GETTIMEOFDAY(&tv1);
930 while (1) {
931 GETTIMEOFDAY(&tv2);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000932#ifdef MS_WINDOWS
Tim Peters7d99ff22001-10-13 07:37:52 +0000933 diff = tv2 - tv1;
934 if (diff != 0) {
935 timeofday_diff = (unsigned long)diff;
Fred Drake8c081a12001-10-12 20:57:55 +0000936 break;
937 }
938#else
939 if (tv1.tv_sec != tv2.tv_sec || tv1.tv_usec != tv2.tv_usec) {
940 if (tv1.tv_sec == tv2.tv_sec)
941 timeofday_diff = tv2.tv_usec - tv1.tv_usec;
942 else
943 timeofday_diff = (1000000 - tv1.tv_usec) + tv2.tv_usec;
944 break;
945 }
946#endif
947 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000948#if defined(MS_WINDOWS) || defined(macintosh) || defined(PYOS_OS2)
Fred Drake8c081a12001-10-12 20:57:55 +0000949 rusage_diff = -1;
950#else
951 {
952 struct rusage ru1, ru2;
953
954 getrusage(RUSAGE_SELF, &ru1);
955 while (1) {
956 getrusage(RUSAGE_SELF, &ru2);
957 if (ru1.ru_utime.tv_sec != ru2.ru_utime.tv_sec) {
958 rusage_diff = ((1000000 - ru1.ru_utime.tv_usec)
959 + ru2.ru_utime.tv_usec);
960 break;
961 }
962 else if (ru1.ru_utime.tv_usec != ru2.ru_utime.tv_usec) {
963 rusage_diff = ru2.ru_utime.tv_usec - ru1.ru_utime.tv_usec;
964 break;
965 }
966 else if (ru1.ru_stime.tv_sec != ru2.ru_stime.tv_sec) {
967 rusage_diff = ((1000000 - ru1.ru_stime.tv_usec)
968 + ru2.ru_stime.tv_usec);
969 break;
970 }
971 else if (ru1.ru_stime.tv_usec != ru2.ru_stime.tv_usec) {
972 rusage_diff = ru2.ru_stime.tv_usec - ru1.ru_stime.tv_usec;
973 break;
974 }
975 }
976 }
977#endif
978}
979
980static void
981do_start(ProfilerObject *self)
982{
983 self->active = 1;
984 GETTIMEOFDAY(&self->prev_timeofday);
985 if (self->lineevents)
986 PyEval_SetTrace((Py_tracefunc) tracer_callback, (PyObject *)self);
987 else
988 PyEval_SetProfile((Py_tracefunc) profiler_callback, (PyObject *)self);
989}
990
991static void
992do_stop(ProfilerObject *self)
993{
994 if (self->active) {
995 self->active = 0;
996 if (self->lineevents)
997 PyEval_SetTrace(NULL, NULL);
998 else
999 PyEval_SetProfile(NULL, NULL);
1000 }
1001 if (self->index > 0) {
1002 /* Best effort to dump out any remaining data. */
1003 flush_data(self);
1004 }
1005}
1006
1007static int
1008is_available(ProfilerObject *self)
1009{
1010 if (self->active) {
1011 PyErr_SetString(ProfilerError, "profiler already active");
1012 return 0;
1013 }
1014 if (self->logfp == NULL) {
1015 PyErr_SetString(ProfilerError, "profiler already closed");
1016 return 0;
1017 }
1018 return 1;
1019}
1020
1021
1022/* Profiler object interface methods. */
1023
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001024PyDoc_STRVAR(addinfo__doc__,
Fred Drake4c2e1af2001-10-29 20:45:57 +00001025"addinfo(key, value)\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001026"Insert an ADD_INFO record into the log.");
Fred Drake4c2e1af2001-10-29 20:45:57 +00001027
1028static PyObject *
1029profiler_addinfo(ProfilerObject *self, PyObject *args)
1030{
1031 PyObject *result = NULL;
1032 char *key, *value;
1033
1034 if (PyArg_ParseTuple(args, "ss:addinfo", &key, &value)) {
1035 if (self->logfp == NULL)
1036 PyErr_SetString(ProfilerError, "profiler already closed");
1037 else {
Fred Drake62c1e3c2001-12-04 21:40:53 +00001038 if (pack_add_info(self, key, value) == 0) {
1039 result = Py_None;
1040 Py_INCREF(result);
1041 }
Fred Drake4c2e1af2001-10-29 20:45:57 +00001042 }
1043 }
1044 return result;
1045}
1046
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001047PyDoc_STRVAR(close__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +00001048"close()\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001049"Shut down this profiler and close the log files, even if its active.");
Fred Drake8c081a12001-10-12 20:57:55 +00001050
1051static PyObject *
Fred Drake666bf522002-07-18 19:11:44 +00001052profiler_close(ProfilerObject *self)
Fred Drake8c081a12001-10-12 20:57:55 +00001053{
Fred Drake666bf522002-07-18 19:11:44 +00001054 do_stop(self);
1055 if (self->logfp != NULL) {
1056 fclose(self->logfp);
1057 self->logfp = NULL;
Fred Drake8c081a12001-10-12 20:57:55 +00001058 }
Fred Drake666bf522002-07-18 19:11:44 +00001059 Py_INCREF(Py_None);
1060 return Py_None;
1061}
1062
1063#define fileno__doc__ logreader_fileno__doc__
1064
1065static PyObject *
1066profiler_fileno(ProfilerObject *self)
1067{
1068 if (self->logfp == NULL) {
1069 PyErr_SetString(PyExc_ValueError,
1070 "profiler's file object already closed");
1071 return NULL;
1072 }
1073 return PyInt_FromLong(fileno(self->logfp));
Fred Drake8c081a12001-10-12 20:57:55 +00001074}
1075
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001076PyDoc_STRVAR(runcall__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +00001077"runcall(callable[, args[, kw]]) -> callable()\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001078"Profile a specific function call, returning the result of that call.");
Fred Drake8c081a12001-10-12 20:57:55 +00001079
1080static PyObject *
1081profiler_runcall(ProfilerObject *self, PyObject *args)
1082{
1083 PyObject *result = NULL;
1084 PyObject *callargs = NULL;
1085 PyObject *callkw = NULL;
1086 PyObject *callable;
1087
1088 if (PyArg_ParseTuple(args, "O|OO:runcall",
1089 &callable, &callargs, &callkw)) {
1090 if (is_available(self)) {
1091 do_start(self);
1092 result = PyEval_CallObjectWithKeywords(callable, callargs, callkw);
1093 do_stop(self);
1094 }
1095 }
1096 return result;
1097}
1098
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001099PyDoc_STRVAR(runcode__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +00001100"runcode(code, globals[, locals])\n"
1101"Execute a code object while collecting profile data. If locals is\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001102"omitted, globals is used for the locals as well.");
Fred Drake8c081a12001-10-12 20:57:55 +00001103
1104static PyObject *
1105profiler_runcode(ProfilerObject *self, PyObject *args)
1106{
1107 PyObject *result = NULL;
1108 PyCodeObject *code;
1109 PyObject *globals;
1110 PyObject *locals = NULL;
1111
1112 if (PyArg_ParseTuple(args, "O!O!|O:runcode",
1113 &PyCode_Type, &code,
1114 &PyDict_Type, &globals,
1115 &locals)) {
1116 if (is_available(self)) {
1117 if (locals == NULL || locals == Py_None)
1118 locals = globals;
1119 else if (!PyDict_Check(locals)) {
1120 PyErr_SetString(PyExc_TypeError,
1121 "locals must be a dictionary or None");
1122 return NULL;
1123 }
1124 do_start(self);
1125 result = PyEval_EvalCode(code, globals, locals);
1126 do_stop(self);
1127#if 0
1128 if (!PyErr_Occurred()) {
1129 result = Py_None;
1130 Py_INCREF(result);
1131 }
1132#endif
1133 }
1134 }
1135 return result;
1136}
1137
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001138PyDoc_STRVAR(start__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +00001139"start()\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001140"Install this profiler for the current thread.");
Fred Drake8c081a12001-10-12 20:57:55 +00001141
1142static PyObject *
1143profiler_start(ProfilerObject *self, PyObject *args)
1144{
1145 PyObject *result = NULL;
1146
Fred Drake666bf522002-07-18 19:11:44 +00001147 if (is_available(self)) {
1148 do_start(self);
1149 result = Py_None;
1150 Py_INCREF(result);
Fred Drake8c081a12001-10-12 20:57:55 +00001151 }
1152 return result;
1153}
1154
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001155PyDoc_STRVAR(stop__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +00001156"stop()\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001157"Remove this profiler from the current thread.");
Fred Drake8c081a12001-10-12 20:57:55 +00001158
1159static PyObject *
1160profiler_stop(ProfilerObject *self, PyObject *args)
1161{
1162 PyObject *result = NULL;
1163
Fred Drake666bf522002-07-18 19:11:44 +00001164 if (!self->active)
1165 PyErr_SetString(ProfilerError, "profiler not active");
1166 else {
1167 do_stop(self);
1168 result = Py_None;
1169 Py_INCREF(result);
Fred Drake8c081a12001-10-12 20:57:55 +00001170 }
1171 return result;
1172}
1173
1174
1175/* Python API support. */
1176
1177static void
1178profiler_dealloc(ProfilerObject *self)
1179{
1180 do_stop(self);
1181 if (self->logfp != NULL)
1182 fclose(self->logfp);
1183 Py_XDECREF(self->filemap);
1184 Py_XDECREF(self->logfilename);
1185 PyObject_Del((PyObject *)self);
1186}
1187
Fred Drake8c081a12001-10-12 20:57:55 +00001188static PyMethodDef profiler_methods[] = {
Fred Drake4c2e1af2001-10-29 20:45:57 +00001189 {"addinfo", (PyCFunction)profiler_addinfo, METH_VARARGS, addinfo__doc__},
Fred Drake666bf522002-07-18 19:11:44 +00001190 {"close", (PyCFunction)profiler_close, METH_NOARGS, close__doc__},
1191 {"fileno", (PyCFunction)profiler_fileno, METH_NOARGS, fileno__doc__},
Fred Drake8c081a12001-10-12 20:57:55 +00001192 {"runcall", (PyCFunction)profiler_runcall, METH_VARARGS, runcall__doc__},
1193 {"runcode", (PyCFunction)profiler_runcode, METH_VARARGS, runcode__doc__},
Fred Drake666bf522002-07-18 19:11:44 +00001194 {"start", (PyCFunction)profiler_start, METH_NOARGS, start__doc__},
1195 {"stop", (PyCFunction)profiler_stop, METH_NOARGS, stop__doc__},
Fred Drake8c081a12001-10-12 20:57:55 +00001196 {NULL, NULL}
1197};
1198
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001199static PyMemberDef profiler_members[] = {
Fred Drake30d1c752001-10-15 22:11:02 +00001200 {"frametimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
1201 {"lineevents", T_LONG, offsetof(ProfilerObject, lineevents), READONLY},
1202 {"linetimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
Fred Drake8c081a12001-10-12 20:57:55 +00001203 {NULL}
1204};
1205
1206static PyObject *
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001207profiler_get_closed(ProfilerObject *self, void *closure)
Fred Drake8c081a12001-10-12 20:57:55 +00001208{
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001209 PyObject *result = (self->logfp == NULL) ? Py_True : Py_False;
1210 Py_INCREF(result);
Fred Drake8c081a12001-10-12 20:57:55 +00001211 return result;
1212}
1213
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001214static PyGetSetDef profiler_getsets[] = {
Fred Draked1eb8b62002-07-17 18:54:20 +00001215 {"closed", (getter)profiler_get_closed, NULL,
Fred Drake5c3ed3d2002-07-17 19:38:05 +00001216 PyDoc_STR("True if the profiler's output file has already been closed.")},
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001217 {NULL}
1218};
1219
Fred Drake8c081a12001-10-12 20:57:55 +00001220
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001221PyDoc_STRVAR(profiler_object__doc__,
Tim Petersfeab23f2001-10-13 00:11:10 +00001222"High-performance profiler object.\n"
1223"\n"
1224"Methods:\n"
1225"\n"
Fred Drake30d1c752001-10-15 22:11:02 +00001226"close(): Stop the profiler and close the log files.\n"
Fred Drake666bf522002-07-18 19:11:44 +00001227"fileno(): Returns the file descriptor of the log file.\n"
Fred Drake30d1c752001-10-15 22:11:02 +00001228"runcall(): Run a single function call with profiling enabled.\n"
1229"runcode(): Execute a code object with profiling enabled.\n"
1230"start(): Install the profiler and return.\n"
1231"stop(): Remove the profiler.\n"
Tim Petersfeab23f2001-10-13 00:11:10 +00001232"\n"
1233"Attributes (read-only):\n"
1234"\n"
Fred Drake30d1c752001-10-15 22:11:02 +00001235"closed: True if the profiler has already been closed.\n"
1236"frametimings: True if ENTER/EXIT events collect timing information.\n"
Michael W. Hudsondd32a912002-08-15 14:59:02 +00001237"lineevents: True if line events are reported to the profiler.\n"
1238"linetimings: True if line events collect timing information.");
Fred Drake8c081a12001-10-12 20:57:55 +00001239
1240static PyTypeObject ProfilerType = {
1241 PyObject_HEAD_INIT(NULL)
1242 0, /* ob_size */
Fred Drake4c2e1af2001-10-29 20:45:57 +00001243 "_hotshot.ProfilerType", /* tp_name */
Fred Drake8c081a12001-10-12 20:57:55 +00001244 (int) sizeof(ProfilerObject), /* tp_basicsize */
1245 0, /* tp_itemsize */
1246 (destructor)profiler_dealloc, /* tp_dealloc */
1247 0, /* tp_print */
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001248 0, /* tp_getattr */
Fred Drake8c081a12001-10-12 20:57:55 +00001249 0, /* tp_setattr */
1250 0, /* tp_compare */
1251 0, /* tp_repr */
1252 0, /* tp_as_number */
1253 0, /* tp_as_sequence */
1254 0, /* tp_as_mapping */
1255 0, /* tp_hash */
1256 0, /* tp_call */
1257 0, /* tp_str */
Jason Tishler4df78cd2002-08-08 19:46:15 +00001258 0, /* tp_getattro */
Fred Drake8c081a12001-10-12 20:57:55 +00001259 0, /* tp_setattro */
1260 0, /* tp_as_buffer */
Fred Drake4c2e1af2001-10-29 20:45:57 +00001261 Py_TPFLAGS_DEFAULT, /* tp_flags */
Fred Drake8c081a12001-10-12 20:57:55 +00001262 profiler_object__doc__, /* tp_doc */
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001263 0, /* tp_traverse */
1264 0, /* tp_clear */
1265 0, /* tp_richcompare */
1266 0, /* tp_weaklistoffset */
1267 0, /* tp_iter */
1268 0, /* tp_iternext */
1269 profiler_methods, /* tp_methods */
1270 profiler_members, /* tp_members */
1271 profiler_getsets, /* tp_getset */
1272 0, /* tp_base */
1273 0, /* tp_dict */
1274 0, /* tp_descr_get */
1275 0, /* tp_descr_set */
Fred Drake8c081a12001-10-12 20:57:55 +00001276};
1277
1278
1279static PyMethodDef logreader_methods[] = {
Fred Drake666bf522002-07-18 19:11:44 +00001280 {"close", (PyCFunction)logreader_close, METH_NOARGS,
Fred Drake8c081a12001-10-12 20:57:55 +00001281 logreader_close__doc__},
Fred Drake666bf522002-07-18 19:11:44 +00001282 {"fileno", (PyCFunction)logreader_fileno, METH_NOARGS,
1283 logreader_fileno__doc__},
Fred Drake8c081a12001-10-12 20:57:55 +00001284 {NULL, NULL}
1285};
1286
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001287static PyMemberDef logreader_members[] = {
Fred Drake5c3ed3d2002-07-17 19:38:05 +00001288 {"info", T_OBJECT, offsetof(LogReaderObject, info), RO,
1289 PyDoc_STR("Dictionary mapping informational keys to lists of values.")},
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001290 {NULL}
1291};
Fred Drake8c081a12001-10-12 20:57:55 +00001292
1293
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001294PyDoc_STRVAR(logreader__doc__,
1295"logreader(filename) --> log-iterator\n\
1296Create a log-reader for the timing information file.");
Fred Drake8c081a12001-10-12 20:57:55 +00001297
1298static PySequenceMethods logreader_as_sequence = {
1299 0, /* sq_length */
1300 0, /* sq_concat */
1301 0, /* sq_repeat */
1302 (intargfunc)logreader_sq_item, /* sq_item */
1303 0, /* sq_slice */
1304 0, /* sq_ass_item */
1305 0, /* sq_ass_slice */
1306 0, /* sq_contains */
1307 0, /* sq_inplace_concat */
1308 0, /* sq_inplace_repeat */
1309};
1310
Fred Drake666bf522002-07-18 19:11:44 +00001311static PyObject *
1312logreader_get_closed(LogReaderObject *self, void *closure)
1313{
1314 PyObject *result = (self->logfp == NULL) ? Py_True : Py_False;
1315 Py_INCREF(result);
1316 return result;
1317}
1318
1319static PyGetSetDef logreader_getsets[] = {
1320 {"closed", (getter)logreader_get_closed, NULL,
1321 PyDoc_STR("True if the logreader's input file has already been closed.")},
1322 {NULL}
1323};
1324
Fred Drake8c081a12001-10-12 20:57:55 +00001325static PyTypeObject LogReaderType = {
1326 PyObject_HEAD_INIT(NULL)
1327 0, /* ob_size */
Fred Drake4c2e1af2001-10-29 20:45:57 +00001328 "_hotshot.LogReaderType", /* tp_name */
Fred Drake8c081a12001-10-12 20:57:55 +00001329 (int) sizeof(LogReaderObject), /* tp_basicsize */
1330 0, /* tp_itemsize */
1331 (destructor)logreader_dealloc, /* tp_dealloc */
1332 0, /* tp_print */
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001333 0, /* tp_getattr */
Fred Drake8c081a12001-10-12 20:57:55 +00001334 0, /* tp_setattr */
1335 0, /* tp_compare */
1336 0, /* tp_repr */
1337 0, /* tp_as_number */
1338 &logreader_as_sequence, /* tp_as_sequence */
1339 0, /* tp_as_mapping */
1340 0, /* tp_hash */
1341 0, /* tp_call */
1342 0, /* tp_str */
Jason Tishler4df78cd2002-08-08 19:46:15 +00001343 0, /* tp_getattro */
Fred Drake8c081a12001-10-12 20:57:55 +00001344 0, /* tp_setattro */
1345 0, /* tp_as_buffer */
Fred Drake4c2e1af2001-10-29 20:45:57 +00001346 Py_TPFLAGS_DEFAULT, /* tp_flags */
Fred Drake8c081a12001-10-12 20:57:55 +00001347 logreader__doc__, /* tp_doc */
Fred Drake8c081a12001-10-12 20:57:55 +00001348 0, /* tp_traverse */
1349 0, /* tp_clear */
1350 0, /* tp_richcompare */
1351 0, /* tp_weaklistoffset */
1352 (getiterfunc)logreader_tp_iter, /* tp_iter */
1353 (iternextfunc)logreader_tp_iternext,/* tp_iternext */
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001354 logreader_methods, /* tp_methods */
1355 logreader_members, /* tp_members */
Fred Drake666bf522002-07-18 19:11:44 +00001356 logreader_getsets, /* tp_getset */
Guido van Rossum9cb64b92002-07-17 16:15:35 +00001357 0, /* tp_base */
1358 0, /* tp_dict */
1359 0, /* tp_descr_get */
1360 0, /* tp_descr_set */
Fred Drake8c081a12001-10-12 20:57:55 +00001361};
1362
1363static PyObject *
1364hotshot_logreader(PyObject *unused, PyObject *args)
1365{
1366 LogReaderObject *self = NULL;
1367 char *filename;
Neil Schemenauer8b6b4912002-05-29 18:19:14 +00001368 int c;
1369 int err = 0;
Fred Drake8c081a12001-10-12 20:57:55 +00001370
1371 if (PyArg_ParseTuple(args, "s:logreader", &filename)) {
1372 self = PyObject_New(LogReaderObject, &LogReaderType);
1373 if (self != NULL) {
Fred Drake30d1c752001-10-15 22:11:02 +00001374 self->frametimings = 1;
Fred Drake8c081a12001-10-12 20:57:55 +00001375 self->linetimings = 0;
Fred Drake4c2e1af2001-10-29 20:45:57 +00001376 self->info = NULL;
Fred Drake8c081a12001-10-12 20:57:55 +00001377 self->logfp = fopen(filename, "rb");
1378 if (self->logfp == NULL) {
1379 PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
1380 Py_DECREF(self);
1381 self = NULL;
Fred Drake4c2e1af2001-10-29 20:45:57 +00001382 goto finally;
1383 }
1384 self->info = PyDict_New();
1385 if (self->info == NULL) {
1386 Py_DECREF(self);
1387 goto finally;
1388 }
Neil Schemenauer8b6b4912002-05-29 18:19:14 +00001389 /* read initial info */
1390 for (;;) {
1391 if ((c = fgetc(self->logfp)) == EOF) {
Fred Drake666bf522002-07-18 19:11:44 +00001392 eof_error(self);
Neil Schemenauer8b6b4912002-05-29 18:19:14 +00001393 break;
1394 }
1395 if (c != WHAT_ADD_INFO) {
1396 ungetc(c, self->logfp);
1397 break;
1398 }
1399 err = unpack_add_info(self);
Fred Drake4c2e1af2001-10-29 20:45:57 +00001400 if (err) {
1401 if (err == ERR_EOF)
Fred Drake666bf522002-07-18 19:11:44 +00001402 eof_error(self);
Fred Drake4c2e1af2001-10-29 20:45:57 +00001403 else
1404 PyErr_SetString(PyExc_RuntimeError,
1405 "unexpected error");
1406 break;
1407 }
Fred Drake8c081a12001-10-12 20:57:55 +00001408 }
1409 }
1410 }
Fred Drake4c2e1af2001-10-29 20:45:57 +00001411 finally:
Fred Drake8c081a12001-10-12 20:57:55 +00001412 return (PyObject *) self;
1413}
1414
1415
1416/* Return a Python string that represents the version number without the
1417 * extra cruft added by revision control, even if the right options were
1418 * given to the "cvs export" command to make it not include the extra
1419 * cruft.
1420 */
1421static char *
1422get_version_string(void)
1423{
1424 static char *rcsid = "$Revision$";
1425 char *rev = rcsid;
1426 char *buffer;
1427 int i = 0;
1428
Neal Norwitz3afb2d22002-03-20 21:32:07 +00001429 while (*rev && !isdigit((int)*rev))
Fred Drake8c081a12001-10-12 20:57:55 +00001430 ++rev;
1431 while (rev[i] != ' ' && rev[i] != '\0')
1432 ++i;
1433 buffer = malloc(i + 1);
1434 if (buffer != NULL) {
1435 memmove(buffer, rev, i);
1436 buffer[i] = '\0';
1437 }
1438 return buffer;
1439}
1440
1441/* Write out a RFC 822-style header with various useful bits of
1442 * information to make the output easier to manage.
1443 */
1444static int
1445write_header(ProfilerObject *self)
1446{
1447 char *buffer;
1448 char cwdbuffer[PATH_MAX];
1449 PyObject *temp;
1450 int i, len;
1451
1452 buffer = get_version_string();
1453 if (buffer == NULL) {
1454 PyErr_NoMemory();
1455 return -1;
1456 }
Fred Drake4c2e1af2001-10-29 20:45:57 +00001457 pack_add_info(self, "hotshot-version", buffer);
1458 pack_add_info(self, "requested-frame-timings",
1459 (self->frametimings ? "yes" : "no"));
1460 pack_add_info(self, "requested-line-events",
Fred Drake8c081a12001-10-12 20:57:55 +00001461 (self->lineevents ? "yes" : "no"));
Fred Drake4c2e1af2001-10-29 20:45:57 +00001462 pack_add_info(self, "requested-line-timings",
1463 (self->linetimings ? "yes" : "no"));
1464 pack_add_info(self, "platform", Py_GetPlatform());
1465 pack_add_info(self, "executable", Py_GetProgramFullPath());
Fred Drakef12a68c2001-11-09 15:59:36 +00001466 free(buffer);
Fred Drake8c081a12001-10-12 20:57:55 +00001467 buffer = (char *) Py_GetVersion();
1468 if (buffer == NULL)
1469 PyErr_Clear();
1470 else
Fred Drake4c2e1af2001-10-29 20:45:57 +00001471 pack_add_info(self, "executable-version", buffer);
Fred Drake8c081a12001-10-12 20:57:55 +00001472
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001473#ifdef MS_WINDOWS
Tim Peters885d4572001-11-28 20:27:42 +00001474 PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%I64d", frequency.QuadPart);
Fred Drake4c2e1af2001-10-29 20:45:57 +00001475 pack_add_info(self, "reported-performance-frequency", cwdbuffer);
Fred Drake8c081a12001-10-12 20:57:55 +00001476#else
Tim Peters885d4572001-11-28 20:27:42 +00001477 PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", rusage_diff);
Fred Drake4c2e1af2001-10-29 20:45:57 +00001478 pack_add_info(self, "observed-interval-getrusage", cwdbuffer);
Tim Peters885d4572001-11-28 20:27:42 +00001479 PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", timeofday_diff);
Fred Drake4c2e1af2001-10-29 20:45:57 +00001480 pack_add_info(self, "observed-interval-gettimeofday", cwdbuffer);
Fred Drake8c081a12001-10-12 20:57:55 +00001481#endif
Fred Drake8c081a12001-10-12 20:57:55 +00001482
Fred Drake4c2e1af2001-10-29 20:45:57 +00001483 pack_add_info(self, "current-directory",
Fred Drake8c081a12001-10-12 20:57:55 +00001484 getcwd(cwdbuffer, sizeof cwdbuffer));
1485
1486 temp = PySys_GetObject("path");
1487 len = PyList_GET_SIZE(temp);
1488 for (i = 0; i < len; ++i) {
1489 PyObject *item = PyList_GET_ITEM(temp, i);
1490 buffer = PyString_AsString(item);
Fred Draked1eb8b62002-07-17 18:54:20 +00001491 if (buffer == NULL) {
1492 pack_add_info(self, "sys-path-entry", "<non-string-path-entry>");
1493 PyErr_Clear();
1494 }
1495 else {
1496 pack_add_info(self, "sys-path-entry", buffer);
1497 }
Fred Drake8c081a12001-10-12 20:57:55 +00001498 }
Fred Drake4c2e1af2001-10-29 20:45:57 +00001499 pack_frame_times(self);
1500 pack_line_times(self);
1501
Fred Drake8c081a12001-10-12 20:57:55 +00001502 return 0;
1503}
1504
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001505PyDoc_STRVAR(profiler__doc__,
1506"profiler(logfilename[, lineevents[, linetimes]]) -> profiler\n\
1507Create a new profiler object.");
Fred Drake8c081a12001-10-12 20:57:55 +00001508
1509static PyObject *
1510hotshot_profiler(PyObject *unused, PyObject *args)
1511{
1512 char *logfilename;
1513 ProfilerObject *self = NULL;
1514 int lineevents = 0;
1515 int linetimings = 1;
1516
1517 if (PyArg_ParseTuple(args, "s|ii:profiler", &logfilename,
1518 &lineevents, &linetimings)) {
1519 self = PyObject_New(ProfilerObject, &ProfilerType);
1520 if (self == NULL)
1521 return NULL;
Fred Drake30d1c752001-10-15 22:11:02 +00001522 self->frametimings = 1;
Fred Drake8c081a12001-10-12 20:57:55 +00001523 self->lineevents = lineevents ? 1 : 0;
1524 self->linetimings = (lineevents && linetimings) ? 1 : 0;
1525 self->index = 0;
1526 self->active = 0;
1527 self->next_fileno = 0;
Tim Peters1566a172001-10-12 22:08:39 +00001528 self->logfp = NULL;
Fred Drake8c081a12001-10-12 20:57:55 +00001529 self->logfilename = PyTuple_GET_ITEM(args, 0);
1530 Py_INCREF(self->logfilename);
1531 self->filemap = PyDict_New();
1532 if (self->filemap == NULL) {
1533 Py_DECREF(self);
1534 return NULL;
1535 }
1536 self->logfp = fopen(logfilename, "wb");
1537 if (self->logfp == NULL) {
1538 Py_DECREF(self);
1539 PyErr_SetFromErrnoWithFilename(PyExc_IOError, logfilename);
1540 return NULL;
1541 }
1542 if (timeofday_diff == 0) {
1543 /* Run this several times since sometimes the first
1544 * doesn't give the lowest values, and we're really trying
1545 * to determine the lowest.
1546 */
1547 calibrate();
1548 calibrate();
1549 calibrate();
1550 }
1551 if (write_header(self))
1552 /* some error occurred, exception has been set */
1553 self = NULL;
1554 }
1555 return (PyObject *) self;
1556}
1557
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001558PyDoc_STRVAR(coverage__doc__,
1559"coverage(logfilename) -> profiler\n\
Fred Drake30d1c752001-10-15 22:11:02 +00001560Returns a profiler that doesn't collect any timing information, which is\n\
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001561useful in building a coverage analysis tool.");
Fred Drake30d1c752001-10-15 22:11:02 +00001562
1563static PyObject *
1564hotshot_coverage(PyObject *unused, PyObject *args)
1565{
1566 char *logfilename;
1567 PyObject *result = NULL;
1568
1569 if (PyArg_ParseTuple(args, "s:coverage", &logfilename)) {
1570 result = hotshot_profiler(unused, args);
1571 if (result != NULL) {
1572 ProfilerObject *self = (ProfilerObject *) result;
1573 self->frametimings = 0;
1574 self->linetimings = 0;
1575 self->lineevents = 1;
1576 }
1577 }
1578 return result;
1579}
1580
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001581PyDoc_VAR(resolution__doc__) =
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001582#ifdef MS_WINDOWS
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001583PyDoc_STR(
Tim Petersfeab23f2001-10-13 00:11:10 +00001584"resolution() -> (performance-counter-ticks, update-frequency)\n"
1585"Return the resolution of the timer provided by the QueryPerformanceCounter()\n"
1586"function. The first value is the smallest observed change, and the second\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001587"is the result of QueryPerformanceFrequency()."
1588)
Fred Drake8c081a12001-10-12 20:57:55 +00001589#else
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001590PyDoc_STR(
Tim Petersfeab23f2001-10-13 00:11:10 +00001591"resolution() -> (gettimeofday-usecs, getrusage-usecs)\n"
1592"Return the resolution of the timers provided by the gettimeofday() and\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001593"getrusage() system calls, or -1 if the call is not supported."
1594)
Fred Drake8c081a12001-10-12 20:57:55 +00001595#endif
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001596;
Fred Drake8c081a12001-10-12 20:57:55 +00001597
1598static PyObject *
1599hotshot_resolution(PyObject *unused, PyObject *args)
1600{
1601 PyObject *result = NULL;
1602
1603 if (PyArg_ParseTuple(args, ":resolution")) {
1604 if (timeofday_diff == 0) {
1605 calibrate();
1606 calibrate();
1607 calibrate();
1608 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001609#ifdef MS_WINDOWS
Fred Drake8c081a12001-10-12 20:57:55 +00001610 result = Py_BuildValue("ii", timeofday_diff, frequency.LowPart);
1611#else
1612 result = Py_BuildValue("ii", timeofday_diff, rusage_diff);
1613#endif
1614 }
1615 return result;
1616}
1617
1618
1619static PyMethodDef functions[] = {
Fred Drake30d1c752001-10-15 22:11:02 +00001620 {"coverage", hotshot_coverage, METH_VARARGS, coverage__doc__},
Fred Drake8c081a12001-10-12 20:57:55 +00001621 {"profiler", hotshot_profiler, METH_VARARGS, profiler__doc__},
1622 {"logreader", hotshot_logreader, METH_VARARGS, logreader__doc__},
1623 {"resolution", hotshot_resolution, METH_VARARGS, resolution__doc__},
1624 {NULL, NULL}
1625};
1626
1627
1628void
1629init_hotshot(void)
1630{
1631 PyObject *module;
1632
1633 LogReaderType.ob_type = &PyType_Type;
Jason Tishler4df78cd2002-08-08 19:46:15 +00001634 LogReaderType.tp_getattro = PyObject_GenericGetAttr;
Fred Drake8c081a12001-10-12 20:57:55 +00001635 ProfilerType.ob_type = &PyType_Type;
Jason Tishler4df78cd2002-08-08 19:46:15 +00001636 ProfilerType.tp_getattro = PyObject_GenericGetAttr;
Fred Drake8c081a12001-10-12 20:57:55 +00001637 module = Py_InitModule("_hotshot", functions);
1638 if (module != NULL) {
1639 char *s = get_version_string();
1640
1641 PyModule_AddStringConstant(module, "__version__", s);
1642 free(s);
1643 Py_INCREF(&LogReaderType);
1644 PyModule_AddObject(module, "LogReaderType",
1645 (PyObject *)&LogReaderType);
1646 Py_INCREF(&ProfilerType);
1647 PyModule_AddObject(module, "ProfilerType",
1648 (PyObject *)&ProfilerType);
1649
1650 if (ProfilerError == NULL)
1651 ProfilerError = PyErr_NewException("hotshot.ProfilerError",
1652 NULL, NULL);
1653 if (ProfilerError != NULL) {
1654 Py_INCREF(ProfilerError);
1655 PyModule_AddObject(module, "ProfilerError", ProfilerError);
1656 }
1657 PyModule_AddIntConstant(module, "WHAT_ENTER", WHAT_ENTER);
1658 PyModule_AddIntConstant(module, "WHAT_EXIT", WHAT_EXIT);
1659 PyModule_AddIntConstant(module, "WHAT_LINENO", WHAT_LINENO);
1660 PyModule_AddIntConstant(module, "WHAT_OTHER", WHAT_OTHER);
1661 PyModule_AddIntConstant(module, "WHAT_ADD_INFO", WHAT_ADD_INFO);
1662 PyModule_AddIntConstant(module, "WHAT_DEFINE_FILE", WHAT_DEFINE_FILE);
Fred Drake30d1c752001-10-15 22:11:02 +00001663 PyModule_AddIntConstant(module, "WHAT_DEFINE_FUNC", WHAT_DEFINE_FUNC);
Fred Drake8c081a12001-10-12 20:57:55 +00001664 PyModule_AddIntConstant(module, "WHAT_LINE_TIMES", WHAT_LINE_TIMES);
1665 }
1666}