symbian-qemu-0.9.1-12/python-2.6.1/Modules/_lsprof.c
changeset 1 2fb8b9db1c86
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symbian-qemu-0.9.1-12/python-2.6.1/Modules/_lsprof.c	Fri Jul 31 15:01:17 2009 +0100
@@ -0,0 +1,887 @@
+#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_LONG
+hpTimer(void)
+{
+	LARGE_INTEGER li;
+	QueryPerformanceCounter(&li);
+	return li.QuadPart;
+}
+
+static double
+hpTimerUnit(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_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;
+}
+
+#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) (Py_TYPE(op) == &PyProfiler_Type)
+
+/*** External Timers ***/
+
+#define DOUBLE_TIMER_PRECISION   4294967296.0
+static 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(pObj->externalTimer);
+		return 0;
+	}
+	return result;
+}
+
+#define CALL_TIMER(pObj)	((pObj)->externalTimer ?		\
+					CallExternalTimer(pObj) :	\
+					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(Py_TYPE(self), 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 void
+initContext(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 void
+Stop(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 void
+ptrace_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;
+
+	/* In the case of entering a generator expression frame via a
+	 * throw (gen_send_ex(.., 1)), we may already have an
+	 * Exception set here. We must not mess around with this
+	 * exception, and some of the code under here assumes that
+	 * PyErr_* is its own to mess around with, so we have to
+	 * save and restore any current exception. */
+	PyObject *last_type, *last_value, *last_tb;
+	PyErr_Fetch(&last_type, &last_value, &last_tb);
+
+	profEntry = getEntry(pObj, key);
+	if (profEntry == NULL) {
+		profEntry = newProfilerEntry(pObj, key, userObj);
+		if (profEntry == NULL)
+			goto restorePyerr;
+	}
+	/* 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;
+			goto restorePyerr;
+		}
+	}
+	initContext(pObj, pContext, profEntry);
+
+restorePyerr:
+	PyErr_Restore(last_type, last_value, last_tb);
+}
+
+static void
+ptrace_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 int
+profiler_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 int
+pending_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"},
+	{"callcount",    "how many times this is called"},
+	{"reccallcount", "how many times this is called recursively"},
+	{"totaltime",    "total time spent in this call"},
+	{"inlinetime",   "inline time (not in further subcalls)"},
+	{0}
+};
+
+static PyStructSequence_Desc profiler_entry_desc = {
+	"_lsprof.profiler_entry", /* name */
+	NULL, /* doc */
+	profiler_entry_fields,
+	6
+};
+
+static PyStructSequence_Desc profiler_subentry_desc = {
+	"_lsprof.profiler_subentry", /* name */
+	NULL, /* doc */
+	profiler_subentry_fields,
+	5
+};
+
+static int initialized;
+static PyTypeObject StatsEntryType;
+static PyTypeObject StatsSubEntryType;
+
+
+typedef struct {
+	PyObject *list;
+	PyObject *sublist;
+	double factor;
+} statscollector_t;
+
+static int statsForSubEntry(rotating_node_t *node, void *arg)
+{
+	ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
+	statscollector_t *collect = (statscollector_t*) arg;
+	ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
+	int err;
+	PyObject *sinfo;
+	sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
+				      "((Olldd))",
+				      entry->userObj,
+				      sentry->callcount,
+				      sentry->recursivecallcount,
+				      collect->factor * sentry->tt,
+				      collect->factor * sentry->it);
+	if (sinfo == NULL)
+		return -1;
+	err = PyList_Append(collect->sublist, sinfo);
+	Py_DECREF(sinfo);
+	return err;
+}
+
+static int statsForEntry(rotating_node_t *node, void *arg)
+{
+	ProfilerEntry *entry = (ProfilerEntry*) node;
+	statscollector_t *collect = (statscollector_t*) arg;
+	PyObject *info;
+	int err;
+	if (entry->callcount == 0)
+		return 0;   /* skip */
+
+	if (entry->calls != EMPTY_ROTATING_TREE) {
+		collect->sublist = PyList_New(0);
+		if (collect->sublist == NULL)
+			return -1;
+		if (RotatingTree_Enum(entry->calls,
+				      statsForSubEntry, collect) != 0) {
+			Py_DECREF(collect->sublist);
+			return -1;
+		}
+	}
+	else {
+		Py_INCREF(Py_None);
+		collect->sublist = Py_None;
+	}
+
+	info = PyObject_CallFunction((PyObject*) &StatsEntryType,
+				     "((OllddO))",
+				     entry->userObj,
+				     entry->callcount,
+				     entry->recursivecallcount,
+				     collect->factor * entry->tt,
+				     collect->factor * entry->it,
+				     collect->sublist);
+	Py_DECREF(collect->sublist);
+	if (info == NULL)
+		return -1;
+	err = PyList_Append(collect->list, info);
+	Py_DECREF(info);
+	return err;
+}
+
+PyDoc_STRVAR(getstats_doc, "\
+getstats() -> list of profiler_entry objects\n\
+\n\
+Return all information collected by the profiler.\n\
+Each profiler_entry is a tuple-like object with the\n\
+following attributes:\n\
+\n\
+    code          code object\n\
+    callcount     how many times this was called\n\
+    reccallcount  how many times called recursively\n\
+    totaltime     total time in this entry\n\
+    inlinetime    inline time in this entry (not in subcalls)\n\
+    calls         details of the calls\n\
+\n\
+The calls attribute is either None or a list of\n\
+profiler_subentry objects:\n\
+\n\
+    code          called code object\n\
+    callcount     how many times this is called\n\
+    reccallcount  how many times this is called recursively\n\
+    totaltime     total time spent in this call\n\
+    inlinetime    inline time (not in further subcalls)\n\
+");
+
+static PyObject*
+profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
+{
+	statscollector_t collect;
+	if (pending_exception(pObj))
+		return NULL;
+	if (!pObj->externalTimer)
+		collect.factor = hpTimerUnit();
+	else if (pObj->externalTimerUnit > 0.0)
+		collect.factor = pObj->externalTimerUnit;
+	else
+		collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
+	collect.list = PyList_New(0);
+	if (collect.list == NULL)
+		return NULL;
+	if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
+	    != 0) {
+		Py_DECREF(collect.list);
+		return NULL;
+	}
+	return collect.list;
+}
+
+static int
+setSubcalls(ProfilerObject *pObj, int nvalue)
+{
+	if (nvalue == 0)
+		pObj->flags &= ~POF_SUBCALLS;
+	else if (nvalue > 0)
+		pObj->flags |=  POF_SUBCALLS;
+	return 0;
+}
+
+static int
+setBuiltins(ProfilerObject *pObj, int nvalue)
+{
+	if (nvalue == 0)
+		pObj->flags &= ~POF_BUILTINS;
+	else if (nvalue > 0) {
+#ifndef PyTrace_C_CALL
+		PyErr_SetString(PyExc_ValueError,
+				"builtins=True requires Python >= 2.4");
+		return -1;
+#else
+		pObj->flags |=  POF_BUILTINS;
+#endif
+	}
+	return 0;
+}
+
+PyDoc_STRVAR(enable_doc, "\
+enable(subcalls=True, builtins=True)\n\
+\n\
+Start collecting profiling information.\n\
+If 'subcalls' is True, also records for each function\n\
+statistics separated according to its current caller.\n\
+If 'builtins' is True, records the time spent in\n\
+built-in functions separately from their caller.\n\
+");
+
+static PyObject*
+profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
+{
+	int subcalls = -1;
+        int builtins = -1;
+	static char *kwlist[] = {"subcalls", "builtins", 0};
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
+					 kwlist, &subcalls, &builtins))
+		return NULL;
+	if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
+		return NULL;
+	PyEval_SetProfile(profiler_callback, (PyObject*)self);
+	self->flags |= POF_ENABLED;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static void
+flush_unmatched(ProfilerObject *pObj)
+{
+	while (pObj->currentProfilerContext) {
+		ProfilerContext *pContext = pObj->currentProfilerContext;
+		ProfilerEntry *profEntry= pContext->ctxEntry;
+		if (profEntry)
+			Stop(pObj, pContext, profEntry);
+		else
+			pObj->currentProfilerContext = pContext->previous;
+		if (pContext)
+			free(pContext);
+	}
+
+}
+
+PyDoc_STRVAR(disable_doc, "\
+disable()\n\
+\n\
+Stop collecting profiling information.\n\
+");
+
+static PyObject*
+profiler_disable(ProfilerObject *self, PyObject* noarg)
+{
+	self->flags &= ~POF_ENABLED;
+	PyEval_SetProfile(NULL, NULL);
+	flush_unmatched(self);
+	if (pending_exception(self))
+		return NULL;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyDoc_STRVAR(clear_doc, "\
+clear()\n\
+\n\
+Clear all profiling information collected so far.\n\
+");
+
+static PyObject*
+profiler_clear(ProfilerObject *pObj, PyObject* noarg)
+{
+	clearEntries(pObj);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static void
+profiler_dealloc(ProfilerObject *op)
+{
+	if (op->flags & POF_ENABLED)
+		PyEval_SetProfile(NULL, NULL);
+	flush_unmatched(op);
+	clearEntries(op);
+	Py_XDECREF(op->externalTimer);
+	Py_TYPE(op)->tp_free(op);
+}
+
+static int
+profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
+{
+	PyObject *o;
+	PyObject *timer = NULL;
+	double timeunit = 0.0;
+	int subcalls = 1;
+#ifdef PyTrace_C_CALL
+	int builtins = 1;
+#else
+	int builtins = 0;
+#endif
+	static char *kwlist[] = {"timer", "timeunit",
+				       "subcalls", "builtins", 0};
+
+	if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
+					 &timer, &timeunit,
+					 &subcalls, &builtins))
+		return -1;
+
+	if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
+		return -1;
+	o = pObj->externalTimer;
+	pObj->externalTimer = timer;
+	Py_XINCREF(timer);
+	Py_XDECREF(o);
+	pObj->externalTimerUnit = timeunit;
+	return 0;
+}
+
+static PyMethodDef profiler_methods[] = {
+	{"getstats",    (PyCFunction)profiler_getstats,
+			METH_NOARGS,			getstats_doc},
+	{"enable",	(PyCFunction)profiler_enable,
+			METH_VARARGS | METH_KEYWORDS,	enable_doc},
+	{"disable",	(PyCFunction)profiler_disable,
+			METH_NOARGS,			disable_doc},
+	{"clear",	(PyCFunction)profiler_clear,
+			METH_NOARGS,			clear_doc},
+	{NULL, NULL}
+};
+
+PyDoc_STRVAR(profiler_doc, "\
+Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
+\n\
+    Builds a profiler object using the specified timer function.\n\
+    The default timer is a fast built-in one based on real time.\n\
+    For custom timer functions returning integers, time_unit can\n\
+    be a float specifying a scale (i.e. how long each integer unit\n\
+    is, in seconds).\n\
+");
+
+statichere PyTypeObject PyProfiler_Type = {
+	PyObject_HEAD_INIT(NULL)
+	0,                                      /* ob_size */
+	"_lsprof.Profiler",                     /* tp_name */
+	sizeof(ProfilerObject),                 /* tp_basicsize */
+	0,                                      /* tp_itemsize */
+	(destructor)profiler_dealloc,           /* tp_dealloc */
+	0,                                      /* tp_print */
+	0,                                      /* tp_getattr */
+	0,                                      /* tp_setattr */
+	0,                                      /* tp_compare */
+	0,                                      /* tp_repr */
+	0,                                      /* tp_as_number */
+	0,                                      /* tp_as_sequence */
+	0,                                      /* tp_as_mapping */
+	0,                                      /* tp_hash */
+	0,                                      /* tp_call */
+	0,                                      /* tp_str */
+	0,                                      /* tp_getattro */
+	0,                                      /* tp_setattro */
+	0,                                      /* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+	profiler_doc,                           /* tp_doc */
+	0,                                      /* tp_traverse */
+	0,                                      /* tp_clear */
+	0,                                      /* tp_richcompare */
+	0,                                      /* tp_weaklistoffset */
+	0,                                      /* tp_iter */
+	0,                                      /* tp_iternext */
+	profiler_methods,                       /* tp_methods */
+	0,                                      /* tp_members */
+	0,                                      /* tp_getset */
+	0,                                      /* tp_base */
+	0,                                      /* tp_dict */
+	0,                                      /* tp_descr_get */
+	0,                                      /* tp_descr_set */
+	0,                                      /* tp_dictoffset */
+	(initproc)profiler_init,                /* tp_init */
+	PyType_GenericAlloc,                    /* tp_alloc */
+	PyType_GenericNew,                      /* tp_new */
+	PyObject_Del,                           /* tp_free */
+};
+
+static PyMethodDef moduleMethods[] = {
+	{NULL, NULL}
+};
+
+PyMODINIT_FUNC
+init_lsprof(void)
+{
+	PyObject *module, *d;
+	module = Py_InitModule3("_lsprof", moduleMethods, "Fast profiler");
+	if (module == NULL)
+		return;
+	d = PyModule_GetDict(module);
+	if (PyType_Ready(&PyProfiler_Type) < 0)
+		return;
+	PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
+
+	if (!initialized) {
+		PyStructSequence_InitType(&StatsEntryType, 
+					  &profiler_entry_desc);
+		PyStructSequence_InitType(&StatsSubEntryType, 
+					  &profiler_subentry_desc);
+	}
+	Py_INCREF((PyObject*) &StatsEntryType);
+	Py_INCREF((PyObject*) &StatsSubEntryType);
+	PyModule_AddObject(module, "profiler_entry",
+			   (PyObject*) &StatsEntryType);
+	PyModule_AddObject(module, "profiler_subentry",
+			   (PyObject*) &StatsSubEntryType);
+	empty_tuple = PyTuple_New(0);
+	initialized = 1;
+}