Isn't the trunk supposed to be frozen now? :) To mirror what happens with the mainline?
---------- Forwarded message ---------- From: kristjan.jonsson <[email protected]> Date: Mon, Aug 16, 2010 at 1:23 AM Subject: [Stackless-checkins] r84071 - stackless/trunk/Modules/_lsprof.c To: [email protected] Author: kristjan.jonsson Date: Sun Aug 15 19:23:00 2010 New Revision: 84071 Log: the _lsprof.c module is now stackless aware. This allows the same cProfile.Profile() instance to be used by multiple tasklets, for whole program profiling. A patch with this new _lsprof.c has also been submitted to bug.python.org. What remains now is the ability to set tracing/profiling for all tasklets globally. Modified: stackless/trunk/Modules/_lsprof.c Modified: stackless/trunk/Modules/_lsprof.c ============================================================================== --- stackless/trunk/Modules/_lsprof.c (original) +++ stackless/trunk/Modules/_lsprof.c Sun Aug 15 19:23:00 2010 @@ -3,6 +3,9 @@ #include "frameobject.h" #include "structseq.h" #include "rotatingtree.h" +#ifdef STACKLESS +#include "stackless_api.h" +#endif #if !defined(HAVE_LONG_LONG) #error "This module requires long longs!" @@ -98,20 +101,35 @@ typedef struct _ProfilerContext { PY_LONG_LONG t0; PY_LONG_LONG subt; + PY_LONG_LONG paused; struct _ProfilerContext *previous; ProfilerEntry *ctxEntry; + char is_recursion; + char is_subcall_recursion; } ProfilerContext; +typedef struct _ProfilerStack { + rotating_node_t header; + ProfilerContext *currentProfilerContext; + PY_LONG_LONG t0; /* When did stack become non-current? */ +} ProfilerStack; + typedef struct { PyObject_HEAD + rotating_node_t *profilerStacks; rotating_node_t *profilerEntries; - ProfilerContext *currentProfilerContext; + ProfilerStack *currentProfilerStack; ProfilerContext *freelistProfilerContext; - int flags; PyObject *externalTimer; double externalTimerUnit; + PY_LONG_LONG currentTime; + int flags; + int nProfilerStacks; } ProfilerObject; +#define CURRENT_CONTEXT(pObj) \ + ((pObj)->currentProfilerStack->currentProfilerContext) + #define POF_ENABLED 0x001 #define POF_SUBCALLS 0x002 #define POF_BUILTINS 0x004 @@ -303,26 +321,61 @@ { RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL); pObj->profilerEntries = EMPTY_ROTATING_TREE; - /* release the memory hold by the ProfilerContexts */ - if (pObj->currentProfilerContext) { - free(pObj->currentProfilerContext); - pObj->currentProfilerContext = NULL; - } + /* release the memory hold by the free list of ProfilerContexts */ while (pObj->freelistProfilerContext) { ProfilerContext *c = pObj->freelistProfilerContext; pObj->freelistProfilerContext = c->previous; free(c); } - pObj->freelistProfilerContext = NULL; +} + +static void +checkRecursion(ProfilerContext *self, int nStacks, long recursionLevel, long subcallRecursionLevel) +{ + ProfilerEntry *entry = self->ctxEntry; + ProfilerContext *p; + self->is_recursion = self->is_subcall_recursion = 0; + if (subcallRecursionLevel > 1) { + ProfilerEntry *previous_entry; + if (nStacks <= 1) { + self->is_recursion = self->is_subcall_recursion = 1; + return; + } + /* possible subcall recursion (and hence recursion) on this stack. */ + previous_entry = self->previous->ctxEntry; + for(p = self->previous; p; p = p->previous) { + if (p->ctxEntry == entry) { + self->is_recursion = 1; + if (p->previous && p->previous->ctxEntry == previous_entry) { + self->is_subcall_recursion = 1; + return; + } + } + } + } + else if (recursionLevel > 1) { + if (nStacks <= 1) { + self->is_recursion = 1; + return; + } + /* possible regular recurion on this stack. Check it. */ + for(p = self->previous; p; p = p->previous) { + if (p->ctxEntry == entry) { + self->is_recursion = 1; + return; + } + } + } } static void initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry) { + long subcallRecursionLevel = 0; self->ctxEntry = entry; - self->subt = 0; - self->previous = pObj->currentProfilerContext; - pObj->currentProfilerContext = self; + self->subt = self->paused = 0; + self->previous = CURRENT_CONTEXT(pObj); + CURRENT_CONTEXT(pObj) = self; ++entry->recursionLevel; if ((pObj->flags & POF_SUBCALLS) && self->previous) { /* find or create an entry for me in my caller's entry */ @@ -331,20 +384,29 @@ if (subentry == NULL) subentry = newSubEntry(pObj, caller, entry); if (subentry) - ++subentry->recursionLevel; + subcallRecursionLevel = ++subentry->recursionLevel; } - self->t0 = CALL_TIMER(pObj); + checkRecursion(self, pObj->nProfilerStacks, entry->recursionLevel, + subcallRecursionLevel); + self->t0 = pObj->currentTime; } 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) + PY_LONG_LONG tt, it; + + tt = pObj->currentTime - self->t0; + tt -= self->paused; + it = tt - self->subt; + + if (self->previous) { self->previous->subt += tt; - pObj->currentProfilerContext = self->previous; - if (--entry->recursionLevel == 0) + self->previous->paused += self->paused; + } + CURRENT_CONTEXT(pObj) = self->previous; + --entry->recursionLevel; + if (!self->is_recursion) entry->tt += tt; else ++entry->recursivecallcount; @@ -355,7 +417,8 @@ ProfilerEntry *caller = self->previous->ctxEntry; ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry); if (subentry) { - if (--subentry->recursionLevel == 0) + --subentry->recursionLevel; + if (!self->is_subcall_recursion) subentry->tt += tt; else ++subentry->recursivecallcount; @@ -417,7 +480,7 @@ ProfilerEntry *profEntry; ProfilerContext *pContext; - pContext = pObj->currentProfilerContext; + pContext = CURRENT_CONTEXT(pObj); if (pContext == NULL) return; profEntry = getEntry(pObj, key); @@ -425,17 +488,72 @@ Stop(pObj, pContext, profEntry); } else { - pObj->currentProfilerContext = pContext->previous; + CURRENT_CONTEXT(pObj) = pContext->previous; } /* put pContext into the free list */ pContext->previous = pObj->freelistProfilerContext; pObj->freelistProfilerContext = pContext; } +static void +SelectStackByKey(ProfilerObject *pObj, void *key) +{ + ProfilerStack *old = pObj->currentProfilerStack; + ProfilerStack *stack; + + if (old) { + if (old->header.key == key) + return; + old->t0 = pObj->currentTime; + } + stack = (ProfilerStack*)RotatingTree_Get(&pObj->profilerStacks, key); + if (stack) { + if (stack->currentProfilerContext) + stack->currentProfilerContext->paused += pObj->currentTime - stack->t0; + } + else { + stack = (ProfilerStack*) malloc(sizeof(ProfilerStack)); + if (stack != NULL) { + stack->currentProfilerContext = NULL; + stack->header.key = key; + RotatingTree_Add(&pObj->profilerStacks, (rotating_node_t*)stack); + ++pObj->nProfilerStacks; + } + } + pObj->currentProfilerStack = stack; +} + +static void +SelectStack(ProfilerObject *pObj) +{ +#ifdef STACKLESS + SelectStackByKey(pObj, PyStackless_GetCurrent()); +#else + PyThreadState *tstate = PyThreadState_GET(); + SelectStackByKey(pObj, tstate); +#endif +} + static int profiler_callback(PyObject *self, PyFrameObject *frame, int what, PyObject *arg) { + ProfilerObject *pObj = (ProfilerObject*)self; + { + /* keep error state, see ptrace_enter_call above. + * We could keep this more focused, only really needed + * when calling a user time function, and initializing + * a user object + */ + PyObject *et, *ev, *tb; + PyErr_Fetch(&et, &ev, &tb); + pObj->currentTime = CALL_TIMER(pObj); + SelectStack(pObj); + PyErr_Restore(et, ev, tb); + } + if (pObj->currentProfilerStack == NULL) + return 0; + switch (what) { /* the 'frame' of a called function is about to start its execution */ @@ -708,19 +826,41 @@ static void flush_unmatched(ProfilerObject *pObj) { - while (pObj->currentProfilerContext) { - ProfilerContext *pContext = pObj->currentProfilerContext; + if (!pObj->currentProfilerStack) + return; + while (CURRENT_CONTEXT(pObj)) { + ProfilerContext *pContext = CURRENT_CONTEXT(pObj); ProfilerEntry *profEntry= pContext->ctxEntry; if (profEntry) Stop(pObj, pContext, profEntry); else - pObj->currentProfilerContext = pContext->previous; + CURRENT_CONTEXT(pObj) = pContext->previous; if (pContext) free(pContext); } } +static int +flush_unmatched_enum(rotating_node_t *n, void *arg) +{ + ProfilerStack *t = (ProfilerStack*)n; + ProfilerObject *pObj = (ProfilerObject*)arg; + pObj->currentProfilerStack = t; + flush_unmatched(pObj); + free(t); + return 0; +} + +static void +flush_unmatched_allstacks(ProfilerObject *pObj) +{ + RotatingTree_Enum(pObj->profilerStacks, &flush_unmatched_enum, pObj); + pObj->profilerStacks = EMPTY_ROTATING_TREE; + pObj->currentProfilerStack = NULL; + pObj->nProfilerStacks = 0; +} + PyDoc_STRVAR(disable_doc, "\ disable()\n\ \n\ @@ -732,6 +872,7 @@ { self->flags &= ~POF_ENABLED; PyEval_SetProfile(NULL, NULL); + SelectStack(self); flush_unmatched(self); if (pending_exception(self)) return NULL; @@ -748,6 +889,7 @@ static PyObject* profiler_clear(ProfilerObject *pObj, PyObject* noarg) { + flush_unmatched_allstacks(pObj); clearEntries(pObj); Py_INCREF(Py_None); return Py_None; @@ -758,7 +900,7 @@ { if (op->flags & POF_ENABLED) PyEval_SetProfile(NULL, NULL); - flush_unmatched(op); + flush_unmatched_allstacks(op); clearEntries(op); Py_XDECREF(op->externalTimer); Py_TYPE(op)->tp_free(op); @@ -889,4 +1031,4 @@ (PyObject*) &StatsSubEntryType); empty_tuple = PyTuple_New(0); initialized = 1; -} +} \ No newline at end of file _______________________________________________ Stackless-checkins mailing list [email protected] http://www.stackless.com/mailman/listinfo/stackless-checkins _______________________________________________ Stackless mailing list [email protected] http://www.stackless.com/mailman/listinfo/stackless
