[Stackless] Fwd: [Stackless-checkins] r84071 - stackless/trunk/Modules/_lsprof.c
Kristján Valur Jónsson
kristjan at ccpgames.com
Mon Aug 16 11:34:17 CEST 2010
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: stackless-bounces at stackless.com [mailto:stackless-
> bounces at stackless.com] On Behalf Of Richard Tew
> Sent: 16. ágúst 2010 00:24
> To: stackless at stackless.com
> 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 <python-checkins at python.org>
> Date: Mon, Aug 16, 2010 at 1:23 AM
> Subject: [Stackless-checkins] r84071 - stackless/trunk/Modules/_lsprof.c
> To: stackless-checkins at stackless.com
>
>
> 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
> Stackless-checkins at stackless.com
> http://www.stackless.com/mailman/listinfo/stackless-checkins
>
> _______________________________________________
> Stackless mailing list
> Stackless at stackless.com
> http://www.stackless.com/mailman/listinfo/stackless
More information about the Stackless
mailing list