PageRenderTime 966ms CodeModel.GetById 213ms app.highlight 468ms RepoModel.GetById 186ms app.codeStats 0ms

/Modules/_lsprof.c

http://unladen-swallow.googlecode.com/
C | 905 lines | 773 code | 85 blank | 47 comment | 119 complexity | 7b4fab24e75dfcf80aa92a450d9cb354 MD5 | raw file
  1#include "Python.h"
  2#include "compile.h"
  3#include "frameobject.h"
  4#include "structseq.h"
  5#include "rotatingtree.h"
  6
  7#if !defined(HAVE_LONG_LONG)
  8#error "This module requires long longs!"
  9#endif
 10
 11/*** Selection of a high-precision timer ***/
 12
 13#ifdef MS_WINDOWS
 14
 15#include <windows.h>
 16
 17static PY_LONG_LONG
 18hpTimer(void)
 19{
 20	LARGE_INTEGER li;
 21	QueryPerformanceCounter(&li);
 22	return li.QuadPart;
 23}
 24
 25static double
 26hpTimerUnit(void)
 27{
 28	LARGE_INTEGER li;
 29	if (QueryPerformanceFrequency(&li))
 30		return 1.0 / li.QuadPart;
 31	else
 32		return 0.000001;  /* unlikely */
 33}
 34
 35#else  /* !MS_WINDOWS */
 36
 37#ifndef HAVE_GETTIMEOFDAY
 38#error "This module requires gettimeofday() on non-Windows platforms!"
 39#endif
 40
 41#if (defined(PYOS_OS2) && defined(PYCC_GCC))
 42#include <sys/time.h>
 43#else
 44#include <sys/resource.h>
 45#include <sys/times.h>
 46#endif
 47
 48static PY_LONG_LONG
 49hpTimer(void)
 50{
 51	struct timeval tv;
 52	PY_LONG_LONG ret;
 53#ifdef GETTIMEOFDAY_NO_TZ
 54	gettimeofday(&tv);
 55#else
 56	gettimeofday(&tv, (struct timezone *)NULL);
 57#endif
 58	ret = tv.tv_sec;
 59	ret = ret * 1000000 + tv.tv_usec;
 60	return ret;
 61}
 62
 63static double
 64hpTimerUnit(void)
 65{
 66	return 0.000001;
 67}
 68
 69#endif  /* MS_WINDOWS */
 70
 71/************************************************************/
 72/* Written by Brett Rosen and Ted Czotter */
 73
 74struct _ProfilerEntry;
 75
 76/* represents a function called from another function */
 77typedef struct _ProfilerSubEntry {
 78	rotating_node_t header;
 79	PY_LONG_LONG tt;
 80	PY_LONG_LONG it;
 81	long callcount;
 82	long recursivecallcount;
 83	long recursionLevel;
 84} ProfilerSubEntry;
 85
 86/* represents a function or user defined block */
 87typedef struct _ProfilerEntry {
 88	rotating_node_t header;
 89	PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */
 90	PY_LONG_LONG tt; /* total time in this entry */
 91	PY_LONG_LONG it; /* inline time in this entry (not in subcalls) */
 92	long callcount; /* how many times this was called */
 93	long recursivecallcount; /* how many times called recursively */
 94	long recursionLevel;
 95	rotating_node_t *calls;
 96} ProfilerEntry;
 97
 98typedef struct _ProfilerContext {
 99	PY_LONG_LONG t0;
100	PY_LONG_LONG subt;
101	struct _ProfilerContext *previous;
102	ProfilerEntry *ctxEntry;
103} ProfilerContext;
104
105typedef struct {
106	PyObject_HEAD
107	rotating_node_t *profilerEntries;
108	ProfilerContext *currentProfilerContext;
109	ProfilerContext *freelistProfilerContext;
110	int flags;
111	PyObject *externalTimer;
112	double externalTimerUnit;
113} ProfilerObject;
114
115#define POF_ENABLED     0x001
116#define POF_SUBCALLS    0x002
117#define POF_BUILTINS    0x004
118#define POF_NOMEMORY    0x100
119
120staticforward PyTypeObject PyProfiler_Type;
121
122#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type)
123#define PyProfiler_CheckExact(op) (Py_TYPE(op) == &PyProfiler_Type)
124
125/*** External Timers ***/
126
127#define DOUBLE_TIMER_PRECISION   4294967296.0
128static PyObject *empty_tuple;
129
130static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj)
131{
132	PY_LONG_LONG result;
133	PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL);
134	if (o == NULL) {
135		PyErr_WriteUnraisable(pObj->externalTimer);
136		return 0;
137	}
138	if (pObj->externalTimerUnit > 0.0) {
139		/* interpret the result as an integer that will be scaled
140		   in profiler_getstats() */
141		result = PyLong_AsLongLong(o);
142	}
143	else {
144		/* interpret the result as a double measured in seconds.
145		   As the profiler works with PY_LONG_LONG internally
146		   we convert it to a large integer */
147		double val = PyFloat_AsDouble(o);
148		/* error handling delayed to the code below */
149		result = (PY_LONG_LONG) (val * DOUBLE_TIMER_PRECISION);
150	}
151	Py_DECREF(o);
152	if (PyErr_Occurred()) {
153		PyErr_WriteUnraisable(pObj->externalTimer);
154		return 0;
155	}
156	return result;
157}
158
159#define CALL_TIMER(pObj)	((pObj)->externalTimer ?		\
160					CallExternalTimer(pObj) :	\
161					hpTimer())
162
163/*** ProfilerObject ***/
164
165static PyObject *
166normalizeUserObj(PyObject *obj)
167{
168	/* Replace built-in function objects with a descriptive string
169	   because of built-in methods -- keeping a reference to
170	   __self__ is probably not a good idea. */
171	PyCFunctionObject *fn = (PyCFunctionObject *)obj;
172
173	if (PyCFunction_Check(obj) && fn->m_self == NULL) {
174		/* built-in function: look up the module name */
175		PyObject *mod = fn->m_module;
176		char *modname;
177		if (mod && PyString_Check(mod)) {
178			modname = PyString_AS_STRING(mod);
179		}
180		else if (mod && PyModule_Check(mod)) {
181			modname = PyModule_GetName(mod);
182			if (modname == NULL) {
183				PyErr_Clear();
184				modname = "__builtin__";
185			}
186		}
187		else {
188			modname = "__builtin__";
189		}
190		if (strcmp(modname, "__builtin__") != 0)
191			return PyString_FromFormat("<%s.%s>",
192						   modname,
193						   fn->m_ml->ml_name);
194		else
195			return PyString_FromFormat("<%s>",
196						   fn->m_ml->ml_name);
197	}
198	else if (PyCFunction_Check(obj) || PyMethodDescr_Check(obj)) {
199		/* built-in method: try to return
200			repr(getattr(type(__self__), __name__))
201		*/
202		PyTypeObject *type;
203		const char *name;
204		PyObject *name_obj;
205		if (PyCFunction_Check(obj)) {
206			type = Py_TYPE(fn->m_self);
207			name = fn->m_ml->ml_name;
208		}
209		else {
210			PyMethodDescrObject *descr = (PyMethodDescrObject *)obj;
211			type = descr->d_type;
212			name = descr->d_method->ml_name;
213		}
214		name_obj = PyString_FromString(name);
215		if (name_obj != NULL) {
216			PyObject *mo = _PyType_Lookup(type, name_obj);
217			Py_XINCREF(mo);
218			Py_DECREF(name_obj);
219			if (mo != NULL) {
220				PyObject *res = PyObject_Repr(mo);
221				Py_DECREF(mo);
222				if (res != NULL)
223					return res;
224			}
225		}
226		PyErr_Clear();
227		return PyString_FromFormat("<built-in method %s>", name);
228	}
229	else {
230		Py_INCREF(obj);
231		return obj;
232	}
233}
234
235static ProfilerEntry*
236newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj)
237{
238	ProfilerEntry *self;
239	self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry));
240	if (self == NULL) {
241		pObj->flags |= POF_NOMEMORY;
242		return NULL;
243	}
244	userObj = normalizeUserObj(userObj);
245	if (userObj == NULL) {
246		PyErr_Clear();
247		free(self);
248		pObj->flags |= POF_NOMEMORY;
249		return NULL;
250	}
251	self->header.key = key;
252	self->userObj = userObj;
253	self->tt = 0;
254	self->it = 0;
255	self->callcount = 0;
256	self->recursivecallcount = 0;
257	self->recursionLevel = 0;
258	self->calls = EMPTY_ROTATING_TREE;
259	RotatingTree_Add(&pObj->profilerEntries, &self->header);
260	return self;
261}
262
263static ProfilerEntry*
264getEntry(ProfilerObject *pObj, void *key)
265{
266	return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key);
267}
268
269static ProfilerSubEntry * 
270getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry)
271{
272	return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls,
273						    (void *)entry);
274}
275
276static ProfilerSubEntry *
277newSubEntry(ProfilerObject *pObj,  ProfilerEntry *caller, ProfilerEntry* entry)
278{
279	ProfilerSubEntry *self;
280	self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry));
281	if (self == NULL) {
282		pObj->flags |= POF_NOMEMORY;
283		return NULL;
284	}
285	self->header.key = (void *)entry;
286	self->tt = 0;
287	self->it = 0;
288	self->callcount = 0;
289	self->recursivecallcount = 0;
290	self->recursionLevel = 0;
291	RotatingTree_Add(&caller->calls, &self->header);
292	return self;
293}
294
295static int freeSubEntry(rotating_node_t *header, void *arg)
296{
297	ProfilerSubEntry *subentry = (ProfilerSubEntry*) header;
298	free(subentry);
299	return 0;
300}
301
302static int freeEntry(rotating_node_t *header, void *arg)
303{
304	ProfilerEntry *entry = (ProfilerEntry*) header;
305	RotatingTree_Enum(entry->calls, freeSubEntry, NULL);
306	Py_DECREF(entry->userObj);
307	free(entry);
308	return 0;
309}
310
311static void clearEntries(ProfilerObject *pObj)
312{
313	RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL);
314	pObj->profilerEntries = EMPTY_ROTATING_TREE;
315	/* release the memory hold by the free list of ProfilerContexts */
316	while (pObj->freelistProfilerContext) {
317		ProfilerContext *c = pObj->freelistProfilerContext;
318		pObj->freelistProfilerContext = c->previous;
319		free(c);
320	}
321}
322
323static void
324initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
325{
326	self->ctxEntry = entry;
327	self->subt = 0;
328	self->previous = pObj->currentProfilerContext;
329	pObj->currentProfilerContext = self;
330	++entry->recursionLevel;
331	if ((pObj->flags & POF_SUBCALLS) && self->previous) {
332		/* find or create an entry for me in my caller's entry */
333		ProfilerEntry *caller = self->previous->ctxEntry;
334		ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
335		if (subentry == NULL)
336			subentry = newSubEntry(pObj, caller, entry);
337		if (subentry)
338			++subentry->recursionLevel;
339	}
340	self->t0 = CALL_TIMER(pObj);
341}
342
343static void
344Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
345{
346	PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0;
347	PY_LONG_LONG it = tt - self->subt;
348	if (self->previous)
349		self->previous->subt += tt;
350	pObj->currentProfilerContext = self->previous;
351	if (--entry->recursionLevel == 0)
352		entry->tt += tt;
353	else
354		++entry->recursivecallcount;
355	entry->it += it;
356	entry->callcount++;
357	if ((pObj->flags & POF_SUBCALLS) && self->previous) {
358		/* find or create an entry for me in my caller's entry */
359		ProfilerEntry *caller = self->previous->ctxEntry;
360		ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry);
361		if (subentry) {
362			if (--subentry->recursionLevel == 0)
363				subentry->tt += tt;
364			else
365				++subentry->recursivecallcount;
366			subentry->it += it;
367			++subentry->callcount;
368		}
369	}
370}
371
372static void
373ptrace_enter_call(PyObject *self, void *key, PyObject *userObj)
374{
375	/* entering a call to the function identified by 'key'
376	   (which can be a PyCodeObject or a PyMethodDef pointer) */
377	ProfilerObject *pObj = (ProfilerObject*)self;
378	ProfilerEntry *profEntry;
379	ProfilerContext *pContext;
380
381	/* In the case of entering a generator expression frame via a
382	 * throw (gen_send_ex(.., 1)), we may already have an
383	 * Exception set here. We must not mess around with this
384	 * exception, and some of the code under here assumes that
385	 * PyErr_* is its own to mess around with, so we have to
386	 * save and restore any current exception. */
387	PyObject *last_type, *last_value, *last_tb;
388	PyErr_Fetch(&last_type, &last_value, &last_tb);
389
390	profEntry = getEntry(pObj, key);
391	if (profEntry == NULL) {
392		profEntry = newProfilerEntry(pObj, key, userObj);
393		if (profEntry == NULL)
394			goto restorePyerr;
395	}
396	/* grab a ProfilerContext out of the free list */
397	pContext = pObj->freelistProfilerContext;
398	if (pContext) {
399		pObj->freelistProfilerContext = pContext->previous;
400	}
401	else {
402		/* free list exhausted, allocate a new one */
403		pContext = (ProfilerContext*)
404			malloc(sizeof(ProfilerContext));
405		if (pContext == NULL) {
406			pObj->flags |= POF_NOMEMORY;
407			goto restorePyerr;
408		}
409	}
410	initContext(pObj, pContext, profEntry);
411
412restorePyerr:
413	PyErr_Restore(last_type, last_value, last_tb);
414}
415
416static void
417ptrace_leave_call(PyObject *self, void *key)
418{
419	/* leaving a call to the function identified by 'key' */
420	ProfilerObject *pObj = (ProfilerObject*)self;
421	ProfilerEntry *profEntry;
422	ProfilerContext *pContext;
423
424	pContext = pObj->currentProfilerContext;
425	if (pContext == NULL)
426		return;
427	profEntry = getEntry(pObj, key);
428	if (profEntry) {
429		Stop(pObj, pContext, profEntry);
430	}
431	else {
432		pObj->currentProfilerContext = pContext->previous;
433	}
434	/* put pContext into the free list */
435	pContext->previous = pObj->freelistProfilerContext;
436	pObj->freelistProfilerContext = pContext;
437}
438
439static int
440profiler_callback(PyObject *self, PyFrameObject *frame, int what,
441		  PyObject *arg)
442{
443	switch (what) {
444
445	/* the 'frame' of a called function is about to start its execution */
446	case PyTrace_CALL:
447		ptrace_enter_call(self, (void *)frame->f_code,
448				        (PyObject *)frame->f_code);
449		break;
450
451	/* the 'frame' of a called function is about to finish
452	   (either normally or with an exception) */
453	case PyTrace_RETURN:
454		ptrace_leave_call(self, (void *)frame->f_code);
455		break;
456
457	/* case PyTrace_EXCEPTION:
458		If the exception results in the function exiting, a
459		PyTrace_RETURN event will be generated, so we don't need to
460		handle it. */
461
462#ifdef PyTrace_C_CALL	/* not defined in Python <= 2.3 */
463	/* the Python function 'frame' is issuing a call to the built-in
464	   function 'arg' */
465	case PyTrace_C_CALL:
466		if (((ProfilerObject *)self)->flags & POF_BUILTINS) {
467			PyMethodDef *ml = NULL;
468			if (PyCFunction_Check(arg)) {
469				ml = ((PyCFunctionObject *)arg)->m_ml;
470			}
471			else if (PyMethodDescr_Check(arg)) {
472				ml = ((PyMethodDescrObject*)arg)->d_method;
473			}
474			ptrace_enter_call(self, ml, arg);
475		}
476		break;
477
478	/* the call to the built-in function 'arg' is returning into its
479	   caller 'frame' */
480	case PyTrace_C_RETURN:		/* ...normally */
481	case PyTrace_C_EXCEPTION:	/* ...with an exception set */
482		if (((ProfilerObject *)self)->flags & POF_BUILTINS) {
483			PyMethodDef *ml = NULL;
484			if (PyCFunction_Check(arg)) {
485				ml = ((PyCFunctionObject *)arg)->m_ml;
486			}
487			else if (PyMethodDescr_Check(arg)) {
488				ml = ((PyMethodDescrObject*)arg)->d_method;
489			}
490			ptrace_leave_call(self, ml);
491		}
492		break;
493#endif
494
495	default:
496		break;
497	}
498	return 0;
499}
500
501static int
502pending_exception(ProfilerObject *pObj)
503{
504	if (pObj->flags & POF_NOMEMORY) {
505		pObj->flags -= POF_NOMEMORY;
506		PyErr_SetString(PyExc_MemoryError,
507				"memory was exhausted while profiling");
508		return -1;
509	}
510	return 0;
511}
512
513/************************************************************/
514
515static PyStructSequence_Field profiler_entry_fields[] = {
516	{"code",         "code object or built-in function name"},
517	{"callcount",    "how many times this was called"},
518	{"reccallcount", "how many times called recursively"},
519	{"totaltime",    "total time in this entry"},
520	{"inlinetime",   "inline time in this entry (not in subcalls)"},
521	{"calls",        "details of the calls"},
522	{0}
523};
524
525static PyStructSequence_Field profiler_subentry_fields[] = {
526	{"code",         "called code object or built-in function name"},
527	{"callcount",    "how many times this is called"},
528	{"reccallcount", "how many times this is called recursively"},
529	{"totaltime",    "total time spent in this call"},
530	{"inlinetime",   "inline time (not in further subcalls)"},
531	{0}
532};
533
534static PyStructSequence_Desc profiler_entry_desc = {
535	"_lsprof.profiler_entry", /* name */
536	NULL, /* doc */
537	profiler_entry_fields,
538	6
539};
540
541static PyStructSequence_Desc profiler_subentry_desc = {
542	"_lsprof.profiler_subentry", /* name */
543	NULL, /* doc */
544	profiler_subentry_fields,
545	5
546};
547
548static int initialized;
549static PyTypeObject StatsEntryType;
550static PyTypeObject StatsSubEntryType;
551
552
553typedef struct {
554	PyObject *list;
555	PyObject *sublist;
556	double factor;
557} statscollector_t;
558
559static int statsForSubEntry(rotating_node_t *node, void *arg)
560{
561	ProfilerSubEntry *sentry = (ProfilerSubEntry*) node;
562	statscollector_t *collect = (statscollector_t*) arg;
563	ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key;
564	int err;
565	PyObject *sinfo;
566	sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType,
567				      "((Olldd))",
568				      entry->userObj,
569				      sentry->callcount,
570				      sentry->recursivecallcount,
571				      collect->factor * sentry->tt,
572				      collect->factor * sentry->it);
573	if (sinfo == NULL)
574		return -1;
575	err = PyList_Append(collect->sublist, sinfo);
576	Py_DECREF(sinfo);
577	return err;
578}
579
580static int statsForEntry(rotating_node_t *node, void *arg)
581{
582	ProfilerEntry *entry = (ProfilerEntry*) node;
583	statscollector_t *collect = (statscollector_t*) arg;
584	PyObject *info;
585	int err;
586	if (entry->callcount == 0)
587		return 0;   /* skip */
588
589	if (entry->calls != EMPTY_ROTATING_TREE) {
590		collect->sublist = PyList_New(0);
591		if (collect->sublist == NULL)
592			return -1;
593		if (RotatingTree_Enum(entry->calls,
594				      statsForSubEntry, collect) != 0) {
595			Py_DECREF(collect->sublist);
596			return -1;
597		}
598	}
599	else {
600		Py_INCREF(Py_None);
601		collect->sublist = Py_None;
602	}
603
604	info = PyObject_CallFunction((PyObject*) &StatsEntryType,
605				     "((OllddO))",
606				     entry->userObj,
607				     entry->callcount,
608				     entry->recursivecallcount,
609				     collect->factor * entry->tt,
610				     collect->factor * entry->it,
611				     collect->sublist);
612	Py_DECREF(collect->sublist);
613	if (info == NULL)
614		return -1;
615	err = PyList_Append(collect->list, info);
616	Py_DECREF(info);
617	return err;
618}
619
620PyDoc_STRVAR(getstats_doc, "\
621getstats() -> list of profiler_entry objects\n\
622\n\
623Return all information collected by the profiler.\n\
624Each profiler_entry is a tuple-like object with the\n\
625following attributes:\n\
626\n\
627    code          code object\n\
628    callcount     how many times this was called\n\
629    reccallcount  how many times called recursively\n\
630    totaltime     total time in this entry\n\
631    inlinetime    inline time in this entry (not in subcalls)\n\
632    calls         details of the calls\n\
633\n\
634The calls attribute is either None or a list of\n\
635profiler_subentry objects:\n\
636\n\
637    code          called code object\n\
638    callcount     how many times this is called\n\
639    reccallcount  how many times this is called recursively\n\
640    totaltime     total time spent in this call\n\
641    inlinetime    inline time (not in further subcalls)\n\
642");
643
644static PyObject*
645profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
646{
647	statscollector_t collect;
648	if (pending_exception(pObj))
649		return NULL;
650	if (!pObj->externalTimer)
651		collect.factor = hpTimerUnit();
652	else if (pObj->externalTimerUnit > 0.0)
653		collect.factor = pObj->externalTimerUnit;
654	else
655		collect.factor = 1.0 / DOUBLE_TIMER_PRECISION;
656	collect.list = PyList_New(0);
657	if (collect.list == NULL)
658		return NULL;
659	if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect)
660	    != 0) {
661		Py_DECREF(collect.list);
662		return NULL;
663	}
664	return collect.list;
665}
666
667static int
668setSubcalls(ProfilerObject *pObj, int nvalue)
669{
670	if (nvalue == 0)
671		pObj->flags &= ~POF_SUBCALLS;
672	else if (nvalue > 0)
673		pObj->flags |=  POF_SUBCALLS;
674	return 0;
675}
676
677static int
678setBuiltins(ProfilerObject *pObj, int nvalue)
679{
680	if (nvalue == 0)
681		pObj->flags &= ~POF_BUILTINS;
682	else if (nvalue > 0) {
683#ifndef PyTrace_C_CALL
684		PyErr_SetString(PyExc_ValueError,
685				"builtins=True requires Python >= 2.4");
686		return -1;
687#else
688		pObj->flags |=  POF_BUILTINS;
689#endif
690	}
691	return 0;
692}
693
694PyDoc_STRVAR(enable_doc, "\
695enable(subcalls=True, builtins=True)\n\
696\n\
697Start collecting profiling information.\n\
698If 'subcalls' is True, also records for each function\n\
699statistics separated according to its current caller.\n\
700If 'builtins' is True, records the time spent in\n\
701built-in functions separately from their caller.\n\
702");
703
704static PyObject*
705profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds)
706{
707	int subcalls = -1;
708        int builtins = -1;
709	static char *kwlist[] = {"subcalls", "builtins", 0};
710	if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
711					 kwlist, &subcalls, &builtins))
712		return NULL;
713	if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
714		return NULL;
715	PyEval_SetProfile(profiler_callback, (PyObject*)self);
716	self->flags |= POF_ENABLED;
717	Py_INCREF(Py_None);
718	return Py_None;
719}
720
721static void
722flush_unmatched(ProfilerObject *pObj)
723{
724	while (pObj->currentProfilerContext) {
725		ProfilerContext *pContext = pObj->currentProfilerContext;
726		ProfilerEntry *profEntry= pContext->ctxEntry;
727		if (profEntry)
728			Stop(pObj, pContext, profEntry);
729		else
730			pObj->currentProfilerContext = pContext->previous;
731		if (pContext)
732			free(pContext);
733	}
734
735}
736
737PyDoc_STRVAR(disable_doc, "\
738disable()\n\
739\n\
740Stop collecting profiling information.\n\
741");
742
743static PyObject*
744profiler_disable(ProfilerObject *self, PyObject* noarg)
745{
746	self->flags &= ~POF_ENABLED;
747	PyEval_SetProfile(NULL, NULL);
748	flush_unmatched(self);
749	if (pending_exception(self))
750		return NULL;
751	Py_INCREF(Py_None);
752	return Py_None;
753}
754
755PyDoc_STRVAR(clear_doc, "\
756clear()\n\
757\n\
758Clear all profiling information collected so far.\n\
759");
760
761static PyObject*
762profiler_clear(ProfilerObject *pObj, PyObject* noarg)
763{
764	clearEntries(pObj);
765	Py_INCREF(Py_None);
766	return Py_None;
767}
768
769static void
770profiler_dealloc(ProfilerObject *op)
771{
772	if (op->flags & POF_ENABLED)
773		PyEval_SetProfile(NULL, NULL);
774	flush_unmatched(op);
775	clearEntries(op);
776	Py_XDECREF(op->externalTimer);
777	Py_TYPE(op)->tp_free(op);
778}
779
780static int
781profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw)
782{
783	PyObject *o;
784	PyObject *timer = NULL;
785	double timeunit = 0.0;
786	int subcalls = 1;
787#ifdef PyTrace_C_CALL
788	int builtins = 1;
789#else
790	int builtins = 0;
791#endif
792	static char *kwlist[] = {"timer", "timeunit",
793				       "subcalls", "builtins", 0};
794
795	if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist,
796					 &timer, &timeunit,
797					 &subcalls, &builtins))
798		return -1;
799
800	if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0)
801		return -1;
802	o = pObj->externalTimer;
803	pObj->externalTimer = timer;
804	Py_XINCREF(timer);
805	Py_XDECREF(o);
806	pObj->externalTimerUnit = timeunit;
807	return 0;
808}
809
810static PyMethodDef profiler_methods[] = {
811	{"getstats",    (PyCFunction)profiler_getstats,
812			METH_NOARGS,			getstats_doc},
813	{"enable",	(PyCFunction)profiler_enable,
814			METH_VARARGS | METH_KEYWORDS,	enable_doc},
815	{"disable",	(PyCFunction)profiler_disable,
816			METH_NOARGS,			disable_doc},
817	{"clear",	(PyCFunction)profiler_clear,
818			METH_NOARGS,			clear_doc},
819	{NULL, NULL}
820};
821
822PyDoc_STRVAR(profiler_doc, "\
823Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\
824\n\
825    Builds a profiler object using the specified timer function.\n\
826    The default timer is a fast built-in one based on real time.\n\
827    For custom timer functions returning integers, time_unit can\n\
828    be a float specifying a scale (i.e. how long each integer unit\n\
829    is, in seconds).\n\
830");
831
832statichere PyTypeObject PyProfiler_Type = {
833	PyObject_HEAD_INIT(NULL)
834	0,                                      /* ob_size */
835	"_lsprof.Profiler",                     /* tp_name */
836	sizeof(ProfilerObject),                 /* tp_basicsize */
837	0,                                      /* tp_itemsize */
838	(destructor)profiler_dealloc,           /* tp_dealloc */
839	0,                                      /* tp_print */
840	0,                                      /* tp_getattr */
841	0,                                      /* tp_setattr */
842	0,                                      /* tp_compare */
843	0,                                      /* tp_repr */
844	0,                                      /* tp_as_number */
845	0,                                      /* tp_as_sequence */
846	0,                                      /* tp_as_mapping */
847	0,                                      /* tp_hash */
848	0,                                      /* tp_call */
849	0,                                      /* tp_str */
850	0,                                      /* tp_getattro */
851	0,                                      /* tp_setattro */
852	0,                                      /* tp_as_buffer */
853	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
854	profiler_doc,                           /* tp_doc */
855	0,                                      /* tp_traverse */
856	0,                                      /* tp_clear */
857	0,                                      /* tp_richcompare */
858	0,                                      /* tp_weaklistoffset */
859	0,                                      /* tp_iter */
860	0,                                      /* tp_iternext */
861	profiler_methods,                       /* tp_methods */
862	0,                                      /* tp_members */
863	0,                                      /* tp_getset */
864	0,                                      /* tp_base */
865	0,                                      /* tp_dict */
866	0,                                      /* tp_descr_get */
867	0,                                      /* tp_descr_set */
868	0,                                      /* tp_dictoffset */
869	(initproc)profiler_init,                /* tp_init */
870	PyType_GenericAlloc,                    /* tp_alloc */
871	PyType_GenericNew,                      /* tp_new */
872	PyObject_Del,                           /* tp_free */
873};
874
875static PyMethodDef moduleMethods[] = {
876	{NULL, NULL}
877};
878
879PyMODINIT_FUNC
880init_lsprof(void)
881{
882	PyObject *module, *d;
883	module = Py_InitModule3("_lsprof", moduleMethods, "Fast profiler");
884	if (module == NULL)
885		return;
886	d = PyModule_GetDict(module);
887	if (PyType_Ready(&PyProfiler_Type) < 0)
888		return;
889	PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type);
890
891	if (!initialized) {
892		PyStructSequence_InitType(&StatsEntryType, 
893					  &profiler_entry_desc);
894		PyStructSequence_InitType(&StatsSubEntryType, 
895					  &profiler_subentry_desc);
896	}
897	Py_INCREF((PyObject*) &StatsEntryType);
898	Py_INCREF((PyObject*) &StatsSubEntryType);
899	PyModule_AddObject(module, "profiler_entry",
900			   (PyObject*) &StatsEntryType);
901	PyModule_AddObject(module, "profiler_subentry",
902			   (PyObject*) &StatsSubEntryType);
903	empty_tuple = PyTuple_New(0);
904	initialized = 1;
905}