[Stackless] tracing Stackless events

Andrew Dalke dalke at dalkescientific.com
Tue Dec 18 02:17:16 CET 2007


Here's a module which does a more complete job of detecting trace  
events in Stackless.  The module includes the hooks to send events to  
a single handler function, two example handler functions, and example  
code which uses the "verbose" handler.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: sltrace.py
Type: text/x-python-script
Size: 11583 bytes
Desc: not available
URL: <http://www.stackless.com/pipermail/stackless/attachments/20071218/35bf689f/attachment.bin>
-------------- next part --------------


Here is the example code so you can see the trace is generates


set_stackless_trace(verbose_dump)

def call_wrapper(f, args, kwargs, result_ch):
     result_ch.send(f(*args, **kwargs), )

def call(f, *args, **kwargs):
     arglist = []
     for arg in args:
         arglist.append(repr(arg))
     for k,v in kwargs.items():
         arglist.append(repr(k) + "=" + repr(v))
     tasklet_name = "%s(%s)" % (f.__name__, ", ".join(arglist))

     result_ch = stackless.channel()
     set_channel_name(result_ch, "<%s result>" % tasklet_name)

     # Use the default or -1 and the tasklet stays around
     # until the end of the run.
     result_ch.preference = 1
     named_tasklet(tasklet_name, call_wrapper)(f, args, kwargs,  
result_ch)

     return result_ch.receive()

def factorial(n):
     if n <= 1:
         return 1
     return n * call(factorial, n-1)

#print factorial(1000)
fact = factorial(4)
print "fact =", fact

stackless.schedule()

  =====================

Here is the output, showing things like all the tasklets waiting for  
a channel and the status of all of the tasklets for each schedule event.


Trace started
Create tasklet: 'factorial(3)' (6510448)
     by: 'main' (6422768) at sltrace.py:241
Receive (will block) 'main' (6422768) at sltrace.py:241
      (empty queue)
Schedule from: 'main' (6422768) at (inaccesible frame)
            to: 'factorial(3)' (6510448) at sltrace.py:241
      (no other tasklets)
Create tasklet: 'factorial(2)' (6510512)
     by: 'factorial(3)' (6510448) at sltrace.py:241
Receive (will block) 'factorial(3)' (6510448) at sltrace.py:241
      (empty queue)
Schedule from: 'factorial(3)' (6510448) at (inaccesible frame)
            to: 'factorial(2)' (6510512) at sltrace.py:241
     'main' (6422768) at sltrace.py:340 blocked on send
Create tasklet: 'factorial(1)' (6510576)
     by: 'factorial(2)' (6510512) at sltrace.py:241
Receive (will block) 'factorial(2)' (6510512) at sltrace.py:241
      (empty queue)
Schedule from: 'factorial(2)' (6510512) at (inaccesible frame)
            to: 'factorial(1)' (6510576) at sltrace.py:241
     'main' (6422768) at sltrace.py:340 blocked on send
     'factorial(3)' (6510448) at sltrace.py:340 blocked on send
Send: 1 'factorial(1)' (6510576) at sltrace.py:241
   in queue: 'factorial(2)' (6510512) at sltrace.py:340
Schedule from: 'factorial(1)' (6510576) at (unknown; dead?)
            to: 'factorial(2)' (6510512) at sltrace.py:241
     'main' (6422768) at sltrace.py:340 blocked on send
     'factorial(3)' (6510448) at sltrace.py:340 blocked on send
Tasklet exit: 'factorial(1)' (6510576)
Send: 2 'factorial(2)' (6510512) at sltrace.py:241
   in queue: 'factorial(3)' (6510448) at sltrace.py:340
Schedule from: 'factorial(2)' (6510512) at (unknown; dead?)
            to: 'factorial(3)' (6510448) at sltrace.py:241
     'main' (6422768) at sltrace.py:340 blocked on send
Tasklet exit: 'factorial(2)' (6510512)
Send: 6 'factorial(3)' (6510448) at sltrace.py:241
   in queue: 'main' (6422768) at sltrace.py:340
Schedule from: 'factorial(3)' (6510448) at (unknown; dead?)
            to: 'main' (6422768) at sltrace.py:241
      (no other tasklets)
fact = 24
Tasklet exit: 'factorial(3)' (6510448)
Trace ended


  ======

Some problems I found:
   - There's direct way to assign a "name" (or a "group") to a  
tasklet or channel.
      (I already reported this; used a weakref.WeakKeyDict as a  
workaround.)

Possible solution:  Let tasklets and channels take two optional  
instance parameters, name and group.  These are (readonly) attributes.

   - I had to synthesize a "tasklet exit" event based on weak references

Possible solution: the set_schedule_callback should get this with  
prev is not None and next is None, according to the documentation.   
Figure out why this isn't the case.

   - I had to work around a strange problem with Python function calls
       taking place during weakref dealloc notification (see the code  
with "if 0:")

Possible solution: No clue.

   - the schedule callback doesn't have a 'frame' for the 'prev' tasklet
        (I already reported this)

Possible solution: change the C code so the frame (and other  
attributes?) are set before the call, (and unset on error?)

   - I can't figure out how to get all tasklets in the system, so I  
only get
      all the ones which are "named" in my WeakKeyDict

Possible solution: tell me how to do that.  Failing that, implement a  
function which iterates over all tasklets.

   - I'm using my workaround for what I assume is a gc problem  
related to
       my weakref of the main tasklet (I already reported this)

Possible solution: No clue.  Will need to stare at C code for a while.



I also synthesize start/end events for the whole trace, but that's  
perhaps YAGNI.


Try it out.  let me know if it proves useful.  The output's somewhat  
ugly so feel free to come up with a better one.  It might be useful  
generate some HTML display with the tasklet information visualized as  
a UML-style sequence diagram, including perhaps coloring a tasklet  
uniquely based on the full stack trace of the creating tasklet and  
with mouseovers for viewing more detail information at each point.


				Andrew
				dalke at dalkescientific.com




More information about the Stackless mailing list