I don't know, we really haven't decided. Stackless is still under active development. I have a few patches and stuff waiting to go in. Unlike vanilla Python, we are still adding stuff :)
For what it's worth, these are changes to the "stackless" module. I do think that we can keep the "python" part of it frozen. These "stackless" changes will also be merged into the maint branches eventually (or those that are being maintained). K > -----Original Message----- > From: [email protected] [mailto:stackless- > [email protected]] On Behalf Of Richard Tew > Sent: 16. ágúst 2010 00:24 > To: [email protected] > Subject: [Stackless] Fwd: [Stackless-checkins] r84071 - > stackless/trunk/Modules/_lsprof.c > > 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 _______________________________________________ Stackless mailing list [email protected] http://www.stackless.com/mailman/listinfo/stackless
