14710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/*
24710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * This is the High Performance Python Profiler portion of HotShot.
34710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm */
44710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
54710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#include "Python.h"
64710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#include "code.h"
74710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#include "eval.h"
84710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#include "frameobject.h"
94710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#include "structmember.h"
104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/*
124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * Which timer to use should be made more configurable, but that should not
134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * be difficult.  This will do for now.
144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm */
154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifdef MS_WINDOWS
164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#include <windows.h>
174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifdef HAVE_DIRECT_H
194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#include <direct.h>    /* for getcwd() */
204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtypedef __int64 hs_time;
234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define GETTIMEOFDAY(P_HS_TIME) \
244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        { LARGE_INTEGER _temp; \
254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm          QueryPerformanceCounter(&_temp); \
264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm          *(P_HS_TIME) = _temp.QuadPart; }
274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#else
304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifndef HAVE_GETTIMEOFDAY
314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#error "This module requires gettimeofday() on non-Windows platforms!"
324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#if (defined(PYOS_OS2) && defined(PYCC_GCC)) || defined(__QNX__)
344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#include <sys/time.h>
354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#else
364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#include <sys/resource.h>
374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#include <sys/times.h>
384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtypedef struct timeval hs_time;
404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#if !defined(__cplusplus) && !defined(inline)
434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifdef __GNUC__
444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define inline __inline
454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifndef inline
494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define inline
504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define BUFFERSIZE 10240
534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#if defined(PYOS_OS2) && defined(PYCC_GCC)
554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define PATH_MAX 260
564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#if defined(__sgi) && _COMPILER_VERSION>700 && !defined(PATH_MAX)
594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* fix PATH_MAX not being defined with MIPSPro 7.x
604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm   if mode is ANSI C (default) */
614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define PATH_MAX 1024
624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifndef PATH_MAX
654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   ifdef MAX_PATH
664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#       define PATH_MAX MAX_PATH
674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   elif defined (_POSIX_PATH_MAX)
684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#       define PATH_MAX _POSIX_PATH_MAX
694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   else
704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#       error "Need a defn. for PATH_MAX in _hotshot.c"
714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   endif
724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtypedef struct {
754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject_HEAD
764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *filemap;
774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *logfilename;
784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_ssize_t index;
794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    unsigned char buffer[BUFFERSIZE];
804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    FILE *logfp;
814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int lineevents;
824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int linetimings;
834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int frametimings;
844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    /* size_t filled; */
854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int active;
864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int next_fileno;
874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    hs_time prev_timeofday;
884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm} ProfilerObject;
894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtypedef struct {
914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject_HEAD
924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *info;
934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    FILE *logfp;
944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int linetimings;
954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int frametimings;
964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm} LogReaderObject;
974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject * ProfilerError = NULL;
994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifndef MS_WINDOWS
1024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifdef GETTIMEOFDAY_NO_TZ
1034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define GETTIMEOFDAY(ptv) gettimeofday((ptv))
1044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#else
1054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define GETTIMEOFDAY(ptv) gettimeofday((ptv), (struct timezone *)NULL)
1064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
1074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
1084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* The log reader... */
1114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STRVAR(logreader_close__doc__,
1134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"close()\n"
1144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Close the log file, preventing additional records from being read.");
1154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
1174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmlogreader_close(LogReaderObject *self, PyObject *args)
1184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
1194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->logfp != NULL) {
1204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        fclose(self->logfp);
1214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->logfp = NULL;
1224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
1234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_INCREF(Py_None);
1244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return Py_None;
1264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
1274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STRVAR(logreader_fileno__doc__,
1294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"fileno() -> file descriptor\n"
1304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Returns the file descriptor for the log file, if open.\n"
1314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Raises ValueError if the log file is closed.");
1324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
1344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmlogreader_fileno(LogReaderObject *self)
1354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
1364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->logfp == NULL) {
1374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_SetString(PyExc_ValueError,
1384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                        "logreader's file object already closed");
1394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return NULL;
1404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
1414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return PyInt_FromLong(fileno(self->logfp));
1424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
1434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* Log File Format
1464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * ---------------
1474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
1484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * The log file consists of a sequence of variable-length records.
1494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * Each record is identified with a record type identifier in two
1504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * bits of the first byte.  The two bits are the "least significant"
1514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * bits of the byte.
1524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
1534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * Low bits:    Opcode:        Meaning:
1544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *       0x00         ENTER     enter a frame
1554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *       0x01          EXIT     exit a frame
1564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *       0x02        LINENO     execution moved onto a different line
1574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *       0x03         OTHER     more bits are needed to deecode
1584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
1594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * If the type is OTHER, the record is not packed so tightly, and the
1604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * remaining bits are used to disambiguate the record type.  These
1614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * records are not used as frequently so compaction is not an issue.
1624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * Each of the first three record types has a highly tailored
1634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * structure that allows it to be packed tightly.
1644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
1654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * The OTHER records have the following identifiers:
1664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
1674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * First byte:  Opcode:        Meaning:
1684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *       0x13      ADD_INFO     define a key/value pair
1694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *       0x23   DEFINE_FILE     define an int->filename mapping
1704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *       0x33    LINE_TIMES     indicates if LINENO events have tdeltas
1714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *       0x43   DEFINE_FUNC     define a (fileno,lineno)->funcname mapping
1724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *       0x53   FRAME_TIMES     indicates if ENTER/EXIT events have tdeltas
1734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
1744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * Packed Integers
1754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
1764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * "Packed integers" are non-negative integer values encoded as a
1774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * sequence of bytes.  Each byte is encoded such that the most
1784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * significant bit is set if the next byte is also part of the
1794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * integer.  Each byte provides bits to the least-significant end of
1804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * the result; the accumulated value must be shifted up to place the
1814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * new bits into the result.
1824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
1834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * "Modified packed integers" are packed integers where only a portion
1844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * of the first byte is used.  In the rest of the specification, these
1854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * are referred to as "MPI(n,name)", where "n" is the number of bits
1864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * discarded from the least-signicant positions of the byte, and
1874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * "name" is a name being given to those "discarded" bits, since they
1884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * are a field themselves.
1894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
1904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * ENTER records:
1914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
1924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      MPI(2,type)  fileno          -- type is 0x00
1934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      PI           lineno
1944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      PI           tdelta          -- iff frame times are enabled
1954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
1964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * EXIT records
1974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
1984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      MPI(2,type)  tdelta          -- type is 0x01; tdelta will be 0
1994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *                                      if frame times are disabled
2004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * LINENO records
2024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      MPI(2,type)  lineno          -- type is 0x02
2044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      PI           tdelta          -- iff LINENO includes it
2054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * ADD_INFO records
2074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      BYTE         type            -- always 0x13
2094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      PI           len1            -- length of first string
2104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      BYTE         string1[len1]   -- len1 bytes of string data
2114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      PI           len2            -- length of second string
2124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      BYTE         string2[len2]   -- len2 bytes of string data
2134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * DEFINE_FILE records
2154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      BYTE         type            -- always 0x23
2174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      PI           fileno
2184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      PI           len             -- length of filename
2194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      BYTE         filename[len]   -- len bytes of string data
2204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * DEFINE_FUNC records
2224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      BYTE         type            -- always 0x43
2244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      PI           fileno
2254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      PI           lineno
2264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      PI           len             -- length of funcname
2274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      BYTE         funcname[len]   -- len bytes of string data
2284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * LINE_TIMES records
2304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * This record can be used only before the start of ENTER/EXIT/LINENO
2324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * records.  If have_tdelta is true, LINENO records will include the
2334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * tdelta field, otherwise it will be omitted.  If this record is not
2344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * given, LINENO records will not contain the tdelta field.
2354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      BYTE         type            -- always 0x33
2374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      BYTE         have_tdelta     -- 0 if LINENO does *not* have
2384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *                                      timing information
2394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * FRAME_TIMES records
2404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * This record can be used only before the start of ENTER/EXIT/LINENO
2424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * records.  If have_tdelta is true, ENTER and EXIT records will
2434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * include the tdelta field, otherwise it will be omitted.  If this
2444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * record is not given, ENTER and EXIT records will contain the tdelta
2454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * field.
2464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *
2474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      BYTE         type            -- always 0x53
2484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *      BYTE         have_tdelta     -- 0 if ENTER/EXIT do *not* have
2494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm *                                      timing information
2504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm */
2514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define WHAT_ENTER        0x00
2534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define WHAT_EXIT         0x01
2544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define WHAT_LINENO       0x02
2554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define WHAT_OTHER        0x03  /* only used in decoding */
2564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define WHAT_ADD_INFO     0x13
2574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define WHAT_DEFINE_FILE  0x23
2584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define WHAT_LINE_TIMES   0x33
2594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define WHAT_DEFINE_FUNC  0x43
2604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define WHAT_FRAME_TIMES  0x53
2614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define ERR_NONE          0
2634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define ERR_EOF          -1
2644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define ERR_EXCEPTION    -2
2654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define ERR_BAD_RECTYPE  -3
2664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define PISIZE            (sizeof(int) + 1)
2684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define MPISIZE           (PISIZE + 1)
2694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* Maximum size of "normal" events -- nothing that contains string data */
2714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define MAXEVENTSIZE      (MPISIZE + PISIZE*2)
2724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* Unpack a packed integer; if "discard" is non-zero, unpack a modified
2754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * packed integer with "discard" discarded bits.
2764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm */
2774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
2784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmunpack_packed_int(LogReaderObject *self, int *pvalue, int discard)
2794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
2804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int c;
2814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int accum = 0;
2824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int bits = 0;
2834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int cont;
2844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    do {
2864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        /* read byte */
2874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if ((c = fgetc(self->logfp)) == EOF)
2884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return ERR_EOF;
2894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        accum |= ((c & 0x7F) >> discard) << bits;
2904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        bits += (7 - discard);
2914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        cont = c & 0x80;
2924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        discard = 0;
2934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    } while (cont);
2944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    *pvalue = accum;
2964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 0;
2984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
2994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* Unpack a string, which is encoded as a packed integer giving the
3014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * length of the string, followed by the string data.
3024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm */
3034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
3044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmunpack_string(LogReaderObject *self, PyObject **pvalue)
3054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
3064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int i;
3074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int len;
3084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int err;
3094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int ch;
3104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    char *buf;
3114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if ((err = unpack_packed_int(self, &len, 0)))
3134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return err;
3144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    buf = (char *)malloc(len);
3164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (!buf) {
3174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_NoMemory();
3184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return ERR_EXCEPTION;
3194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
3204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    for (i=0; i < len; i++) {
3224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        ch = fgetc(self->logfp);
3234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        buf[i] = ch;
3244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (ch == EOF) {
3254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            free(buf);
3264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return ERR_EOF;
3274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
3284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
3294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    *pvalue = PyString_FromStringAndSize(buf, len);
3304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    free(buf);
3314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (*pvalue == NULL) {
3324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return ERR_EXCEPTION;
3334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
3344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 0;
3354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
3364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
3394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmunpack_add_info(LogReaderObject *self)
3404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
3414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *key;
3424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *value = NULL;
3434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int err;
3444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    err = unpack_string(self, &key);
3464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (!err) {
3474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        err = unpack_string(self, &value);
3484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (err)
3494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            Py_DECREF(key);
3504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else {
3514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyObject *list = PyDict_GetItem(self->info, key);
3524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (list == NULL) {
3534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                list = PyList_New(0);
3544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                if (list == NULL) {
3554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    err = ERR_EXCEPTION;
3564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    goto finally;
3574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                }
3584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                if (PyDict_SetItem(self->info, key, list)) {
3594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    Py_DECREF(list);
3604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    err = ERR_EXCEPTION;
3614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    goto finally;
3624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                }
3634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                Py_DECREF(list);
3644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
3654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (PyList_Append(list, value))
3664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                err = ERR_EXCEPTION;
3674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
3684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
3694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm finally:
3704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_XDECREF(key);
3714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_XDECREF(value);
3724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return err;
3734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
3744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic void
3774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmeof_error(LogReaderObject *self)
3784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
3794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    fclose(self->logfp);
3804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->logfp = NULL;
3814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyErr_SetString(PyExc_EOFError,
3824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    "end of file with incomplete profile record");
3834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
3844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
3864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmlogreader_tp_iternext(LogReaderObject *self)
3874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
3884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int c;
3894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int what;
3904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int err = ERR_NONE;
3914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int lineno = -1;
3924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int fileno = -1;
3934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int tdelta = -1;
3944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *s1 = NULL, *s2 = NULL;
3954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *result = NULL;
3964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#if 0
3974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    unsigned char b0, b1;
3984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
3994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->logfp == NULL) {
4014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_SetString(ProfilerError,
4024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                        "cannot iterate over closed LogReader object");
4034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return NULL;
4044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
4054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmrestart:
4074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    /* decode the record type */
4084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if ((c = fgetc(self->logfp)) == EOF) {
4094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        fclose(self->logfp);
4104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->logfp = NULL;
4114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return NULL;
4124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
4134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    what = c & WHAT_OTHER;
4144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (what == WHAT_OTHER)
4154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        what = c; /* need all the bits for type */
4164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else
4174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        ungetc(c, self->logfp); /* type byte includes packed int */
4184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    switch (what) {
4204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    case WHAT_ENTER:
4214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        err = unpack_packed_int(self, &fileno, 2);
4224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (!err) {
4234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            err = unpack_packed_int(self, &lineno, 0);
4244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (self->frametimings && !err)
4254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                err = unpack_packed_int(self, &tdelta, 0);
4264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
4274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        break;
4284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    case WHAT_EXIT:
4294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        err = unpack_packed_int(self, &tdelta, 2);
4304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        break;
4314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    case WHAT_LINENO:
4324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        err = unpack_packed_int(self, &lineno, 2);
4334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (self->linetimings && !err)
4344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            err = unpack_packed_int(self, &tdelta, 0);
4354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        break;
4364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    case WHAT_ADD_INFO:
4374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        err = unpack_add_info(self);
4384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        break;
4394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    case WHAT_DEFINE_FILE:
4404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        err = unpack_packed_int(self, &fileno, 0);
4414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (!err) {
4424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            err = unpack_string(self, &s1);
4434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (!err) {
4444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                Py_INCREF(Py_None);
4454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                s2 = Py_None;
4464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
4474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
4484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        break;
4494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    case WHAT_DEFINE_FUNC:
4504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        err = unpack_packed_int(self, &fileno, 0);
4514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (!err) {
4524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            err = unpack_packed_int(self, &lineno, 0);
4534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (!err)
4544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                err = unpack_string(self, &s1);
4554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
4564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        break;
4574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    case WHAT_LINE_TIMES:
4584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if ((c = fgetc(self->logfp)) == EOF)
4594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            err = ERR_EOF;
4604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else {
4614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self->linetimings = c ? 1 : 0;
4624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            goto restart;
4634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
4644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        break;
4654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    case WHAT_FRAME_TIMES:
4664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if ((c = fgetc(self->logfp)) == EOF)
4674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            err = ERR_EOF;
4684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else {
4694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self->frametimings = c ? 1 : 0;
4704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            goto restart;
4714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
4724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        break;
4734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    default:
4744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        err = ERR_BAD_RECTYPE;
4754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
4764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (err == ERR_BAD_RECTYPE) {
4774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_SetString(PyExc_ValueError,
4784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                        "unknown record type in log file");
4794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
4804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else if (err == ERR_EOF) {
4814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        eof_error(self);
4824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
4834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else if (!err) {
4844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        result = PyTuple_New(4);
4854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (result == NULL)
4864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return NULL;
4874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyTuple_SET_ITEM(result, 0, PyInt_FromLong(what));
4884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyTuple_SET_ITEM(result, 2, PyInt_FromLong(fileno));
4894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (s1 == NULL)
4904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyTuple_SET_ITEM(result, 1, PyInt_FromLong(tdelta));
4914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else
4924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyTuple_SET_ITEM(result, 1, s1);
4934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (s2 == NULL)
4944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyTuple_SET_ITEM(result, 3, PyInt_FromLong(lineno));
4954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else
4964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyTuple_SET_ITEM(result, 3, s2);
4974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
4984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    /* The only other case is err == ERR_EXCEPTION, in which case the
4994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm     * exception is already set.
5004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm     */
5014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#if 0
5024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    b0 = self->buffer[self->index];
5034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    b1 = self->buffer[self->index + 1];
5044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (b0 & 1) {
5054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        /* This is a line-number event. */
5064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        what = PyTrace_LINE;
5074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        lineno = ((b0 & ~1) << 7) + b1;
5084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->index += 2;
5094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
5104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else {
5114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        what = (b0 & 0x0E) >> 1;
5124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        tdelta = ((b0 & 0xF0) << 4) + b1;
5134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (what == PyTrace_CALL) {
5144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            /* we know there's a 2-byte file ID & 2-byte line number */
5154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            fileno = ((self->buffer[self->index + 2] << 8)
5164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                      + self->buffer[self->index + 3]);
5174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            lineno = ((self->buffer[self->index + 4] << 8)
5184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                      + self->buffer[self->index + 5]);
5194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self->index += 6;
5204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
5214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else
5224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self->index += 2;
5234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
5244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
5254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return result;
5264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
5274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic void
5294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmlogreader_dealloc(LogReaderObject *self)
5304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
5314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->logfp != NULL) {
5324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        fclose(self->logfp);
5334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->logfp = NULL;
5344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
5354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_XDECREF(self->info);
5364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject_Del(self);
5374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
5384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
5404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmlogreader_sq_item(LogReaderObject *self, Py_ssize_t index)
5414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
5424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *result = logreader_tp_iternext(self);
5434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (result == NULL && !PyErr_Occurred()) {
5444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_SetString(PyExc_IndexError, "no more events in log");
5454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return NULL;
5464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
5474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return result;
5484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
5494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic void
5514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdo_stop(ProfilerObject *self);
5524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
5544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmflush_data(ProfilerObject *self)
5554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
5564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    /* Need to dump data to the log file... */
5574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    size_t written = fwrite(self->buffer, 1, self->index, self->logfp);
5584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (written == (size_t)self->index)
5594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->index = 0;
5604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else {
5614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        memmove(self->buffer, &self->buffer[written],
5624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                self->index - written);
5634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->index -= written;
5644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (written == 0) {
5654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            char *s = PyString_AsString(self->logfilename);
5664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyErr_SetFromErrnoWithFilename(PyExc_IOError, s);
5674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            do_stop(self);
5684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
5694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
5704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
5714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (written > 0) {
5724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (fflush(self->logfp)) {
5734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            char *s = PyString_AsString(self->logfilename);
5744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyErr_SetFromErrnoWithFilename(PyExc_IOError, s);
5754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            do_stop(self);
5764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
5774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
5784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
5794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 0;
5804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
5814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic inline int
5834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmpack_packed_int(ProfilerObject *self, int value)
5844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
5854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    unsigned char partial;
5864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    do {
5884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        partial = value & 0x7F;
5894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        value >>= 7;
5904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (value)
5914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            partial |= 0x80;
5924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->buffer[self->index] = partial;
5934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->index++;
5944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    } while (value);
5954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 0;
5964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
5974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* Encode a modified packed integer, with a subfield of modsize bits
5994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * containing the value "subfield".  The value of subfield is not
6004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * checked to ensure it actually fits in modsize bits.
6014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm */
6024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic inline int
6034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmpack_modified_packed_int(ProfilerObject *self, int value,
6044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                         int modsize, int subfield)
6054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
6064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    const int maxvalues[] = {-1, 1, 3, 7, 15, 31, 63, 127};
6074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int bits = 7 - modsize;
6094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int partial = value & maxvalues[bits];
6104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    unsigned char b = subfield | (partial << modsize);
6114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (partial != value) {
6134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        b |= 0x80;
6144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->buffer[self->index] = b;
6154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->index++;
6164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return pack_packed_int(self, value >> bits);
6174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
6184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->buffer[self->index] = b;
6194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->index++;
6204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 0;
6214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
6224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
6244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmpack_string(ProfilerObject *self, const char *s, Py_ssize_t len)
6254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
6264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (len + PISIZE + self->index >= BUFFERSIZE) {
6274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (flush_data(self) < 0)
6284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
6294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
6304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    assert(len < INT_MAX);
6314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (pack_packed_int(self, (int)len) < 0)
6324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return -1;
6334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    memcpy(self->buffer + self->index, s, len);
6344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->index += len;
6354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 0;
6364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
6374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
6394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmpack_add_info(ProfilerObject *self, const char *s1, const char *s2)
6404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
6414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_ssize_t len1 = strlen(s1);
6424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_ssize_t len2 = strlen(s2);
6434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (len1 + len2 + PISIZE*2 + 1 + self->index >= BUFFERSIZE) {
6454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (flush_data(self) < 0)
6464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
6474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
6484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->buffer[self->index] = WHAT_ADD_INFO;
6494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->index++;
6504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (pack_string(self, s1, len1) < 0)
6514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return -1;
6524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return pack_string(self, s2, len2);
6534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
6544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
6564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmpack_define_file(ProfilerObject *self, int fileno, const char *filename)
6574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
6584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_ssize_t len = strlen(filename);
6594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (len + PISIZE*2 + 1 + self->index >= BUFFERSIZE) {
6614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (flush_data(self) < 0)
6624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
6634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
6644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->buffer[self->index] = WHAT_DEFINE_FILE;
6654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->index++;
6664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (pack_packed_int(self, fileno) < 0)
6674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return -1;
6684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return pack_string(self, filename, len);
6694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
6704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
6724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmpack_define_func(ProfilerObject *self, int fileno, int lineno,
6734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                 const char *funcname)
6744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
6754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_ssize_t len = strlen(funcname);
6764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (len + PISIZE*3 + 1 + self->index >= BUFFERSIZE) {
6784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (flush_data(self) < 0)
6794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
6804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
6814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->buffer[self->index] = WHAT_DEFINE_FUNC;
6824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->index++;
6834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (pack_packed_int(self, fileno) < 0)
6844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return -1;
6854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (pack_packed_int(self, lineno) < 0)
6864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return -1;
6874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return pack_string(self, funcname, len);
6884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
6894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
6914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmpack_line_times(ProfilerObject *self)
6924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
6934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (2 + self->index >= BUFFERSIZE) {
6944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (flush_data(self) < 0)
6954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
6964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
6974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->buffer[self->index] = WHAT_LINE_TIMES;
6984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->buffer[self->index + 1] = self->linetimings ? 1 : 0;
6994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->index += 2;
7004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 0;
7014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
7024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
7034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
7044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmpack_frame_times(ProfilerObject *self)
7054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
7064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (2 + self->index >= BUFFERSIZE) {
7074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (flush_data(self) < 0)
7084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
7094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
7104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->buffer[self->index] = WHAT_FRAME_TIMES;
7114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->buffer[self->index + 1] = self->frametimings ? 1 : 0;
7124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->index += 2;
7134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 0;
7144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
7154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
7164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic inline int
7174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmpack_enter(ProfilerObject *self, int fileno, int tdelta, int lineno)
7184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
7194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (MPISIZE + PISIZE*2 + self->index >= BUFFERSIZE) {
7204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (flush_data(self) < 0)
7214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
7224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
7234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_modified_packed_int(self, fileno, 2, WHAT_ENTER);
7244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_packed_int(self, lineno);
7254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->frametimings)
7264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return pack_packed_int(self, tdelta);
7274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else
7284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 0;
7294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
7304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
7314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic inline int
7324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmpack_exit(ProfilerObject *self, int tdelta)
7334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
7344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (MPISIZE + self->index >= BUFFERSIZE) {
7354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (flush_data(self) < 0)
7364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
7374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
7384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->frametimings)
7394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return pack_modified_packed_int(self, tdelta, 2, WHAT_EXIT);
7404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->buffer[self->index] = WHAT_EXIT;
7414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->index++;
7424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 0;
7434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
7444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
7454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic inline int
7464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmpack_lineno(ProfilerObject *self, int lineno)
7474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
7484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (MPISIZE + self->index >= BUFFERSIZE) {
7494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (flush_data(self) < 0)
7504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
7514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
7524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return pack_modified_packed_int(self, lineno, 2, WHAT_LINENO);
7534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
7544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
7554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic inline int
7564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmpack_lineno_tdelta(ProfilerObject *self, int lineno, int tdelta)
7574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
7584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (MPISIZE + PISIZE + self->index >= BUFFERSIZE) {
7594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (flush_data(self) < 0)
7604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return 0;
7614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
7624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (pack_modified_packed_int(self, lineno, 2, WHAT_LINENO) < 0)
7634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return -1;
7644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return pack_packed_int(self, tdelta);
7654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
7664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
7674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic inline int
7684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmget_fileno(ProfilerObject *self, PyCodeObject *fcode)
7694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
7704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    /* This is only used for ENTER events. */
7714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
7724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *obj;
7734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *dict;
7744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int fileno;
7754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
7764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    obj = PyDict_GetItem(self->filemap, fcode->co_filename);
7774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (obj == NULL) {
7784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        /* first sighting of this file */
7794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        dict = PyDict_New();
7804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (dict == NULL) {
7814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
7824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
7834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        fileno = self->next_fileno;
7844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        obj = Py_BuildValue("iN", fileno, dict);
7854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (obj == NULL) {
7864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
7874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
7884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (PyDict_SetItem(self->filemap, fcode->co_filename, obj)) {
7894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            Py_DECREF(obj);
7904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
7914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
7924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->next_fileno++;
7934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        Py_DECREF(obj);
7944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (pack_define_file(self, fileno,
7954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                             PyString_AS_STRING(fcode->co_filename)) < 0)
7964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
7974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
7984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else {
7994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        /* already know this ID */
8004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        fileno = PyInt_AS_LONG(PyTuple_GET_ITEM(obj, 0));
8014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        dict = PyTuple_GET_ITEM(obj, 1);
8024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
8034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    /* make sure we save a function name for this (fileno, lineno) */
8044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    obj = PyInt_FromLong(fcode->co_firstlineno);
8054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (obj == NULL) {
8064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        /* We just won't have it saved; too bad. */
8074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_Clear();
8084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
8094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else {
8104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyObject *name = PyDict_GetItem(dict, obj);
8114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (name == NULL) {
8124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (pack_define_func(self, fileno, fcode->co_firstlineno,
8134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                                 PyString_AS_STRING(fcode->co_name)) < 0) {
8144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                Py_DECREF(obj);
8154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return -1;
8164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
8174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (PyDict_SetItem(dict, obj, fcode->co_name)) {
8184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                Py_DECREF(obj);
8194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return -1;
8204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
8214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
8224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        Py_DECREF(obj);
8234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
8244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return fileno;
8254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
8264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic inline int
8284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmget_tdelta(ProfilerObject *self)
8294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
8304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int tdelta;
8314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifdef MS_WINDOWS
8324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    hs_time tv;
8334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    hs_time diff;
8344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    GETTIMEOFDAY(&tv);
8364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    diff = tv - self->prev_timeofday;
8374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    tdelta = (int)diff;
8384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#else
8394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    struct timeval tv;
8404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    GETTIMEOFDAY(&tv);
8424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    tdelta = tv.tv_usec - self->prev_timeofday.tv_usec;
8444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (tv.tv_sec != self->prev_timeofday.tv_sec)
8454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        tdelta += (tv.tv_sec - self->prev_timeofday.tv_sec) * 1000000;
8464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
8474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    /* time can go backwards on some multiprocessor systems or by NTP */
8484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (tdelta < 0)
8494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 0;
8504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->prev_timeofday = tv;
8524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return tdelta;
8534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
8544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* The workhorse:  the profiler callback function. */
8574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
8594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtracer_callback(ProfilerObject *self, PyFrameObject *frame, int what,
8604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                PyObject *arg)
8614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
8624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int fileno;
8634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    switch (what) {
8654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    case PyTrace_CALL:
8664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        fileno = get_fileno(self, frame->f_code);
8674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (fileno < 0)
8684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return -1;
8694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return pack_enter(self, fileno,
8704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                          self->frametimings ? get_tdelta(self) : -1,
8714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                          frame->f_code->co_firstlineno);
8724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    case PyTrace_RETURN:
8744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return pack_exit(self, get_tdelta(self));
8754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    case PyTrace_LINE:  /* we only get these events if we asked for them */
8774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (self->linetimings)
8784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return pack_lineno_tdelta(self, frame->f_lineno,
8794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                                      get_tdelta(self));
8804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else
8814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return pack_lineno(self, frame->f_lineno);
8824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    default:
8844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        /* ignore PyTrace_EXCEPTION */
8854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        break;
8864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
8874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 0;
8884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
8894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* A couple of useful helper functions. */
8924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifdef MS_WINDOWS
8944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic LARGE_INTEGER frequency = {0, 0};
8954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
8964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
8974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic unsigned long timeofday_diff = 0;
8984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic unsigned long rusage_diff = 0;
8994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
9004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic void
9014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmcalibrate(void)
9024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
9034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    hs_time tv1, tv2;
9044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
9054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifdef MS_WINDOWS
9064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    hs_time diff;
9074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    QueryPerformanceFrequency(&frequency);
9084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
9094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
9104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    GETTIMEOFDAY(&tv1);
9114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    while (1) {
9124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        GETTIMEOFDAY(&tv2);
9134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifdef MS_WINDOWS
9144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        diff = tv2 - tv1;
9154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (diff != 0) {
9164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            timeofday_diff = (unsigned long)diff;
9174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            break;
9184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
9194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#else
9204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (tv1.tv_sec != tv2.tv_sec || tv1.tv_usec != tv2.tv_usec) {
9214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (tv1.tv_sec == tv2.tv_sec)
9224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                timeofday_diff = tv2.tv_usec - tv1.tv_usec;
9234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            else
9244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                timeofday_diff = (1000000 - tv1.tv_usec) + tv2.tv_usec;
9254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            break;
9264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
9274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
9284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
9294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#if defined(MS_WINDOWS) || defined(PYOS_OS2) || \
9304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    defined(__VMS) || defined (__QNX__)
9314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    rusage_diff = -1;
9324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#else
9334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {
9344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        struct rusage ru1, ru2;
9354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
9364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        getrusage(RUSAGE_SELF, &ru1);
9374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        while (1) {
9384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            getrusage(RUSAGE_SELF, &ru2);
9394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (ru1.ru_utime.tv_sec != ru2.ru_utime.tv_sec) {
9404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                rusage_diff = ((1000000 - ru1.ru_utime.tv_usec)
9414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                               + ru2.ru_utime.tv_usec);
9424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                break;
9434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
9444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            else if (ru1.ru_utime.tv_usec != ru2.ru_utime.tv_usec) {
9454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                rusage_diff = ru2.ru_utime.tv_usec - ru1.ru_utime.tv_usec;
9464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                break;
9474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
9484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            else if (ru1.ru_stime.tv_sec != ru2.ru_stime.tv_sec) {
9494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                rusage_diff = ((1000000 - ru1.ru_stime.tv_usec)
9504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                               + ru2.ru_stime.tv_usec);
9514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                break;
9524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
9534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            else if (ru1.ru_stime.tv_usec != ru2.ru_stime.tv_usec) {
9544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                rusage_diff = ru2.ru_stime.tv_usec - ru1.ru_stime.tv_usec;
9554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                break;
9564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
9574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
9584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
9594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
9604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
9614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
9624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic void
9634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdo_start(ProfilerObject *self)
9644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
9654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    self->active = 1;
9664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    GETTIMEOFDAY(&self->prev_timeofday);
9674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->lineevents)
9684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyEval_SetTrace((Py_tracefunc) tracer_callback, (PyObject *)self);
9694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else
9704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyEval_SetProfile((Py_tracefunc) tracer_callback, (PyObject *)self);
9714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
9724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
9734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic void
9744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdo_stop(ProfilerObject *self)
9754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
9764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->active) {
9774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->active = 0;
9784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (self->lineevents)
9794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyEval_SetTrace(NULL, NULL);
9804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else
9814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyEval_SetProfile(NULL, NULL);
9824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
9834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->index > 0) {
9844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        /* Best effort to dump out any remaining data. */
9854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        flush_data(self);
9864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
9874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
9884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
9894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
9904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmis_available(ProfilerObject *self)
9914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
9924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->active) {
9934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_SetString(ProfilerError, "profiler already active");
9944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 0;
9954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
9964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->logfp == NULL) {
9974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_SetString(ProfilerError, "profiler already closed");
9984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 0;
9994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
10004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 1;
10014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
10024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* Profiler object interface methods. */
10054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STRVAR(addinfo__doc__,
10074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"addinfo(key, value)\n"
10084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Insert an ADD_INFO record into the log.");
10094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
10114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmprofiler_addinfo(ProfilerObject *self, PyObject *args)
10124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
10134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *result = NULL;
10144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    char *key, *value;
10154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (PyArg_ParseTuple(args, "ss:addinfo", &key, &value)) {
10174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (self->logfp == NULL)
10184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyErr_SetString(ProfilerError, "profiler already closed");
10194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else {
10204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (pack_add_info(self, key, value) == 0) {
10214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                result = Py_None;
10224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                Py_INCREF(result);
10234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
10244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
10254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
10264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return result;
10274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
10284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STRVAR(close__doc__,
10304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"close()\n"
10314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Shut down this profiler and close the log files, even if its active.");
10324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
10344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmprofiler_close(ProfilerObject *self)
10354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
10364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    do_stop(self);
10374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->logfp != NULL) {
10384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        fclose(self->logfp);
10394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->logfp = NULL;
10404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
10414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_INCREF(Py_None);
10424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return Py_None;
10434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
10444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#define fileno__doc__ logreader_fileno__doc__
10464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
10484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmprofiler_fileno(ProfilerObject *self)
10494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
10504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->logfp == NULL) {
10514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_SetString(PyExc_ValueError,
10524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                        "profiler's file object already closed");
10534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return NULL;
10544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
10554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return PyInt_FromLong(fileno(self->logfp));
10564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
10574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STRVAR(runcall__doc__,
10594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"runcall(callable[, args[, kw]]) -> callable()\n"
10604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Profile a specific function call, returning the result of that call.");
10614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
10634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmprofiler_runcall(ProfilerObject *self, PyObject *args)
10644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
10654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *result = NULL;
10664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *callargs = NULL;
10674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *callkw = NULL;
10684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *callable;
10694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (PyArg_UnpackTuple(args, "runcall", 1, 3,
10714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                         &callable, &callargs, &callkw)) {
10724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (is_available(self)) {
10734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            do_start(self);
10744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            result = PyEval_CallObjectWithKeywords(callable, callargs, callkw);
10754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            do_stop(self);
10764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
10774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
10784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return result;
10794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
10804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STRVAR(runcode__doc__,
10824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"runcode(code, globals[, locals])\n"
10834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Execute a code object while collecting profile data.  If locals is\n"
10844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"omitted, globals is used for the locals as well.");
10854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
10874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmprofiler_runcode(ProfilerObject *self, PyObject *args)
10884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
10894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *result = NULL;
10904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyCodeObject *code;
10914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *globals;
10924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *locals = NULL;
10934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
10944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (PyArg_ParseTuple(args, "O!O!|O:runcode",
10954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                         &PyCode_Type, &code,
10964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                         &PyDict_Type, &globals,
10974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                         &locals)) {
10984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (is_available(self)) {
10994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (locals == NULL || locals == Py_None)
11004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                locals = globals;
11014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            else if (!PyDict_Check(locals)) {
11024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                PyErr_SetString(PyExc_TypeError,
11034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                                "locals must be a dictionary or None");
11044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return NULL;
11054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
11064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            do_start(self);
11074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            result = PyEval_EvalCode(code, globals, locals);
11084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            do_stop(self);
11094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#if 0
11104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (!PyErr_Occurred()) {
11114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                result = Py_None;
11124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                Py_INCREF(result);
11134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
11144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
11154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
11164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
11174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return result;
11184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
11194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STRVAR(start__doc__,
11214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"start()\n"
11224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Install this profiler for the current thread.");
11234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
11254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmprofiler_start(ProfilerObject *self, PyObject *args)
11264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
11274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *result = NULL;
11284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (is_available(self)) {
11304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        do_start(self);
11314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        result = Py_None;
11324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        Py_INCREF(result);
11334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
11344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return result;
11354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
11364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STRVAR(stop__doc__,
11384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"stop()\n"
11394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Remove this profiler from the current thread.");
11404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
11424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmprofiler_stop(ProfilerObject *self, PyObject *args)
11434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
11444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *result = NULL;
11454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (!self->active)
11474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_SetString(ProfilerError, "profiler not active");
11484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else {
11494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        do_stop(self);
11504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        result = Py_None;
11514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        Py_INCREF(result);
11524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
11534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return result;
11544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
11554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* Python API support. */
11584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic void
11604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmprofiler_dealloc(ProfilerObject *self)
11614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
11624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    do_stop(self);
11634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (self->logfp != NULL)
11644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        fclose(self->logfp);
11654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_XDECREF(self->filemap);
11664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_XDECREF(self->logfilename);
11674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject_Del((PyObject *)self);
11684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
11694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyMethodDef profiler_methods[] = {
11714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"addinfo", (PyCFunction)profiler_addinfo, METH_VARARGS, addinfo__doc__},
11724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"close",   (PyCFunction)profiler_close,   METH_NOARGS,  close__doc__},
11734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"fileno",  (PyCFunction)profiler_fileno,  METH_NOARGS,  fileno__doc__},
11744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"runcall", (PyCFunction)profiler_runcall, METH_VARARGS, runcall__doc__},
11754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"runcode", (PyCFunction)profiler_runcode, METH_VARARGS, runcode__doc__},
11764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"start",   (PyCFunction)profiler_start,   METH_NOARGS,  start__doc__},
11774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"stop",    (PyCFunction)profiler_stop,    METH_NOARGS,  stop__doc__},
11784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {NULL, NULL}
11794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm};
11804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyMemberDef profiler_members[] = {
11824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"frametimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
11834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"lineevents",   T_LONG, offsetof(ProfilerObject, lineevents), READONLY},
11844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"linetimings",  T_LONG, offsetof(ProfilerObject, linetimings), READONLY},
11854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {NULL}
11864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm};
11874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
11894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmprofiler_get_closed(ProfilerObject *self, void *closure)
11904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
11914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *result = (self->logfp == NULL) ? Py_True : Py_False;
11924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_INCREF(result);
11934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return result;
11944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
11954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
11964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyGetSetDef profiler_getsets[] = {
11974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"closed", (getter)profiler_get_closed, NULL,
11984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm     PyDoc_STR("True if the profiler's output file has already been closed.")},
11994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {NULL}
12004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm};
12014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
12024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
12034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STRVAR(profiler_object__doc__,
12044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"High-performance profiler object.\n"
12054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"\n"
12064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Methods:\n"
12074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"\n"
12084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"close():      Stop the profiler and close the log files.\n"
12094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"fileno():     Returns the file descriptor of the log file.\n"
12104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"runcall():    Run a single function call with profiling enabled.\n"
12114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"runcode():    Execute a code object with profiling enabled.\n"
12124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"start():      Install the profiler and return.\n"
12134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"stop():       Remove the profiler.\n"
12144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"\n"
12154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Attributes (read-only):\n"
12164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"\n"
12174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"closed:       True if the profiler has already been closed.\n"
12184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"frametimings: True if ENTER/EXIT events collect timing information.\n"
12194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"lineevents:   True if line events are reported to the profiler.\n"
12204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"linetimings:  True if line events collect timing information.");
12214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
12224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyTypeObject ProfilerType = {
12234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyVarObject_HEAD_INIT(NULL, 0)
12244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    "_hotshot.ProfilerType",            /* tp_name              */
12254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    (int) sizeof(ProfilerObject),       /* tp_basicsize         */
12264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_itemsize          */
12274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    (destructor)profiler_dealloc,       /* tp_dealloc           */
12284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_print             */
12294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_getattr           */
12304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_setattr           */
12314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_compare           */
12324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_repr              */
12334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_as_number         */
12344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_as_sequence       */
12354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_as_mapping        */
12364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_hash              */
12374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_call              */
12384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_str               */
12394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject_GenericGetAttr,            /* tp_getattro          */
12404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_setattro          */
12414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_as_buffer         */
12424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_TPFLAGS_DEFAULT,                 /* tp_flags             */
12434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    profiler_object__doc__,             /* tp_doc               */
12444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_traverse          */
12454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_clear             */
12464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_richcompare       */
12474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_weaklistoffset    */
12484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_iter              */
12494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_iternext          */
12504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    profiler_methods,                   /* tp_methods           */
12514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    profiler_members,                   /* tp_members           */
12524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    profiler_getsets,                   /* tp_getset            */
12534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_base              */
12544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_dict              */
12554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_descr_get         */
12564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_descr_set         */
12574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm};
12584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
12594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
12604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyMethodDef logreader_methods[] = {
12614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"close",   (PyCFunction)logreader_close,  METH_NOARGS,
12624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm     logreader_close__doc__},
12634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"fileno",  (PyCFunction)logreader_fileno, METH_NOARGS,
12644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm     logreader_fileno__doc__},
12654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {NULL, NULL}
12664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm};
12674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
12684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyMemberDef logreader_members[] = {
12694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"info", T_OBJECT, offsetof(LogReaderObject, info), RO,
12704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm     PyDoc_STR("Dictionary mapping informational keys to lists of values.")},
12714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {NULL}
12724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm};
12734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
12744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
12754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STRVAR(logreader__doc__,
12764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"logreader(filename) --> log-iterator\n\
12774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmCreate a log-reader for the timing information file.");
12784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
12794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PySequenceMethods logreader_as_sequence = {
12804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* sq_length */
12814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* sq_concat */
12824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* sq_repeat */
12834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    (ssizeargfunc)logreader_sq_item,    /* sq_item */
12844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* sq_slice */
12854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* sq_ass_item */
12864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* sq_ass_slice */
12874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* sq_contains */
12884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* sq_inplace_concat */
12894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* sq_inplace_repeat */
12904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm};
12914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
12924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
12934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmlogreader_get_closed(LogReaderObject *self, void *closure)
12944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
12954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *result = (self->logfp == NULL) ? Py_True : Py_False;
12964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_INCREF(result);
12974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return result;
12984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
12994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
13004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyGetSetDef logreader_getsets[] = {
13014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"closed", (getter)logreader_get_closed, NULL,
13024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm     PyDoc_STR("True if the logreader's input file has already been closed.")},
13034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {NULL}
13044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm};
13054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
13064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyTypeObject LogReaderType = {
13074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyVarObject_HEAD_INIT(NULL, 0)
13084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    "_hotshot.LogReaderType",           /* tp_name              */
13094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    (int) sizeof(LogReaderObject),      /* tp_basicsize         */
13104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_itemsize          */
13114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    (destructor)logreader_dealloc,      /* tp_dealloc           */
13124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_print             */
13134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_getattr           */
13144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_setattr           */
13154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_compare           */
13164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_repr              */
13174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_as_number         */
13184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    &logreader_as_sequence,             /* tp_as_sequence       */
13194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_as_mapping        */
13204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_hash              */
13214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_call              */
13224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_str               */
13234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject_GenericGetAttr,            /* tp_getattro          */
13244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_setattro          */
13254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_as_buffer         */
13264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_TPFLAGS_DEFAULT,                 /* tp_flags             */
13274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    logreader__doc__,                   /* tp_doc               */
13284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_traverse          */
13294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_clear             */
13304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_richcompare       */
13314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_weaklistoffset    */
13324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject_SelfIter,                  /* tp_iter              */
13334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    (iternextfunc)logreader_tp_iternext,/* tp_iternext          */
13344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    logreader_methods,                  /* tp_methods           */
13354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    logreader_members,                  /* tp_members           */
13364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    logreader_getsets,                  /* tp_getset            */
13374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_base              */
13384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_dict              */
13394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_descr_get         */
13404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    0,                                  /* tp_descr_set         */
13414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm};
13424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
13434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
13444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmhotshot_logreader(PyObject *unused, PyObject *args)
13454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
13464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    LogReaderObject *self = NULL;
13474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    char *filename;
13484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int c;
13494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int err = 0;
13504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
13514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (PyArg_ParseTuple(args, "s:logreader", &filename)) {
13524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self = PyObject_New(LogReaderObject, &LogReaderType);
13534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (self != NULL) {
13544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self->frametimings = 1;
13554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self->linetimings = 0;
13564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self->info = NULL;
13574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self->logfp = fopen(filename, "rb");
13584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (self->logfp == NULL) {
13594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename);
13604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                goto error;
13614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
13624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self->info = PyDict_New();
13634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if (self->info == NULL)
13644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                goto error;
13654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            /* read initial info */
13664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            for (;;) {
13674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                if ((c = fgetc(self->logfp)) == EOF) {
13684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    eof_error(self);
13694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    goto error;
13704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                }
13714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                if (c != WHAT_ADD_INFO) {
13724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    ungetc(c, self->logfp);
13734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    break;
13744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                }
13754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                err = unpack_add_info(self);
13764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                if (err) {
13774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    if (err == ERR_EOF)
13784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                        eof_error(self);
13794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    else
13804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                        PyErr_SetString(PyExc_RuntimeError,
13814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                                        "unexpected error");
13824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    goto error;
13834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                }
13844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            }
13854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
13864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
13874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return (PyObject *) self;
13884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm  error:
13894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_DECREF(self);
13904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return NULL;
13914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
13924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
13934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
13944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* Return a Python string that represents the version number without the
13954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * extra cruft added by revision control, even if the right options were
13964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * given to the "cvs export" command to make it not include the extra
13974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * cruft.
13984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm */
13994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic char *
14004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmget_version_string(void)
14014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
14024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    static char *rcsid = "$Revision$";
14034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    char *rev = rcsid;
14044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    char *buffer;
14054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int i = 0;
14064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
14074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    while (*rev && !isdigit(Py_CHARMASK(*rev)))
14084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        ++rev;
14094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    while (rev[i] != ' ' && rev[i] != '\0')
14104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        ++i;
14114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    buffer = (char *)malloc(i + 1);
14124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (buffer != NULL) {
14134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        memmove(buffer, rev, i);
14144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        buffer[i] = '\0';
14154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
14164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return buffer;
14174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
14184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
14194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm/* Write out a RFC 822-style header with various useful bits of
14204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm * information to make the output easier to manage.
14214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm */
14224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic int
14234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmwrite_header(ProfilerObject *self)
14244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
14254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    char *buffer;
14264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    char cwdbuffer[PATH_MAX];
14274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *temp;
14284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_ssize_t i, len;
14294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
14304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    buffer = get_version_string();
14314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (buffer == NULL) {
14324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_NoMemory();
14334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return -1;
14344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
14354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_add_info(self, "hotshot-version", buffer);
14364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_add_info(self, "requested-frame-timings",
14374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                  (self->frametimings ? "yes" : "no"));
14384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_add_info(self, "requested-line-events",
14394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                  (self->lineevents ? "yes" : "no"));
14404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_add_info(self, "requested-line-timings",
14414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                  (self->linetimings ? "yes" : "no"));
14424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_add_info(self, "platform", Py_GetPlatform());
14434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_add_info(self, "executable", Py_GetProgramFullPath());
14444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    free(buffer);
14454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    buffer = (char *) Py_GetVersion();
14464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (buffer == NULL)
14474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_Clear();
14484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else
14494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        pack_add_info(self, "executable-version", buffer);
14504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
14514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifdef MS_WINDOWS
14524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%I64d", frequency.QuadPart);
14534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_add_info(self, "reported-performance-frequency", cwdbuffer);
14544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#else
14554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", rusage_diff);
14564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_add_info(self, "observed-interval-getrusage", cwdbuffer);
14574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", timeofday_diff);
14584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_add_info(self, "observed-interval-gettimeofday", cwdbuffer);
14594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
14604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
14614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_add_info(self, "current-directory",
14624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                  getcwd(cwdbuffer, sizeof cwdbuffer));
14634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
14644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    temp = PySys_GetObject("path");
14654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (temp == NULL || !PyList_Check(temp)) {
14664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyErr_SetString(PyExc_RuntimeError, "sys.path must be a list");
14674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return -1;
14684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
14694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    len = PyList_GET_SIZE(temp);
14704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    for (i = 0; i < len; ++i) {
14714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyObject *item = PyList_GET_ITEM(temp, i);
14724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        buffer = PyString_AsString(item);
14734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (buffer == NULL) {
14744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            pack_add_info(self, "sys-path-entry", "<non-string-path-entry>");
14754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyErr_Clear();
14764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
14774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else {
14784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            pack_add_info(self, "sys-path-entry", buffer);
14794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
14804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
14814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_frame_times(self);
14824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pack_line_times(self);
14834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
14844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 0;
14854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
14864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
14874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STRVAR(profiler__doc__,
14884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"profiler(logfilename[, lineevents[, linetimes]]) -> profiler\n\
14894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmCreate a new profiler object.");
14904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
14914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
14924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmhotshot_profiler(PyObject *unused, PyObject *args)
14934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
14944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    char *logfilename;
14954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    ProfilerObject *self = NULL;
14964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int lineevents = 0;
14974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    int linetimings = 1;
14984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
14994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (PyArg_ParseTuple(args, "s|ii:profiler", &logfilename,
15004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                         &lineevents, &linetimings)) {
15014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self = PyObject_New(ProfilerObject, &ProfilerType);
15024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (self == NULL)
15034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return NULL;
15044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->frametimings = 1;
15054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->lineevents = lineevents ? 1 : 0;
15064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->linetimings = (lineevents && linetimings) ? 1 : 0;
15074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->index = 0;
15084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->active = 0;
15094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->next_fileno = 0;
15104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->logfp = NULL;
15114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->logfilename = PyTuple_GET_ITEM(args, 0);
15124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        Py_INCREF(self->logfilename);
15134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->filemap = PyDict_New();
15144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (self->filemap == NULL) {
15154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            Py_DECREF(self);
15164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return NULL;
15174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
15184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self->logfp = fopen(logfilename, "wb");
15194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (self->logfp == NULL) {
15204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            Py_DECREF(self);
15214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyErr_SetFromErrnoWithFilename(PyExc_IOError, logfilename);
15224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return NULL;
15234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
15244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (timeofday_diff == 0) {
15254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            /* Run this several times since sometimes the first
15264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm             * doesn't give the lowest values, and we're really trying
15274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm             * to determine the lowest.
15284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm             */
15294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            calibrate();
15304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            calibrate();
15314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            calibrate();
15324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
15334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (write_header(self)) {
15344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            /* some error occurred, exception has been set */
15354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            Py_DECREF(self);
15364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self = NULL;
15374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
15384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
15394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return (PyObject *) self;
15404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
15414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
15424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STRVAR(coverage__doc__,
15434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"coverage(logfilename) -> profiler\n\
15444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmReturns a profiler that doesn't collect any timing information, which is\n\
15454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmuseful in building a coverage analysis tool.");
15464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
15474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
15484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmhotshot_coverage(PyObject *unused, PyObject *args)
15494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
15504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    char *logfilename;
15514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *result = NULL;
15524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
15534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (PyArg_ParseTuple(args, "s:coverage", &logfilename)) {
15544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        result = hotshot_profiler(unused, args);
15554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (result != NULL) {
15564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            ProfilerObject *self = (ProfilerObject *) result;
15574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self->frametimings = 0;
15584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self->linetimings = 0;
15594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self->lineevents = 1;
15604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
15614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
15624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return result;
15634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
15644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
15654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_VAR(resolution__doc__) =
15664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifdef MS_WINDOWS
15674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STR(
15684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"resolution() -> (performance-counter-ticks, update-frequency)\n"
15694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Return the resolution of the timer provided by the QueryPerformanceCounter()\n"
15704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"function.  The first value is the smallest observed change, and the second\n"
15714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"is the result of QueryPerformanceFrequency()."
15724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm)
15734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#else
15744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmPyDoc_STR(
15754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"resolution() -> (gettimeofday-usecs, getrusage-usecs)\n"
15764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"Return the resolution of the timers provided by the gettimeofday() and\n"
15774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"getrusage() system calls, or -1 if the call is not supported."
15784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm)
15794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
15804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm;
15814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
15824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyObject *
15834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmhotshot_resolution(PyObject *self, PyObject *unused)
15844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
15854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (timeofday_diff == 0) {
15864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        calibrate();
15874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        calibrate();
15884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        calibrate();
15894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
15904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#ifdef MS_WINDOWS
15914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return Py_BuildValue("ii", timeofday_diff, frequency.LowPart);
15924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#else
15934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return Py_BuildValue("ii", timeofday_diff, rusage_diff);
15944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#endif
15954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
15964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
15974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
15984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmstatic PyMethodDef functions[] = {
15994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"coverage",   hotshot_coverage,   METH_VARARGS, coverage__doc__},
16004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"profiler",   hotshot_profiler,   METH_VARARGS, profiler__doc__},
16014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"logreader",  hotshot_logreader,  METH_VARARGS, logreader__doc__},
16024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {"resolution", hotshot_resolution, METH_NOARGS,  resolution__doc__},
16034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    {NULL, NULL}
16044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm};
16054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
16064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
16074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmvoid
16084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylminit_hotshot(void)
16094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm{
16104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    PyObject *module;
16114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
16124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_TYPE(&LogReaderType) = &PyType_Type;
16134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Py_TYPE(&ProfilerType) = &PyType_Type;
16144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    module = Py_InitModule("_hotshot", functions);
16154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if (module != NULL) {
16164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        char *s = get_version_string();
16174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
16184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyModule_AddStringConstant(module, "__version__", s);
16194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        free(s);
16204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        Py_INCREF(&LogReaderType);
16214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyModule_AddObject(module, "LogReaderType",
16224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                           (PyObject *)&LogReaderType);
16234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        Py_INCREF(&ProfilerType);
16244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyModule_AddObject(module, "ProfilerType",
16254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                           (PyObject *)&ProfilerType);
16264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
16274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (ProfilerError == NULL)
16284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            ProfilerError = PyErr_NewException("hotshot.ProfilerError",
16294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                                               NULL, NULL);
16304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if (ProfilerError != NULL) {
16314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            Py_INCREF(ProfilerError);
16324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            PyModule_AddObject(module, "ProfilerError", ProfilerError);
16334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        }
16344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyModule_AddIntConstant(module, "WHAT_ENTER", WHAT_ENTER);
16354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyModule_AddIntConstant(module, "WHAT_EXIT", WHAT_EXIT);
16364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyModule_AddIntConstant(module, "WHAT_LINENO", WHAT_LINENO);
16374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyModule_AddIntConstant(module, "WHAT_OTHER", WHAT_OTHER);
16384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyModule_AddIntConstant(module, "WHAT_ADD_INFO", WHAT_ADD_INFO);
16394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyModule_AddIntConstant(module, "WHAT_DEFINE_FILE", WHAT_DEFINE_FILE);
16404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyModule_AddIntConstant(module, "WHAT_DEFINE_FUNC", WHAT_DEFINE_FUNC);
16414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        PyModule_AddIntConstant(module, "WHAT_LINE_TIMES", WHAT_LINE_TIMES);
16424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    }
16434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm}
1644