--- _lsprof_rev59564.c 2008-03-22 10:47:01.000000000 -0700 +++ _lsprof.c 2008-03-13 12:49:52.000000000 -0700 @@ -4,80 +4,182 @@ #include "structseq.h" #include "rotatingtree.h" -#if !defined(HAVE_LONG_LONG) -#error "This module requires long longs!" + +#if 1 /* XXX is 0 in original code */ +# define lsprofMalloc(n) PyObject_MALLOC(n) +# define lsprofFree(p) PyObject_FREE(p) +#else +# define lsprofMalloc(n) malloc(n) +# define lsprofFree(p) free(p) #endif -/*** Selection of a high-precision timer ***/ +#ifdef HAVE_LONG_LONG + typedef unsigned PY_LONG_LONG hpTime_t; +# define HPTIMER SIZEOF_LONG_LONG +#elif + typedef unsigned long hpTime_t; +# define HPTIMER SIZEOF_LONG +#endif -#ifdef MS_WINDOWS +#if HPTIMER != 8 +# error "This module requires long longs or 64-bit longs!" +#endif -#include -static PY_LONG_LONG -hpTimer(void) -{ - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - return li.QuadPart; -} +/*** Selection of a high-precision timer ***/ -static double -hpTimerUnit(void) -{ - LARGE_INTEGER li; - if (QueryPerformanceFrequency(&li)) - return 1.0 / li.QuadPart; - else - return 0.000001; /* unlikely */ -} +#ifdef MS_WINDOWS -#else /* !MS_WINDOWS */ +# include -#ifndef HAVE_GETTIMEOFDAY -#error "This module requires gettimeofday() on non-Windows platforms!" -#endif + static hpTime_t + hpTimer(void) + { + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + return (hpTime_t) li.QuadPart; + } + + static double + hpTimerUnit(void) + { + LARGE_INTEGER li; + if (QueryPerformanceFrequency(&li)) + return 1.0 / (double) li.QuadPart; + else + return 0.000001; /* unlikely */ + } -#if (defined(PYOS_OS2) && defined(PYCC_GCC)) -#include -#else -#include -#include -#endif +#else /* !MS_WINDOWS */ -static PY_LONG_LONG -hpTimer(void) -{ - struct timeval tv; - PY_LONG_LONG ret; -#ifdef GETTIMEOFDAY_NO_TZ - gettimeofday(&tv); -#else - gettimeofday(&tv, (struct timezone *)NULL); -#endif - ret = tv.tv_sec; - ret = ret * 1000000 + tv.tv_usec; - return ret; -} - -static double -hpTimerUnit(void) -{ - return 0.000001; -} +# ifndef HAVE_GETTIMEOFDAY +# error "This module requires gettimeofday() on non-Windows platforms!" +# endif + +# if (defined(PYOS_OS2) && defined(PYCC_GCC)) +# include +# else +# include +# include +# endif + + /* XXX HAVE_GETHRTIME should probably be defined in + pyconfig.h. Solaris and HP-UX provide a function + gethrtime returning a 64-bit time stamp with nano- + second accuracy (using a very low overhead system + call on Solaris UltraSPARC). */ +# if defined(HAVE_GETHRTIME) /* Solaris and HP-UX only */ +# include +# define hpTimer (hpTime_t) gethrtime + +# elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + static hpTime_t + hpTimer (void) + { + hpTime_t h; +# ifdef rdtscll + /* rdtscll() is defined in + of certain, recent Linux distro's */ + rdtscll(h); +# else + unsigned int hi, lo; + asm volatile ("rdtsc" : "=a" (lo), "=d" (hi)); + h = (((hpTime_t) hi) << 32) | (hpTime_t) lo; +# endif + return (h); + } + +# elif defined (__GNUC__) && (defined(__powerpc64__) || defined(__POWERPC64__)) +# warning "This module is untested on 64-bit PPC." + static hpTime_t + hpTimer (void) + { + hpTime_t h; + asm volatile ("mftb %0" : "=r" (h)); + return (h); + } + +# elif defined (__GNUC__) && (defined(__ppc__) || defined(__POWERPC__)) + static hpTime_t + hpTimer (void) + { + hpTime_t h; + unsigned int hi, hi2, lo; + do { /* see also .../Python/ceval.c */ + asm volatile ("mftbu %0 \n" + "mftb %1 \n" + "mftbu %2 \n" : "=r"(hi), "=r"(lo), "=r"(hi2)); + } while (__builtin_expect(hi != hi2, 0)); +# if 0 /* see also .../Python/ceval.c */ + ((unsigned int*)(h))[0] = hi; + ((unsigned int*)(h))[1] = lo; +# else + h = (((hpTime_t) hi) << 32) | (hpTime_t) lo; +# endif + return (h); + } + +# else /* no hires timer, use hpTimeofday */ +# undef HPTIMER +# define hpTimer hpTimeofday +# endif + + static hpTime_t + hpTimeofday (void) /* in usec ticks */ + { + hpTime_t h; + struct timeval tv; +# ifdef GETTIMEOFDAY_NO_TZ + gettimeofday(&tv) +# else + gettimeofday(&tv, (struct timezone *) NULL); +# endif + h = (hpTime_t) tv.tv_usec + (hpTime_t) 1000000 * (hpTime_t) tv.tv_sec; + return h; + } + +# ifdef HPTIMER + static hpTime_t Timer0 = (hpTime_t) 0; + static hpTime_t Tod0 = (hpTime_t) 0; +# endif + + static double + hpTimerUnit(void) + { +# ifdef HPTIMER + hpTime_t t, h; + /* determine the hpTimer tick length by waiting + at least 0.25 secs since the very start */ + hpTime_t Tod1 = Tod0 + (hpTime_t) 250000; + do { + t = hpTimeofday(); + h = hpTimer(); + /* reset on wrap around of either */ + if (h < Timer0 || t < Tod0) { + Timer0 = h; + Tod0 = t; + Tod1 = t + (hpTime_t) 250000; + } + } while (t <= Tod1 && h <= Timer0); + return (0.000001 * (double) (t - Tod0) / (double) (h - Timer0)); +# else + /* hpTimeofday returns usec ticks */ + return 0.000001; +# endif + } #endif /* MS_WINDOWS */ /************************************************************/ /* Written by Brett Rosen and Ted Czotter */ -struct _ProfilerEntry; +/* XXX struct _ProfilerEntry; */ /* represents a function called from another function */ typedef struct _ProfilerSubEntry { rotating_node_t header; - PY_LONG_LONG tt; - PY_LONG_LONG it; + hpTime_t tt; + hpTime_t it; long callcount; long recursivecallcount; long recursionLevel; @@ -87,8 +189,8 @@ typedef struct _ProfilerEntry { rotating_node_t header; PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */ - PY_LONG_LONG tt; /* total time in this entry */ - PY_LONG_LONG it; /* inline time in this entry (not in subcalls) */ + hpTime_t tt; /* total time in this entry */ + hpTime_t it; /* inline time in this entry (not in subcalls) */ long callcount; /* how many times this was called */ long recursivecallcount; /* how many times called recursively */ long recursionLevel; @@ -96,8 +198,8 @@ } ProfilerEntry; typedef struct _ProfilerContext { - PY_LONG_LONG t0; - PY_LONG_LONG subt; + hpTime_t t0; + hpTime_t subt; struct _ProfilerContext *previous; ProfilerEntry *ctxEntry; } ProfilerContext; @@ -117,7 +219,7 @@ #define POF_BUILTINS 0x004 #define POF_NOMEMORY 0x100 -staticforward PyTypeObject PyProfiler_Type; +static PyTypeObject PyProfiler_Type; #define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type) #define PyProfiler_CheckExact(op) (Py_TYPE(op) == &PyProfiler_Type) @@ -125,33 +227,37 @@ /*** External Timers ***/ #define DOUBLE_TIMER_PRECISION 4294967296.0 -static PyObject *empty_tuple; +static PyObject *empty_tuple = (PyObject *) NULL; -static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj) +static hpTime_t CallExternalTimer(ProfilerObject *pObj) { - PY_LONG_LONG result; + hpTime_t result; PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL); if (o == NULL) { PyErr_WriteUnraisable(pObj->externalTimer); - return 0; + return (hpTime_t) 0; } if (pObj->externalTimerUnit > 0.0) { /* interpret the result as an integer that will be scaled in profiler_getstats() */ - result = PyLong_AsLongLong(o); +#ifdef HAVE_LONG_LONG + result = (hpTime_t) PyLong_AsLongLong(o); +#else + result = (hpTime_t) PyLong_AsLong(o); +#endif } else { /* interpret the result as a double measured in seconds. - As the profiler works with PY_LONG_LONG internally + As the profiler works with hpTime_t internally we convert it to a large integer */ double val = PyFloat_AsDouble(o); /* error handling delayed to the code below */ - result = (PY_LONG_LONG) (val * DOUBLE_TIMER_PRECISION); + result = (hpTime_t) (val * DOUBLE_TIMER_PRECISION); } Py_DECREF(o); if (PyErr_Occurred()) { PyErr_WriteUnraisable((PyObject *) pObj); - return 0; + return (hpTime_t) 0; } return result; } @@ -178,34 +284,34 @@ if (fn->m_self == NULL) { /* built-in function: look up the module name */ PyObject *mod = fn->m_module; - char *modname; - if (mod && PyString_Check(mod)) { - modname = PyString_AS_STRING(mod); + const char *modname; + if (mod && PyUnicode_Check(mod)) { + modname = PyUnicode_AsString(mod); } else if (mod && PyModule_Check(mod)) { modname = PyModule_GetName(mod); if (modname == NULL) { PyErr_Clear(); - modname = "__builtin__"; + modname = "builtins"; } } else { - modname = "__builtin__"; + modname = "builtins"; } - if (strcmp(modname, "__builtin__") != 0) - return PyString_FromFormat("<%s.%s>", - modname, - fn->m_ml->ml_name); + if (strcmp(modname, "builtins") != 0) + return PyUnicode_FromFormat("<%s.%s>", + modname, + fn->m_ml->ml_name); else - return PyString_FromFormat("<%s>", - fn->m_ml->ml_name); + return PyUnicode_FromFormat("<%s>", + fn->m_ml->ml_name); } else { /* built-in method: try to return repr(getattr(type(__self__), __name__)) */ PyObject *self = fn->m_self; - PyObject *name = PyString_FromString(fn->m_ml->ml_name); + PyObject *name = PyUnicode_FromString(fn->m_ml->ml_name); if (name != NULL) { PyObject *mo = _PyType_Lookup(Py_TYPE(self), name); Py_XINCREF(mo); @@ -218,8 +324,8 @@ } } PyErr_Clear(); - return PyString_FromFormat("", - fn->m_ml->ml_name); + return PyUnicode_FromFormat("", + fn->m_ml->ml_name); } } @@ -227,7 +333,7 @@ newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj) { ProfilerEntry *self; - self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry)); + self = (ProfilerEntry*) lsprofMalloc(sizeof(ProfilerEntry)); if (self == NULL) { pObj->flags |= POF_NOMEMORY; return NULL; @@ -235,14 +341,14 @@ userObj = normalizeUserObj(userObj); if (userObj == NULL) { PyErr_Clear(); - free(self); + lsprofFree(self); pObj->flags |= POF_NOMEMORY; return NULL; } self->header.key = key; self->userObj = userObj; - self->tt = 0; - self->it = 0; + self->tt = (hpTime_t) 0; + self->it = (hpTime_t) 0; self->callcount = 0; self->recursivecallcount = 0; self->recursionLevel = 0; @@ -268,7 +374,7 @@ newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry) { ProfilerSubEntry *self; - self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry)); + self = (ProfilerSubEntry*) lsprofMalloc(sizeof(ProfilerSubEntry)); if (self == NULL) { pObj->flags |= POF_NOMEMORY; return NULL; @@ -286,7 +392,7 @@ static int freeSubEntry(rotating_node_t *header, void *arg) { ProfilerSubEntry *subentry = (ProfilerSubEntry*) header; - free(subentry); + lsprofFree(subentry); return 0; } @@ -295,7 +401,7 @@ ProfilerEntry *entry = (ProfilerEntry*) header; RotatingTree_Enum(entry->calls, freeSubEntry, NULL); Py_DECREF(entry->userObj); - free(entry); + lsprofFree(entry); return 0; } @@ -307,7 +413,7 @@ while (pObj->freelistProfilerContext) { ProfilerContext *c = pObj->freelistProfilerContext; pObj->freelistProfilerContext = c->previous; - free(c); + lsprofFree(c); } } @@ -334,8 +440,8 @@ static void Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry) { - PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0; - PY_LONG_LONG it = tt - self->subt; + hpTime_t tt = CALL_TIMER(pObj) - self->t0; + hpTime_t it = tt - self->subt; if (self->previous) self->previous->subt += tt; pObj->currentProfilerContext = self->previous; @@ -392,7 +498,7 @@ else { /* free list exhausted, allocate a new one */ pContext = (ProfilerContext*) - malloc(sizeof(ProfilerContext)); + lsprofMalloc(sizeof(ProfilerContext)); if (pContext == NULL) { pObj->flags |= POF_NOMEMORY; goto restorePyerr; @@ -527,7 +633,7 @@ 5 }; -static int initialized; +static int initialized = 0; static PyTypeObject StatsEntryType; static PyTypeObject StatsSubEntryType; @@ -687,7 +793,7 @@ profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds) { int subcalls = -1; - int builtins = -1; + int builtins = -1; static char *kwlist[] = {"subcalls", "builtins", 0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable", kwlist, &subcalls, &builtins)) @@ -711,7 +817,7 @@ else pObj->currentProfilerContext = pContext->previous; if (pContext) - free(pContext); + lsprofFree(pContext); } } @@ -811,9 +917,8 @@ is, in seconds).\n\ "); -statichere PyTypeObject PyProfiler_Type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ +static PyTypeObject PyProfiler_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "_lsprof.Profiler", /* tp_name */ sizeof(ProfilerObject), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -862,6 +967,12 @@ init_lsprof(void) { PyObject *module, *d; +# ifdef HPTIMER + if (!initialized) { + Tod0 = hpTimeofday(); + Timer0 = hpTimer(); + } +# endif module = Py_InitModule3("_lsprof", moduleMethods, "Fast profiler"); if (module == NULL) return; @@ -882,6 +993,7 @@ (PyObject*) &StatsEntryType); PyModule_AddObject(module, "profiler_subentry", (PyObject*) &StatsSubEntryType); - empty_tuple = PyTuple_New(0); + if (!empty_tuple) + empty_tuple = PyTuple_New(0); initialized = 1; }