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