Issue #1515: Enable use of deepcopy() with instance methods. Patch by Robert Collins.
[python.git] / Modules / _hotshot.c
bloba36cd50f0f65aa53d80a47c3cf1740b30fa4d186
1 /*
2 * This is the High Performance Python Profiler portion of HotShot.
3 */
5 #include "Python.h"
6 #include "code.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>
18 #ifdef HAVE_DIRECT_H
19 #include <direct.h> /* for getcwd() */
20 #endif
22 typedef __int64 hs_time;
23 #define GETTIMEOFDAY(P_HS_TIME) \
24 { LARGE_INTEGER _temp; \
25 QueryPerformanceCounter(&_temp); \
26 *(P_HS_TIME) = _temp.QuadPart; }
29 #else
30 #ifndef HAVE_GETTIMEOFDAY
31 #error "This module requires gettimeofday() on non-Windows platforms!"
32 #endif
33 #if (defined(PYOS_OS2) && defined(PYCC_GCC)) || defined(__QNX__)
34 #include <sys/time.h>
35 #else
36 #include <sys/resource.h>
37 #include <sys/times.h>
38 #endif
39 typedef struct timeval hs_time;
40 #endif
42 #if !defined(__cplusplus) && !defined(inline)
43 #ifdef __GNUC__
44 #define inline __inline
45 #endif
46 #endif
48 #ifndef inline
49 #define inline
50 #endif
52 #define BUFFERSIZE 10240
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 Py_ssize_t index;
79 unsigned char buffer[BUFFERSIZE];
80 FILE *logfp;
81 int lineevents;
82 int linetimings;
83 int frametimings;
84 /* size_t filled; */
85 int active;
86 int next_fileno;
87 hs_time prev_timeofday;
88 } ProfilerObject;
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));
145 /* Log File Format
146 * ---------------
148 * The log file consists of a sequence of variable-length records.
149 * Each record is identified with a record type identifier in two
150 * bits of the first byte. The two bits are the "least significant"
151 * bits of the byte.
153 * Low bits: Opcode: Meaning:
154 * 0x00 ENTER enter a frame
155 * 0x01 EXIT exit a frame
156 * 0x02 LINENO execution moved onto a different line
157 * 0x03 OTHER more bits are needed to deecode
159 * If the type is OTHER, the record is not packed so tightly, and the
160 * remaining bits are used to disambiguate the record type. These
161 * records are not used as frequently so compaction is not an issue.
162 * Each of the first three record types has a highly tailored
163 * structure that allows it to be packed tightly.
165 * The OTHER records have the following identifiers:
167 * First byte: Opcode: Meaning:
168 * 0x13 ADD_INFO define a key/value pair
169 * 0x23 DEFINE_FILE define an int->filename mapping
170 * 0x33 LINE_TIMES indicates if LINENO events have tdeltas
171 * 0x43 DEFINE_FUNC define a (fileno,lineno)->funcname mapping
172 * 0x53 FRAME_TIMES indicates if ENTER/EXIT events have tdeltas
174 * Packed Integers
176 * "Packed integers" are non-negative integer values encoded as a
177 * sequence of bytes. Each byte is encoded such that the most
178 * significant bit is set if the next byte is also part of the
179 * integer. Each byte provides bits to the least-significant end of
180 * the result; the accumulated value must be shifted up to place the
181 * new bits into the result.
183 * "Modified packed integers" are packed integers where only a portion
184 * of the first byte is used. In the rest of the specification, these
185 * are referred to as "MPI(n,name)", where "n" is the number of bits
186 * discarded from the least-signicant positions of the byte, and
187 * "name" is a name being given to those "discarded" bits, since they
188 * are a field themselves.
190 * ENTER records:
192 * MPI(2,type) fileno -- type is 0x00
193 * PI lineno
194 * PI tdelta -- iff frame times are enabled
196 * EXIT records
198 * MPI(2,type) tdelta -- type is 0x01; tdelta will be 0
199 * if frame times are disabled
201 * LINENO records
203 * MPI(2,type) lineno -- type is 0x02
204 * PI tdelta -- iff LINENO includes it
206 * ADD_INFO records
208 * BYTE type -- always 0x13
209 * PI len1 -- length of first string
210 * BYTE string1[len1] -- len1 bytes of string data
211 * PI len2 -- length of second string
212 * BYTE string2[len2] -- len2 bytes of string data
214 * DEFINE_FILE records
216 * BYTE type -- always 0x23
217 * PI fileno
218 * PI len -- length of filename
219 * BYTE filename[len] -- len bytes of string data
221 * DEFINE_FUNC records
223 * BYTE type -- always 0x43
224 * PI fileno
225 * PI lineno
226 * PI len -- length of funcname
227 * BYTE funcname[len] -- len bytes of string data
229 * LINE_TIMES records
231 * This record can be used only before the start of ENTER/EXIT/LINENO
232 * records. If have_tdelta is true, LINENO records will include the
233 * tdelta field, otherwise it will be omitted. If this record is not
234 * given, LINENO records will not contain the tdelta field.
236 * BYTE type -- always 0x33
237 * BYTE have_tdelta -- 0 if LINENO does *not* have
238 * timing information
239 * FRAME_TIMES records
241 * This record can be used only before the start of ENTER/EXIT/LINENO
242 * records. If have_tdelta is true, ENTER and EXIT records will
243 * include the tdelta field, otherwise it will be omitted. If this
244 * record is not given, ENTER and EXIT records will contain the tdelta
245 * field.
247 * BYTE type -- always 0x53
248 * BYTE have_tdelta -- 0 if ENTER/EXIT do *not* have
249 * timing information
252 #define WHAT_ENTER 0x00
253 #define WHAT_EXIT 0x01
254 #define WHAT_LINENO 0x02
255 #define WHAT_OTHER 0x03 /* only used in decoding */
256 #define WHAT_ADD_INFO 0x13
257 #define WHAT_DEFINE_FILE 0x23
258 #define WHAT_LINE_TIMES 0x33
259 #define WHAT_DEFINE_FUNC 0x43
260 #define WHAT_FRAME_TIMES 0x53
262 #define ERR_NONE 0
263 #define ERR_EOF -1
264 #define ERR_EXCEPTION -2
265 #define ERR_BAD_RECTYPE -3
267 #define PISIZE (sizeof(int) + 1)
268 #define MPISIZE (PISIZE + 1)
270 /* Maximum size of "normal" events -- nothing that contains string data */
271 #define MAXEVENTSIZE (MPISIZE + PISIZE*2)
274 /* Unpack a packed integer; if "discard" is non-zero, unpack a modified
275 * packed integer with "discard" discarded bits.
277 static int
278 unpack_packed_int(LogReaderObject *self, int *pvalue, int discard)
280 int c;
281 int accum = 0;
282 int bits = 0;
283 int cont;
285 do {
286 /* read byte */
287 if ((c = fgetc(self->logfp)) == EOF)
288 return ERR_EOF;
289 accum |= ((c & 0x7F) >> discard) << bits;
290 bits += (7 - discard);
291 cont = c & 0x80;
292 discard = 0;
293 } while (cont);
295 *pvalue = accum;
297 return 0;
300 /* Unpack a string, which is encoded as a packed integer giving the
301 * length of the string, followed by the string data.
303 static int
304 unpack_string(LogReaderObject *self, PyObject **pvalue)
306 int i;
307 int len;
308 int err;
309 int ch;
310 char *buf;
312 if ((err = unpack_packed_int(self, &len, 0)))
313 return err;
315 buf = (char *)malloc(len);
316 if (!buf) {
317 PyErr_NoMemory();
318 return ERR_EXCEPTION;
321 for (i=0; i < len; i++) {
322 ch = fgetc(self->logfp);
323 buf[i] = ch;
324 if (ch == EOF) {
325 free(buf);
326 return ERR_EOF;
329 *pvalue = PyString_FromStringAndSize(buf, len);
330 free(buf);
331 if (*pvalue == NULL) {
332 return ERR_EXCEPTION;
334 return 0;
338 static int
339 unpack_add_info(LogReaderObject *self)
341 PyObject *key;
342 PyObject *value = NULL;
343 int err;
345 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;
358 if (PyDict_SetItem(self->info, key, list)) {
359 Py_DECREF(list);
360 err = ERR_EXCEPTION;
361 goto finally;
363 Py_DECREF(list);
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 if (result == NULL)
486 return NULL;
487 PyTuple_SET_ITEM(result, 0, PyInt_FromLong(what));
488 PyTuple_SET_ITEM(result, 2, PyInt_FromLong(fileno));
489 if (s1 == NULL)
490 PyTuple_SET_ITEM(result, 1, PyInt_FromLong(tdelta));
491 else
492 PyTuple_SET_ITEM(result, 1, s1);
493 if (s2 == NULL)
494 PyTuple_SET_ITEM(result, 3, PyInt_FromLong(lineno));
495 else
496 PyTuple_SET_ITEM(result, 3, s2);
498 /* The only other case is err == ERR_EXCEPTION, in which case the
499 * exception is already set.
501 #if 0
502 b0 = self->buffer[self->index];
503 b1 = self->buffer[self->index + 1];
504 if (b0 & 1) {
505 /* This is a line-number event. */
506 what = PyTrace_LINE;
507 lineno = ((b0 & ~1) << 7) + b1;
508 self->index += 2;
510 else {
511 what = (b0 & 0x0E) >> 1;
512 tdelta = ((b0 & 0xF0) << 4) + b1;
513 if (what == PyTrace_CALL) {
514 /* we know there's a 2-byte file ID & 2-byte line number */
515 fileno = ((self->buffer[self->index + 2] << 8)
516 + self->buffer[self->index + 3]);
517 lineno = ((self->buffer[self->index + 4] << 8)
518 + self->buffer[self->index + 5]);
519 self->index += 6;
521 else
522 self->index += 2;
524 #endif
525 return result;
528 static void
529 logreader_dealloc(LogReaderObject *self)
531 if (self->logfp != NULL) {
532 fclose(self->logfp);
533 self->logfp = NULL;
535 Py_XDECREF(self->info);
536 PyObject_Del(self);
539 static PyObject *
540 logreader_sq_item(LogReaderObject *self, Py_ssize_t index)
542 PyObject *result = logreader_tp_iternext(self);
543 if (result == NULL && !PyErr_Occurred()) {
544 PyErr_SetString(PyExc_IndexError, "no more events in log");
545 return NULL;
547 return result;
550 static void
551 do_stop(ProfilerObject *self);
553 static int
554 flush_data(ProfilerObject *self)
556 /* Need to dump data to the log file... */
557 size_t written = fwrite(self->buffer, 1, self->index, self->logfp);
558 if (written == (size_t)self->index)
559 self->index = 0;
560 else {
561 memmove(self->buffer, &self->buffer[written],
562 self->index - written);
563 self->index -= written;
564 if (written == 0) {
565 char *s = PyString_AsString(self->logfilename);
566 PyErr_SetFromErrnoWithFilename(PyExc_IOError, s);
567 do_stop(self);
568 return -1;
571 if (written > 0) {
572 if (fflush(self->logfp)) {
573 char *s = PyString_AsString(self->logfilename);
574 PyErr_SetFromErrnoWithFilename(PyExc_IOError, s);
575 do_stop(self);
576 return -1;
579 return 0;
582 static inline int
583 pack_packed_int(ProfilerObject *self, int value)
585 unsigned char partial;
587 do {
588 partial = value & 0x7F;
589 value >>= 7;
590 if (value)
591 partial |= 0x80;
592 self->buffer[self->index] = partial;
593 self->index++;
594 } while (value);
595 return 0;
598 /* Encode a modified packed integer, with a subfield of modsize bits
599 * containing the value "subfield". The value of subfield is not
600 * checked to ensure it actually fits in modsize bits.
602 static inline int
603 pack_modified_packed_int(ProfilerObject *self, int value,
604 int modsize, int subfield)
606 const int maxvalues[] = {-1, 1, 3, 7, 15, 31, 63, 127};
608 int bits = 7 - modsize;
609 int partial = value & maxvalues[bits];
610 unsigned char b = subfield | (partial << modsize);
612 if (partial != value) {
613 b |= 0x80;
614 self->buffer[self->index] = b;
615 self->index++;
616 return pack_packed_int(self, value >> bits);
618 self->buffer[self->index] = b;
619 self->index++;
620 return 0;
623 static int
624 pack_string(ProfilerObject *self, const char *s, Py_ssize_t len)
626 if (len + PISIZE + self->index >= BUFFERSIZE) {
627 if (flush_data(self) < 0)
628 return -1;
630 assert(len < INT_MAX);
631 if (pack_packed_int(self, (int)len) < 0)
632 return -1;
633 memcpy(self->buffer + self->index, s, len);
634 self->index += len;
635 return 0;
638 static int
639 pack_add_info(ProfilerObject *self, const char *s1, const char *s2)
641 Py_ssize_t len1 = strlen(s1);
642 Py_ssize_t len2 = strlen(s2);
644 if (len1 + len2 + PISIZE*2 + 1 + self->index >= BUFFERSIZE) {
645 if (flush_data(self) < 0)
646 return -1;
648 self->buffer[self->index] = WHAT_ADD_INFO;
649 self->index++;
650 if (pack_string(self, s1, len1) < 0)
651 return -1;
652 return pack_string(self, s2, len2);
655 static int
656 pack_define_file(ProfilerObject *self, int fileno, const char *filename)
658 Py_ssize_t len = strlen(filename);
660 if (len + PISIZE*2 + 1 + self->index >= BUFFERSIZE) {
661 if (flush_data(self) < 0)
662 return -1;
664 self->buffer[self->index] = WHAT_DEFINE_FILE;
665 self->index++;
666 if (pack_packed_int(self, fileno) < 0)
667 return -1;
668 return pack_string(self, filename, len);
671 static int
672 pack_define_func(ProfilerObject *self, int fileno, int lineno,
673 const char *funcname)
675 Py_ssize_t len = strlen(funcname);
677 if (len + PISIZE*3 + 1 + self->index >= BUFFERSIZE) {
678 if (flush_data(self) < 0)
679 return -1;
681 self->buffer[self->index] = WHAT_DEFINE_FUNC;
682 self->index++;
683 if (pack_packed_int(self, fileno) < 0)
684 return -1;
685 if (pack_packed_int(self, lineno) < 0)
686 return -1;
687 return pack_string(self, funcname, len);
690 static int
691 pack_line_times(ProfilerObject *self)
693 if (2 + self->index >= BUFFERSIZE) {
694 if (flush_data(self) < 0)
695 return -1;
697 self->buffer[self->index] = WHAT_LINE_TIMES;
698 self->buffer[self->index + 1] = self->linetimings ? 1 : 0;
699 self->index += 2;
700 return 0;
703 static int
704 pack_frame_times(ProfilerObject *self)
706 if (2 + self->index >= BUFFERSIZE) {
707 if (flush_data(self) < 0)
708 return -1;
710 self->buffer[self->index] = WHAT_FRAME_TIMES;
711 self->buffer[self->index + 1] = self->frametimings ? 1 : 0;
712 self->index += 2;
713 return 0;
716 static inline int
717 pack_enter(ProfilerObject *self, int fileno, int tdelta, int lineno)
719 if (MPISIZE + PISIZE*2 + self->index >= BUFFERSIZE) {
720 if (flush_data(self) < 0)
721 return -1;
723 pack_modified_packed_int(self, fileno, 2, WHAT_ENTER);
724 pack_packed_int(self, lineno);
725 if (self->frametimings)
726 return pack_packed_int(self, tdelta);
727 else
728 return 0;
731 static inline int
732 pack_exit(ProfilerObject *self, int tdelta)
734 if (MPISIZE + self->index >= BUFFERSIZE) {
735 if (flush_data(self) < 0)
736 return -1;
738 if (self->frametimings)
739 return pack_modified_packed_int(self, tdelta, 2, WHAT_EXIT);
740 self->buffer[self->index] = WHAT_EXIT;
741 self->index++;
742 return 0;
745 static inline int
746 pack_lineno(ProfilerObject *self, int lineno)
748 if (MPISIZE + self->index >= BUFFERSIZE) {
749 if (flush_data(self) < 0)
750 return -1;
752 return pack_modified_packed_int(self, lineno, 2, WHAT_LINENO);
755 static inline int
756 pack_lineno_tdelta(ProfilerObject *self, int lineno, int tdelta)
758 if (MPISIZE + PISIZE + self->index >= BUFFERSIZE) {
759 if (flush_data(self) < 0)
760 return 0;
762 if (pack_modified_packed_int(self, lineno, 2, WHAT_LINENO) < 0)
763 return -1;
764 return pack_packed_int(self, tdelta);
767 static inline int
768 get_fileno(ProfilerObject *self, PyCodeObject *fcode)
770 /* This is only used for ENTER events. */
772 PyObject *obj;
773 PyObject *dict;
774 int fileno;
776 obj = PyDict_GetItem(self->filemap, fcode->co_filename);
777 if (obj == NULL) {
778 /* first sighting of this file */
779 dict = PyDict_New();
780 if (dict == NULL) {
781 return -1;
783 fileno = self->next_fileno;
784 obj = Py_BuildValue("iN", fileno, dict);
785 if (obj == NULL) {
786 return -1;
788 if (PyDict_SetItem(self->filemap, fcode->co_filename, obj)) {
789 Py_DECREF(obj);
790 return -1;
792 self->next_fileno++;
793 Py_DECREF(obj);
794 if (pack_define_file(self, fileno,
795 PyString_AS_STRING(fcode->co_filename)) < 0)
796 return -1;
798 else {
799 /* already know this ID */
800 fileno = PyInt_AS_LONG(PyTuple_GET_ITEM(obj, 0));
801 dict = PyTuple_GET_ITEM(obj, 1);
803 /* make sure we save a function name for this (fileno, lineno) */
804 obj = PyInt_FromLong(fcode->co_firstlineno);
805 if (obj == NULL) {
806 /* We just won't have it saved; too bad. */
807 PyErr_Clear();
809 else {
810 PyObject *name = PyDict_GetItem(dict, obj);
811 if (name == NULL) {
812 if (pack_define_func(self, fileno, fcode->co_firstlineno,
813 PyString_AS_STRING(fcode->co_name)) < 0) {
814 Py_DECREF(obj);
815 return -1;
817 if (PyDict_SetItem(dict, obj, fcode->co_name)) {
818 Py_DECREF(obj);
819 return -1;
822 Py_DECREF(obj);
824 return fileno;
827 static inline int
828 get_tdelta(ProfilerObject *self)
830 int tdelta;
831 #ifdef MS_WINDOWS
832 hs_time tv;
833 hs_time diff;
835 GETTIMEOFDAY(&tv);
836 diff = tv - self->prev_timeofday;
837 tdelta = (int)diff;
838 #else
839 struct timeval tv;
841 GETTIMEOFDAY(&tv);
843 tdelta = tv.tv_usec - self->prev_timeofday.tv_usec;
844 if (tv.tv_sec != self->prev_timeofday.tv_sec)
845 tdelta += (tv.tv_sec - self->prev_timeofday.tv_sec) * 1000000;
846 #endif
847 /* time can go backwards on some multiprocessor systems or by NTP */
848 if (tdelta < 0)
849 return 0;
851 self->prev_timeofday = tv;
852 return tdelta;
856 /* The workhorse: the profiler callback function. */
858 static int
859 tracer_callback(ProfilerObject *self, PyFrameObject *frame, int what,
860 PyObject *arg)
862 int fileno;
864 switch (what) {
865 case PyTrace_CALL:
866 fileno = get_fileno(self, frame->f_code);
867 if (fileno < 0)
868 return -1;
869 return pack_enter(self, fileno,
870 self->frametimings ? get_tdelta(self) : -1,
871 frame->f_code->co_firstlineno);
873 case PyTrace_RETURN:
874 return pack_exit(self, get_tdelta(self));
876 case PyTrace_LINE: /* we only get these events if we asked for them */
877 if (self->linetimings)
878 return pack_lineno_tdelta(self, frame->f_lineno,
879 get_tdelta(self));
880 else
881 return pack_lineno(self, frame->f_lineno);
883 default:
884 /* ignore PyTrace_EXCEPTION */
885 break;
887 return 0;
891 /* A couple of useful helper functions. */
893 #ifdef MS_WINDOWS
894 static LARGE_INTEGER frequency = {0, 0};
895 #endif
897 static unsigned long timeofday_diff = 0;
898 static unsigned long rusage_diff = 0;
900 static void
901 calibrate(void)
903 hs_time tv1, tv2;
905 #ifdef MS_WINDOWS
906 hs_time diff;
907 QueryPerformanceFrequency(&frequency);
908 #endif
910 GETTIMEOFDAY(&tv1);
911 while (1) {
912 GETTIMEOFDAY(&tv2);
913 #ifdef MS_WINDOWS
914 diff = tv2 - tv1;
915 if (diff != 0) {
916 timeofday_diff = (unsigned long)diff;
917 break;
919 #else
920 if (tv1.tv_sec != tv2.tv_sec || tv1.tv_usec != tv2.tv_usec) {
921 if (tv1.tv_sec == tv2.tv_sec)
922 timeofday_diff = tv2.tv_usec - tv1.tv_usec;
923 else
924 timeofday_diff = (1000000 - tv1.tv_usec) + tv2.tv_usec;
925 break;
927 #endif
929 #if defined(MS_WINDOWS) || defined(PYOS_OS2) || \
930 defined(__VMS) || defined (__QNX__)
931 rusage_diff = -1;
932 #else
934 struct rusage ru1, ru2;
936 getrusage(RUSAGE_SELF, &ru1);
937 while (1) {
938 getrusage(RUSAGE_SELF, &ru2);
939 if (ru1.ru_utime.tv_sec != ru2.ru_utime.tv_sec) {
940 rusage_diff = ((1000000 - ru1.ru_utime.tv_usec)
941 + ru2.ru_utime.tv_usec);
942 break;
944 else if (ru1.ru_utime.tv_usec != ru2.ru_utime.tv_usec) {
945 rusage_diff = ru2.ru_utime.tv_usec - ru1.ru_utime.tv_usec;
946 break;
948 else if (ru1.ru_stime.tv_sec != ru2.ru_stime.tv_sec) {
949 rusage_diff = ((1000000 - ru1.ru_stime.tv_usec)
950 + ru2.ru_stime.tv_usec);
951 break;
953 else if (ru1.ru_stime.tv_usec != ru2.ru_stime.tv_usec) {
954 rusage_diff = ru2.ru_stime.tv_usec - ru1.ru_stime.tv_usec;
955 break;
959 #endif
962 static void
963 do_start(ProfilerObject *self)
965 self->active = 1;
966 GETTIMEOFDAY(&self->prev_timeofday);
967 if (self->lineevents)
968 PyEval_SetTrace((Py_tracefunc) tracer_callback, (PyObject *)self);
969 else
970 PyEval_SetProfile((Py_tracefunc) tracer_callback, (PyObject *)self);
973 static void
974 do_stop(ProfilerObject *self)
976 if (self->active) {
977 self->active = 0;
978 if (self->lineevents)
979 PyEval_SetTrace(NULL, NULL);
980 else
981 PyEval_SetProfile(NULL, NULL);
983 if (self->index > 0) {
984 /* Best effort to dump out any remaining data. */
985 flush_data(self);
989 static int
990 is_available(ProfilerObject *self)
992 if (self->active) {
993 PyErr_SetString(ProfilerError, "profiler already active");
994 return 0;
996 if (self->logfp == NULL) {
997 PyErr_SetString(ProfilerError, "profiler already closed");
998 return 0;
1000 return 1;
1004 /* Profiler object interface methods. */
1006 PyDoc_STRVAR(addinfo__doc__,
1007 "addinfo(key, value)\n"
1008 "Insert an ADD_INFO record into the log.");
1010 static PyObject *
1011 profiler_addinfo(ProfilerObject *self, PyObject *args)
1013 PyObject *result = NULL;
1014 char *key, *value;
1016 if (PyArg_ParseTuple(args, "ss:addinfo", &key, &value)) {
1017 if (self->logfp == NULL)
1018 PyErr_SetString(ProfilerError, "profiler already closed");
1019 else {
1020 if (pack_add_info(self, key, value) == 0) {
1021 result = Py_None;
1022 Py_INCREF(result);
1026 return result;
1029 PyDoc_STRVAR(close__doc__,
1030 "close()\n"
1031 "Shut down this profiler and close the log files, even if its active.");
1033 static PyObject *
1034 profiler_close(ProfilerObject *self)
1036 do_stop(self);
1037 if (self->logfp != NULL) {
1038 fclose(self->logfp);
1039 self->logfp = NULL;
1041 Py_INCREF(Py_None);
1042 return Py_None;
1045 #define fileno__doc__ logreader_fileno__doc__
1047 static PyObject *
1048 profiler_fileno(ProfilerObject *self)
1050 if (self->logfp == NULL) {
1051 PyErr_SetString(PyExc_ValueError,
1052 "profiler's file object already closed");
1053 return NULL;
1055 return PyInt_FromLong(fileno(self->logfp));
1058 PyDoc_STRVAR(runcall__doc__,
1059 "runcall(callable[, args[, kw]]) -> callable()\n"
1060 "Profile a specific function call, returning the result of that call.");
1062 static PyObject *
1063 profiler_runcall(ProfilerObject *self, PyObject *args)
1065 PyObject *result = NULL;
1066 PyObject *callargs = NULL;
1067 PyObject *callkw = NULL;
1068 PyObject *callable;
1070 if (PyArg_UnpackTuple(args, "runcall", 1, 3,
1071 &callable, &callargs, &callkw)) {
1072 if (is_available(self)) {
1073 do_start(self);
1074 result = PyEval_CallObjectWithKeywords(callable, callargs, callkw);
1075 do_stop(self);
1078 return result;
1081 PyDoc_STRVAR(runcode__doc__,
1082 "runcode(code, globals[, locals])\n"
1083 "Execute a code object while collecting profile data. If locals is\n"
1084 "omitted, globals is used for the locals as well.");
1086 static PyObject *
1087 profiler_runcode(ProfilerObject *self, PyObject *args)
1089 PyObject *result = NULL;
1090 PyCodeObject *code;
1091 PyObject *globals;
1092 PyObject *locals = NULL;
1094 if (PyArg_ParseTuple(args, "O!O!|O:runcode",
1095 &PyCode_Type, &code,
1096 &PyDict_Type, &globals,
1097 &locals)) {
1098 if (is_available(self)) {
1099 if (locals == NULL || locals == Py_None)
1100 locals = globals;
1101 else if (!PyDict_Check(locals)) {
1102 PyErr_SetString(PyExc_TypeError,
1103 "locals must be a dictionary or None");
1104 return NULL;
1106 do_start(self);
1107 result = PyEval_EvalCode(code, globals, locals);
1108 do_stop(self);
1109 #if 0
1110 if (!PyErr_Occurred()) {
1111 result = Py_None;
1112 Py_INCREF(result);
1114 #endif
1117 return result;
1120 PyDoc_STRVAR(start__doc__,
1121 "start()\n"
1122 "Install this profiler for the current thread.");
1124 static PyObject *
1125 profiler_start(ProfilerObject *self, PyObject *args)
1127 PyObject *result = NULL;
1129 if (is_available(self)) {
1130 do_start(self);
1131 result = Py_None;
1132 Py_INCREF(result);
1134 return result;
1137 PyDoc_STRVAR(stop__doc__,
1138 "stop()\n"
1139 "Remove this profiler from the current thread.");
1141 static PyObject *
1142 profiler_stop(ProfilerObject *self, PyObject *args)
1144 PyObject *result = NULL;
1146 if (!self->active)
1147 PyErr_SetString(ProfilerError, "profiler not active");
1148 else {
1149 do_stop(self);
1150 result = Py_None;
1151 Py_INCREF(result);
1153 return result;
1157 /* Python API support. */
1159 static void
1160 profiler_dealloc(ProfilerObject *self)
1162 do_stop(self);
1163 if (self->logfp != NULL)
1164 fclose(self->logfp);
1165 Py_XDECREF(self->filemap);
1166 Py_XDECREF(self->logfilename);
1167 PyObject_Del((PyObject *)self);
1170 static PyMethodDef profiler_methods[] = {
1171 {"addinfo", (PyCFunction)profiler_addinfo, METH_VARARGS, addinfo__doc__},
1172 {"close", (PyCFunction)profiler_close, METH_NOARGS, close__doc__},
1173 {"fileno", (PyCFunction)profiler_fileno, METH_NOARGS, fileno__doc__},
1174 {"runcall", (PyCFunction)profiler_runcall, METH_VARARGS, runcall__doc__},
1175 {"runcode", (PyCFunction)profiler_runcode, METH_VARARGS, runcode__doc__},
1176 {"start", (PyCFunction)profiler_start, METH_NOARGS, start__doc__},
1177 {"stop", (PyCFunction)profiler_stop, METH_NOARGS, stop__doc__},
1178 {NULL, NULL}
1181 static PyMemberDef profiler_members[] = {
1182 {"frametimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
1183 {"lineevents", T_LONG, offsetof(ProfilerObject, lineevents), READONLY},
1184 {"linetimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
1185 {NULL}
1188 static PyObject *
1189 profiler_get_closed(ProfilerObject *self, void *closure)
1191 PyObject *result = (self->logfp == NULL) ? Py_True : Py_False;
1192 Py_INCREF(result);
1193 return result;
1196 static PyGetSetDef profiler_getsets[] = {
1197 {"closed", (getter)profiler_get_closed, NULL,
1198 PyDoc_STR("True if the profiler's output file has already been closed.")},
1199 {NULL}
1203 PyDoc_STRVAR(profiler_object__doc__,
1204 "High-performance profiler object.\n"
1205 "\n"
1206 "Methods:\n"
1207 "\n"
1208 "close(): Stop the profiler and close the log files.\n"
1209 "fileno(): Returns the file descriptor of the log file.\n"
1210 "runcall(): Run a single function call with profiling enabled.\n"
1211 "runcode(): Execute a code object with profiling enabled.\n"
1212 "start(): Install the profiler and return.\n"
1213 "stop(): Remove the profiler.\n"
1214 "\n"
1215 "Attributes (read-only):\n"
1216 "\n"
1217 "closed: True if the profiler has already been closed.\n"
1218 "frametimings: True if ENTER/EXIT events collect timing information.\n"
1219 "lineevents: True if line events are reported to the profiler.\n"
1220 "linetimings: True if line events collect timing information.");
1222 static PyTypeObject ProfilerType = {
1223 PyVarObject_HEAD_INIT(NULL, 0)
1224 "_hotshot.ProfilerType", /* tp_name */
1225 (int) sizeof(ProfilerObject), /* tp_basicsize */
1226 0, /* tp_itemsize */
1227 (destructor)profiler_dealloc, /* tp_dealloc */
1228 0, /* tp_print */
1229 0, /* tp_getattr */
1230 0, /* tp_setattr */
1231 0, /* tp_compare */
1232 0, /* tp_repr */
1233 0, /* tp_as_number */
1234 0, /* tp_as_sequence */
1235 0, /* tp_as_mapping */
1236 0, /* tp_hash */
1237 0, /* tp_call */
1238 0, /* tp_str */
1239 PyObject_GenericGetAttr, /* tp_getattro */
1240 0, /* tp_setattro */
1241 0, /* tp_as_buffer */
1242 Py_TPFLAGS_DEFAULT, /* tp_flags */
1243 profiler_object__doc__, /* tp_doc */
1244 0, /* tp_traverse */
1245 0, /* tp_clear */
1246 0, /* tp_richcompare */
1247 0, /* tp_weaklistoffset */
1248 0, /* tp_iter */
1249 0, /* tp_iternext */
1250 profiler_methods, /* tp_methods */
1251 profiler_members, /* tp_members */
1252 profiler_getsets, /* tp_getset */
1253 0, /* tp_base */
1254 0, /* tp_dict */
1255 0, /* tp_descr_get */
1256 0, /* tp_descr_set */
1260 static PyMethodDef logreader_methods[] = {
1261 {"close", (PyCFunction)logreader_close, METH_NOARGS,
1262 logreader_close__doc__},
1263 {"fileno", (PyCFunction)logreader_fileno, METH_NOARGS,
1264 logreader_fileno__doc__},
1265 {NULL, NULL}
1268 static PyMemberDef logreader_members[] = {
1269 {"info", T_OBJECT, offsetof(LogReaderObject, info), RO,
1270 PyDoc_STR("Dictionary mapping informational keys to lists of values.")},
1271 {NULL}
1275 PyDoc_STRVAR(logreader__doc__,
1276 "logreader(filename) --> log-iterator\n\
1277 Create a log-reader for the timing information file.");
1279 static PySequenceMethods logreader_as_sequence = {
1280 0, /* sq_length */
1281 0, /* sq_concat */
1282 0, /* sq_repeat */
1283 (ssizeargfunc)logreader_sq_item, /* sq_item */
1284 0, /* sq_slice */
1285 0, /* sq_ass_item */
1286 0, /* sq_ass_slice */
1287 0, /* sq_contains */
1288 0, /* sq_inplace_concat */
1289 0, /* sq_inplace_repeat */
1292 static PyObject *
1293 logreader_get_closed(LogReaderObject *self, void *closure)
1295 PyObject *result = (self->logfp == NULL) ? Py_True : Py_False;
1296 Py_INCREF(result);
1297 return result;
1300 static PyGetSetDef logreader_getsets[] = {
1301 {"closed", (getter)logreader_get_closed, NULL,
1302 PyDoc_STR("True if the logreader's input file has already been closed.")},
1303 {NULL}
1306 static PyTypeObject LogReaderType = {
1307 PyVarObject_HEAD_INIT(NULL, 0)
1308 "_hotshot.LogReaderType", /* tp_name */
1309 (int) sizeof(LogReaderObject), /* tp_basicsize */
1310 0, /* tp_itemsize */
1311 (destructor)logreader_dealloc, /* tp_dealloc */
1312 0, /* tp_print */
1313 0, /* tp_getattr */
1314 0, /* tp_setattr */
1315 0, /* tp_compare */
1316 0, /* tp_repr */
1317 0, /* tp_as_number */
1318 &logreader_as_sequence, /* tp_as_sequence */
1319 0, /* tp_as_mapping */
1320 0, /* tp_hash */
1321 0, /* tp_call */
1322 0, /* tp_str */
1323 PyObject_GenericGetAttr, /* tp_getattro */
1324 0, /* tp_setattro */
1325 0, /* tp_as_buffer */
1326 Py_TPFLAGS_DEFAULT, /* tp_flags */
1327 logreader__doc__, /* tp_doc */
1328 0, /* tp_traverse */
1329 0, /* tp_clear */
1330 0, /* tp_richcompare */
1331 0, /* tp_weaklistoffset */
1332 PyObject_SelfIter, /* tp_iter */
1333 (iternextfunc)logreader_tp_iternext,/* tp_iternext */
1334 logreader_methods, /* tp_methods */
1335 logreader_members, /* tp_members */
1336 logreader_getsets, /* tp_getset */
1337 0, /* tp_base */
1338 0, /* tp_dict */
1339 0, /* tp_descr_get */
1340 0, /* tp_descr_set */
1343 static PyObject *
1344 hotshot_logreader(PyObject *unused, PyObject *args)
1346 LogReaderObject *self = NULL;
1347 char *filename;
1348 int c;
1349 int err = 0;
1351 if (PyArg_ParseTuple(args, "s:logreader", &filename)) {
1352 self = PyObject_New(LogReaderObject, &LogReaderType);
1353 if (self != NULL) {
1354 self->frametimings = 1;
1355 self->linetimings = 0;
1356 self->info = NULL;
1357 self->logfp = fopen(filename, "rb");
1358 if (self->logfp == NULL) {
1359 PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
1360 goto error;
1362 self->info = PyDict_New();
1363 if (self->info == NULL)
1364 goto error;
1365 /* read initial info */
1366 for (;;) {
1367 if ((c = fgetc(self->logfp)) == EOF) {
1368 eof_error(self);
1369 goto error;
1371 if (c != WHAT_ADD_INFO) {
1372 ungetc(c, self->logfp);
1373 break;
1375 err = unpack_add_info(self);
1376 if (err) {
1377 if (err == ERR_EOF)
1378 eof_error(self);
1379 else
1380 PyErr_SetString(PyExc_RuntimeError,
1381 "unexpected error");
1382 goto error;
1387 return (PyObject *) self;
1388 error:
1389 Py_DECREF(self);
1390 return NULL;
1394 /* Return a Python string that represents the version number without the
1395 * extra cruft added by revision control, even if the right options were
1396 * given to the "cvs export" command to make it not include the extra
1397 * cruft.
1399 static char *
1400 get_version_string(void)
1402 static char *rcsid = "$Revision$";
1403 char *rev = rcsid;
1404 char *buffer;
1405 int i = 0;
1407 while (*rev && !isdigit(Py_CHARMASK(*rev)))
1408 ++rev;
1409 while (rev[i] != ' ' && rev[i] != '\0')
1410 ++i;
1411 buffer = (char *)malloc(i + 1);
1412 if (buffer != NULL) {
1413 memmove(buffer, rev, i);
1414 buffer[i] = '\0';
1416 return buffer;
1419 /* Write out a RFC 822-style header with various useful bits of
1420 * information to make the output easier to manage.
1422 static int
1423 write_header(ProfilerObject *self)
1425 char *buffer;
1426 char cwdbuffer[PATH_MAX];
1427 PyObject *temp;
1428 Py_ssize_t i, len;
1430 buffer = get_version_string();
1431 if (buffer == NULL) {
1432 PyErr_NoMemory();
1433 return -1;
1435 pack_add_info(self, "hotshot-version", buffer);
1436 pack_add_info(self, "requested-frame-timings",
1437 (self->frametimings ? "yes" : "no"));
1438 pack_add_info(self, "requested-line-events",
1439 (self->lineevents ? "yes" : "no"));
1440 pack_add_info(self, "requested-line-timings",
1441 (self->linetimings ? "yes" : "no"));
1442 pack_add_info(self, "platform", Py_GetPlatform());
1443 pack_add_info(self, "executable", Py_GetProgramFullPath());
1444 free(buffer);
1445 buffer = (char *) Py_GetVersion();
1446 if (buffer == NULL)
1447 PyErr_Clear();
1448 else
1449 pack_add_info(self, "executable-version", buffer);
1451 #ifdef MS_WINDOWS
1452 PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%I64d", frequency.QuadPart);
1453 pack_add_info(self, "reported-performance-frequency", cwdbuffer);
1454 #else
1455 PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", rusage_diff);
1456 pack_add_info(self, "observed-interval-getrusage", cwdbuffer);
1457 PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", timeofday_diff);
1458 pack_add_info(self, "observed-interval-gettimeofday", cwdbuffer);
1459 #endif
1461 pack_add_info(self, "current-directory",
1462 getcwd(cwdbuffer, sizeof cwdbuffer));
1464 temp = PySys_GetObject("path");
1465 if (temp == NULL || !PyList_Check(temp)) {
1466 PyErr_SetString(PyExc_RuntimeError, "sys.path must be a list");
1467 return -1;
1469 len = PyList_GET_SIZE(temp);
1470 for (i = 0; i < len; ++i) {
1471 PyObject *item = PyList_GET_ITEM(temp, i);
1472 buffer = PyString_AsString(item);
1473 if (buffer == NULL) {
1474 pack_add_info(self, "sys-path-entry", "<non-string-path-entry>");
1475 PyErr_Clear();
1477 else {
1478 pack_add_info(self, "sys-path-entry", buffer);
1481 pack_frame_times(self);
1482 pack_line_times(self);
1484 return 0;
1487 PyDoc_STRVAR(profiler__doc__,
1488 "profiler(logfilename[, lineevents[, linetimes]]) -> profiler\n\
1489 Create a new profiler object.");
1491 static PyObject *
1492 hotshot_profiler(PyObject *unused, PyObject *args)
1494 char *logfilename;
1495 ProfilerObject *self = NULL;
1496 int lineevents = 0;
1497 int linetimings = 1;
1499 if (PyArg_ParseTuple(args, "s|ii:profiler", &logfilename,
1500 &lineevents, &linetimings)) {
1501 self = PyObject_New(ProfilerObject, &ProfilerType);
1502 if (self == NULL)
1503 return NULL;
1504 self->frametimings = 1;
1505 self->lineevents = lineevents ? 1 : 0;
1506 self->linetimings = (lineevents && linetimings) ? 1 : 0;
1507 self->index = 0;
1508 self->active = 0;
1509 self->next_fileno = 0;
1510 self->logfp = NULL;
1511 self->logfilename = PyTuple_GET_ITEM(args, 0);
1512 Py_INCREF(self->logfilename);
1513 self->filemap = PyDict_New();
1514 if (self->filemap == NULL) {
1515 Py_DECREF(self);
1516 return NULL;
1518 self->logfp = fopen(logfilename, "wb");
1519 if (self->logfp == NULL) {
1520 Py_DECREF(self);
1521 PyErr_SetFromErrnoWithFilename(PyExc_IOError, logfilename);
1522 return NULL;
1524 if (timeofday_diff == 0) {
1525 /* Run this several times since sometimes the first
1526 * doesn't give the lowest values, and we're really trying
1527 * to determine the lowest.
1529 calibrate();
1530 calibrate();
1531 calibrate();
1533 if (write_header(self)) {
1534 /* some error occurred, exception has been set */
1535 Py_DECREF(self);
1536 self = NULL;
1539 return (PyObject *) self;
1542 PyDoc_STRVAR(coverage__doc__,
1543 "coverage(logfilename) -> profiler\n\
1544 Returns a profiler that doesn't collect any timing information, which is\n\
1545 useful in building a coverage analysis tool.");
1547 static PyObject *
1548 hotshot_coverage(PyObject *unused, PyObject *args)
1550 char *logfilename;
1551 PyObject *result = NULL;
1553 if (PyArg_ParseTuple(args, "s:coverage", &logfilename)) {
1554 result = hotshot_profiler(unused, args);
1555 if (result != NULL) {
1556 ProfilerObject *self = (ProfilerObject *) result;
1557 self->frametimings = 0;
1558 self->linetimings = 0;
1559 self->lineevents = 1;
1562 return result;
1565 PyDoc_VAR(resolution__doc__) =
1566 #ifdef MS_WINDOWS
1567 PyDoc_STR(
1568 "resolution() -> (performance-counter-ticks, update-frequency)\n"
1569 "Return the resolution of the timer provided by the QueryPerformanceCounter()\n"
1570 "function. The first value is the smallest observed change, and the second\n"
1571 "is the result of QueryPerformanceFrequency()."
1573 #else
1574 PyDoc_STR(
1575 "resolution() -> (gettimeofday-usecs, getrusage-usecs)\n"
1576 "Return the resolution of the timers provided by the gettimeofday() and\n"
1577 "getrusage() system calls, or -1 if the call is not supported."
1579 #endif
1582 static PyObject *
1583 hotshot_resolution(PyObject *self, PyObject *unused)
1585 if (timeofday_diff == 0) {
1586 calibrate();
1587 calibrate();
1588 calibrate();
1590 #ifdef MS_WINDOWS
1591 return Py_BuildValue("ii", timeofday_diff, frequency.LowPart);
1592 #else
1593 return Py_BuildValue("ii", timeofday_diff, rusage_diff);
1594 #endif
1598 static PyMethodDef functions[] = {
1599 {"coverage", hotshot_coverage, METH_VARARGS, coverage__doc__},
1600 {"profiler", hotshot_profiler, METH_VARARGS, profiler__doc__},
1601 {"logreader", hotshot_logreader, METH_VARARGS, logreader__doc__},
1602 {"resolution", hotshot_resolution, METH_NOARGS, resolution__doc__},
1603 {NULL, NULL}
1607 void
1608 init_hotshot(void)
1610 PyObject *module;
1612 Py_TYPE(&LogReaderType) = &PyType_Type;
1613 Py_TYPE(&ProfilerType) = &PyType_Type;
1614 module = Py_InitModule("_hotshot", functions);
1615 if (module != NULL) {
1616 char *s = get_version_string();
1618 PyModule_AddStringConstant(module, "__version__", s);
1619 free(s);
1620 Py_INCREF(&LogReaderType);
1621 PyModule_AddObject(module, "LogReaderType",
1622 (PyObject *)&LogReaderType);
1623 Py_INCREF(&ProfilerType);
1624 PyModule_AddObject(module, "ProfilerType",
1625 (PyObject *)&ProfilerType);
1627 if (ProfilerError == NULL)
1628 ProfilerError = PyErr_NewException("hotshot.ProfilerError",
1629 NULL, NULL);
1630 if (ProfilerError != NULL) {
1631 Py_INCREF(ProfilerError);
1632 PyModule_AddObject(module, "ProfilerError", ProfilerError);
1634 PyModule_AddIntConstant(module, "WHAT_ENTER", WHAT_ENTER);
1635 PyModule_AddIntConstant(module, "WHAT_EXIT", WHAT_EXIT);
1636 PyModule_AddIntConstant(module, "WHAT_LINENO", WHAT_LINENO);
1637 PyModule_AddIntConstant(module, "WHAT_OTHER", WHAT_OTHER);
1638 PyModule_AddIntConstant(module, "WHAT_ADD_INFO", WHAT_ADD_INFO);
1639 PyModule_AddIntConstant(module, "WHAT_DEFINE_FILE", WHAT_DEFINE_FILE);
1640 PyModule_AddIntConstant(module, "WHAT_DEFINE_FUNC", WHAT_DEFINE_FUNC);
1641 PyModule_AddIntConstant(module, "WHAT_LINE_TIMES", WHAT_LINE_TIMES);