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