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