Shop OBEX P1 Docs P2 Docs Learn Events
Stack thoughts — Parallax Forums

Stack thoughts

CannibalRoboticsCannibalRobotics Posts: 535
edited 2011-04-15 12:13 in Propeller 1
Calculating Stack space has long been a messy and tedious process. Seems like most of the threads end up in something like "sorry, it's a SWAG at best" For a large program it's even messier.
So, I was wondering about a different angle of analysis - I may be retracing steps here because I have not really dug into the details of the Obex tools.
But, what if a very fast PASM cog that just watched the stack pointer of another cog and captured only min and max values over a period of time?
Would the pointer be an accurate assessment of usage? (ie, is a point to an address the usage of one long or possibly the base of x more.)
Would a 'stack overflow' warning be possible by looking at what has been allocated then comparing it to what the pointer monitor is seeing?
Would cog timing be a huge factor in the sampling?
Thoughts?

Comments

  • RS_JimRS_Jim Posts: 1,768
    edited 2011-04-15 05:49
    Hi,
    Try OBEX tools, stack length. Measures stack requirements of methods under development.
    RS_Jim
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-04-15 06:11
    Each SPIN COG has it's own stack-pointer. The stack-pointer is not copied to HUB-RAM, thus no other COG can watch it, at least unless you change the SPIN-interpreter.
    What could also be done is watch the stacks. You could run one COG where you register all stacks and that COG always keeps an eye on the last entry of each stack registered. Of course each stack then should have one additional LONG that should not change.
  • Dave HeinDave Hein Posts: 6,347
    edited 2011-04-15 07:52
    Pre-fill the stacks with a known value, and then check each stack starting from the end to see where the first non-matching value occurs. You could check the stacks just before your program terminates, or you can check them periodically from a convenient point in your program. Of course, you could also run a watchdog cog to constantly check the stacks.

    Here's a routine that will return the number of unused longs on the stack.
    pub CheckStack(laststackaddr, checkword) | addr
      repeat addr from laststackaddr to 0 step 4
        if long[addr] <> checkword
          quit
        result++
    
  • CannibalRoboticsCannibalRobotics Posts: 535
    edited 2011-04-15 10:21
    MagIO2 wrote: »
    Each SPIN COG has it's own stack-pointer. The stack-pointer is not copied to HUB-RAM, thus no other COG can watch it, at least unless you change the SPIN-interpreter.
    OK, this makes sense now, in re-reading the documentation I've found my confusion. The term 'StackPointer' is a bit misleading as it is really a value used to point. It's a scale of memory allocation for the 'next COG'. I was thinking of it as the actual pointer value in runtime.
    I think I'll think of it as "StackOffset"?
    Is the pointer value available within the COG SPIN environment? It's not in the SPR or readily apparent elsewhere.
  • johnfosjohnfos Posts: 59
    edited 2011-04-15 10:37
    Vapourware warning: this is something I'm working on, but don't hold your breath. It's got a long way to go yet.

    "It" is a program that will calculate stack length by static analysis of code, giving an upper bound to the actual requirement. By contrast, all the methods I've seen here use dynamic (run-time) analysis, and therefore can only give a lower bound that depends on how thoroughly you can exercise the code.

    Enemies to this kind of analysis include recursion (a killer), self-modifying code (which the Prop uses, but which would be surmountable in all the code I've looked at) and computed jumps. So even if I get this thing finished, it won't necessarily cope with all programs. Still, I'm hopeful that it would cope with a fair number.

    I'm aware that a few people have said this can't be done. However, I've done it in the past with a couple of other (simpler) micros and so far I haven't seen any insurmountable obstacles.

    If anyone else would be interested, it'd help to spur me on. Or if anyone else is working on the same idea, maybe we could cooperate.
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-04-15 11:18
    Ok .. let's start from the beginning. When you call COGNEW starting a SPIN method, a SPIN interpreter is loaded into a COG. The parameter you pass to the SPIN interpreter is a memory address where the stack of this SPIN interpreter shall start (the bottom of the stack so to say). The SPIN interpreter of course has a variable somewhere in COG RAM which IS the stack pointer pointing to the "top" of the stack.

    There is no possibility in the existing SPIN interpreter to access any COG-RAM except the SFRs and the stack pointer is no SFR.

    So, if you need this feature you have to modify the SPIN interpreter and maybe the SPIN compiler.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-04-15 11:19
    Spin doesn't use self-modifying code nor does it use computed jumps. Assembly language uses both, but doesn't use a stack at all and there's no real transfer of control between Spin and assembly. The Spin interpreter fully occupies the cog that runs it and assembly is always started in its own cog.
  • johnfosjohnfos Posts: 59
    edited 2011-04-15 12:11
    @mike:

    Thanks for that helpful comment!

    I'm in the early days of this project, currently studying the interpreter source code to determine exact stack implications of each byte code. Knowing that SPIN doesn't use self-modifying code or computed jumps is a big step forward.
  • Dave HeinDave Hein Posts: 6,347
    edited 2011-04-15 12:13
    You can get an approximate value of the stack pointer by getting the address of the last local variable. You could call a routine to check the stack pointer at that time and maintain a maximum value. It would look something like this.
    dat
    maxsp long 0
    
    pub CheckStackPointer
     if @result > maxsp
      maxsp := @result
    
    The actual value will be higher than @result due to stack usage by the Spin instructions that are executed. I would recommend using the checkword method instead. You just need to use large stacks during development, and then reduce them to a smaller size after your code is finalized.
Sign In or Register to comment.