879 lines · 23.0 KB · C
RawDownload
#include "Python.h"#include "compile.h"#include "frameobject.h"#include "structseq.h"#include "rotatingtree.h" #if !defined(HAVE_LONG_LONG)#error "This module requires long longs!"#endif /*** Selection of a high-precision timer ***/ #ifdef MS_WINDOWS #include <windows.h> static PY_LONG_LONGhpTimer(void){	LARGE_INTEGER li;	QueryPerformanceCounter(&li);	return li.QuadPart;} static doublehpTimerUnit(void){	LARGE_INTEGER li;	if (QueryPerformanceFrequency(&li))		return 1.0 / li.QuadPart;	else		return 0.000001;  /* unlikely */} #else  /* !MS_WINDOWS */ #ifndef HAVE_GETTIMEOFDAY#error "This module requires gettimeofday() on non-Windows platforms!"#endif #if (defined(PYOS_OS2) && defined(PYCC_GCC))#include <sys/time.h>#else#include <sys/resource.h>#include <sys/times.h>#endif static PY_LONG_LONGhpTimer(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 doublehpTimerUnit(void){	return 0.000001;} #endif  /* MS_WINDOWS */ /************************************************************//* Written by Brett Rosen and Ted Czotter */ struct _ProfilerEntry; /* represents a function called from another function */typedef struct _ProfilerSubEntry {	rotating_node_t header;	PY_LONG_LONG tt;	PY_LONG_LONG it;	long callcount;	long recursivecallcount;	long recursionLevel;} ProfilerSubEntry; /* represents a function or user defined block */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) */	long callcount; /* how many times this was called */	long recursivecallcount; /* how many times called recursively */	long recursionLevel;	rotating_node_t *calls;} ProfilerEntry; typedef struct _ProfilerContext {	PY_LONG_LONG t0;	PY_LONG_LONG subt;	struct _ProfilerContext *previous;	ProfilerEntry *ctxEntry;} ProfilerContext; typedef struct {	PyObject_HEAD	rotating_node_t *profilerEntries;	ProfilerContext *currentProfilerContext;	ProfilerContext *freelistProfilerContext;	int flags;	PyObject *externalTimer;	double externalTimerUnit;} ProfilerObject; #define POF_ENABLED     0x001#define POF_SUBCALLS    0x002#define POF_BUILTINS    0x004#define POF_NOMEMORY    0x100 staticforward PyTypeObject PyProfiler_Type; #define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)#define PyProfiler_CheckExact(op) ((op)->ob_type == &PyProfiler_Type) /*** External Timers ***/ #define DOUBLE_TIMER_PRECISION   4294967296.0static PyObject *empty_tuple; static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj){	PY_LONG_LONG result;	PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL);	if (o == NULL) {		PyErr_WriteUnraisable(pObj->externalTimer);		return 0;	}	if (pObj->externalTimerUnit > 0.0) {		/* interpret the result as an integer that will be scaled		   in profiler_getstats() */		result = PyLong_AsLongLong(o);	}	else {		/* interpret the result as a double measured in seconds.		   As the profiler works with PY_LONG_LONG 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);	}	Py_DECREF(o);	if (PyErr_Occurred()) {		PyErr_WriteUnraisable((PyObject *) pObj);		return 0;	}	return result;} static PY_LONG_LONGCALL_TIMER(ProfilerObject *pObj){	if(pObj->externalTimer)		return CallExternalTimer(pObj);	return hpTimer();} /*** ProfilerObject ***/ static PyObject *normalizeUserObj(PyObject *obj){	PyCFunctionObject *fn;	if (!PyCFunction_Check(obj)) {		Py_INCREF(obj);		return obj;	}	/* Replace built-in function objects with a descriptive string	   because of built-in methods -- keeping a reference to	   __self__ is probably not a good idea. */	fn = (PyCFunctionObject *)obj; 	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);		}		else if (mod && PyModule_Check(mod)) {			modname = PyModule_GetName(mod);			if (modname == NULL) {				PyErr_Clear();				modname = "__builtin__";			}		}		else {			modname = "__builtin__";		}		if (strcmp(modname, "__builtin__") != 0)			return PyString_FromFormat("<%s.%s>",						   modname,						   fn->m_ml->ml_name);		else			return PyString_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);		if (name != NULL) {			PyObject *mo = _PyType_Lookup(self->ob_type, name);			Py_XINCREF(mo);			Py_DECREF(name);			if (mo != NULL) {				PyObject *res = PyObject_Repr(mo);				Py_DECREF(mo);				if (res != NULL)					return res;			}		}		PyErr_Clear();		return PyString_FromFormat("<built-in method %s>",					   fn->m_ml->ml_name);	}} static ProfilerEntry*newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj){	ProfilerEntry *self;	self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry));	if (self == NULL) {		pObj->flags |= POF_NOMEMORY;		return NULL;	}	userObj = normalizeUserObj(userObj);	if (userObj == NULL) {		PyErr_Clear();		free(self);		pObj->flags |= POF_NOMEMORY;		return NULL;	}	self->header.key = key;	self->userObj = userObj;	self->tt = 0;	self->it = 0;	self->callcount = 0;	self->recursivecallcount = 0;	self->recursionLevel = 0;	self->calls = EMPTY_ROTATING_TREE;	RotatingTree_Add(&pObj->profilerEntries, &self->header);	return self;} static ProfilerEntry*getEntry(ProfilerObject *pObj, void *key){	return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);} static ProfilerSubEntry * getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry){	return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,						    (void *)entry);} static ProfilerSubEntry *newSubEntry(ProfilerObject *pObj,  ProfilerEntry *caller, ProfilerEntry* entry){	ProfilerSubEntry *self;	self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry));	if (self == NULL) {		pObj->flags |= POF_NOMEMORY;		return NULL;	}	self->header.key = (void *)entry;	self->tt = 0;	self->it = 0;	self->callcount = 0;	self->recursivecallcount = 0;	self->recursionLevel = 0;	RotatingTree_Add(&caller->calls, &self->header);	return self;} static int freeSubEntry(rotating_node_t *header, void *arg){	ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;	free(subentry);	return 0;} static int freeEntry(rotating_node_t *header, void *arg){	ProfilerEntry *entry = (ProfilerEntry*) header;	RotatingTree_Enum(entry->calls, freeSubEntry, NULL);	Py_DECREF(entry->userObj);	free(entry);	return 0;} static void clearEntries(ProfilerObject *pObj){	RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);	pObj->profilerEntries = EMPTY_ROTATING_TREE;	/* release the memory hold by the free list of ProfilerContexts */	while (pObj->freelistProfilerContext) {		ProfilerContext *c = pObj->freelistProfilerContext;		pObj->freelistProfilerContext = c->previous;		free(c);	}} static voidinitContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry){	self->ctxEntry = entry;	self->subt = 0;	self->previous = pObj->currentProfilerContext;	pObj->currentProfilerContext = self;	++entry->recursionLevel;	if ((pObj->flags & POF_SUBCALLS) && self->previous) {		/* find or create an entry for me in my caller's entry */		ProfilerEntry *caller = self->previous->ctxEntry;		ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);		if (subentry == NULL)			subentry = newSubEntry(pObj, caller, entry);		if (subentry)			++subentry->recursionLevel;	}	self->t0 = CALL_TIMER(pObj);} static voidStop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry){	PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0;	PY_LONG_LONG it = tt - self->subt;	if (self->previous)		self->previous->subt += tt;	pObj->currentProfilerContext = self->previous;	if (--entry->recursionLevel == 0)		entry->tt += tt;	else		++entry->recursivecallcount;	entry->it += it;	entry->callcount++;	if ((pObj->flags & POF_SUBCALLS) && self->previous) {		/* find or create an entry for me in my caller's entry */		ProfilerEntry *caller = self->previous->ctxEntry;		ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);		if (subentry) {			if (--subentry->recursionLevel == 0)				subentry->tt += tt;			else				++subentry->recursivecallcount;			subentry->it += it;			++subentry->callcount;		}	}} static voidptrace_enter_call(PyObject *self, void *key, PyObject *userObj){	/* entering a call to the function identified by 'key'	   (which can be a PyCodeObject or a PyMethodDef pointer) */	ProfilerObject *pObj = (ProfilerObject*)self;	ProfilerEntry *profEntry;	ProfilerContext *pContext; 	profEntry = getEntry(pObj, key);	if (profEntry == NULL) {		profEntry = newProfilerEntry(pObj, key, userObj);		if (profEntry == NULL)			return;	}	/* grab a ProfilerContext out of the free list */	pContext = pObj->freelistProfilerContext;	if (pContext) {		pObj->freelistProfilerContext = pContext->previous;	}	else {		/* free list exhausted, allocate a new one */		pContext = (ProfilerContext*)			malloc(sizeof(ProfilerContext));		if (pContext == NULL) {			pObj->flags |= POF_NOMEMORY;			return;		}	}	initContext(pObj, pContext, profEntry);} static voidptrace_leave_call(PyObject *self, void *key){	/* leaving a call to the function identified by 'key' */	ProfilerObject *pObj = (ProfilerObject*)self;	ProfilerEntry *profEntry;	ProfilerContext *pContext; 	pContext = pObj->currentProfilerContext;	if (pContext == NULL)		return;	profEntry = getEntry(pObj, key);	if (profEntry) {		Stop(pObj, pContext, profEntry);	}	else {		pObj->currentProfilerContext = pContext->previous;	}	/* put pContext into the free list */	pContext->previous = pObj->freelistProfilerContext;	pObj->freelistProfilerContext = pContext;} static intprofiler_callback(PyObject *self, PyFrameObject *frame, int what,		  PyObject *arg){	switch (what) { 	/* the 'frame' of a called function is about to start its execution */	case PyTrace_CALL:		ptrace_enter_call(self, (void *)frame->f_code,				        (PyObject *)frame->f_code);		break; 	/* the 'frame' of a called function is about to finish	   (either normally or with an exception) */	case PyTrace_RETURN:		ptrace_leave_call(self, (void *)frame->f_code);		break; 	/* case PyTrace_EXCEPTION:		If the exception results in the function exiting, a		PyTrace_RETURN event will be generated, so we don't need to		handle it. */ #ifdef PyTrace_C_CALL	/* not defined in Python <= 2.3 */	/* the Python function 'frame' is issuing a call to the built-in	   function 'arg' */	case PyTrace_C_CALL:		if ((((ProfilerObject *)self)->flags & POF_BUILTINS)		    && PyCFunction_Check(arg)) {			ptrace_enter_call(self,					  ((PyCFunctionObject *)arg)->m_ml,					  arg);		}		break; 	/* the call to the built-in function 'arg' is returning into its	   caller 'frame' */	case PyTrace_C_RETURN:		/* ...normally */	case PyTrace_C_EXCEPTION:	/* ...with an exception set */		if ((((ProfilerObject *)self)->flags & POF_BUILTINS)		    && PyCFunction_Check(arg)) {			ptrace_leave_call(self,					  ((PyCFunctionObject *)arg)->m_ml);		}		break;#endif 	default:		break;	}	return 0;} static intpending_exception(ProfilerObject *pObj){	if (pObj->flags & POF_NOMEMORY) {		pObj->flags -= POF_NOMEMORY;		PyErr_SetString(PyExc_MemoryError,				"memory was exhausted while profiling");		return -1;	}	return 0;} /************************************************************/ static PyStructSequence_Field profiler_entry_fields[] = {	{"code",         "code object or built-in function name"},	{"callcount",    "how many times this was called"},	{"reccallcount", "how many times called recursively"},	{"totaltime",    "total time in this entry"},	{"inlinetime",   "inline time in this entry (not in subcalls)"},	{"calls",        "details of the calls"},	{0}}; static PyStructSequence_Field profiler_subentry_fields[] = {	{"code",         "called code object or built-in function name"},

Lines 1–500 of 879.