Shop OBEX P1 Docs P2 Docs Learn Events
Understanding the results of the "Stack Length" library object... — Parallax Forums

Understanding the results of the "Stack Length" library object...

bill190bill190 Posts: 769
edited 2010-04-27 05:35 in Propeller 1
Ok, I want to get this stack length business down if I can...

For a test I'm running TestSquareWaveMethod.spin from the PE kit / Methods and Cogs Lab folder.

TestSquareWaveMethod.spin assigns a stack space of...

long swStack[noparse][[/noparse]120]

...for 3 new cogs it runs as follows...

swCog[noparse][[/noparse]0] := cognew(SquareWave(5, clkfreq/20, clkfreq/10), @swStack)
swCog[noparse][[/noparse]1] := cognew(SquareWave(6, clkfreq/100, clkfreq/5), @swStack[noparse][[/noparse]40])
swCog[noparse][[/noparse]2] := cognew(SquareWave(9, clkfreq/2000, clkfreq/500), @swStack[noparse][[/noparse]80])

So 40 longs of stack space for each new cog being run and 120 longs total stack space. OK...

Then I added the "Stack Length" object to measure how much stack space was being used. I added the following at the top of the file/object TestSquareWaveMethod.spin after the end of the CON block (where it sets the clock speed as is also needed for Stack Length)...

OBJ
· Stk·· :······ "Stack Length"····· 'Include Stack Length Object

PUB TestStack
· Stk.Init(@swStack, 120)········ 'Initialize reserved Stack space (reserved below)

· TestSquareWave··············· 'Run method below.

· waitcnt(clkfreq * 3 + cnt)·· 'Wait ample time for max stack usage
· Stk.GetLength(30, 19200)···· 'Transmit results serially out P30 at 19,200 baud

Then I click on run and compile current to load in the EEPROM.

Then I startup the Parallax Serial Terminal, select the same com port as the Propeller is on (Com 4 in my case), and 19200 baud. Then click on Enable.

Then I press the reset button on the Propeller...

(Stack Length sends the information back sooner than you can get the get the Parallax Serial Terminal up and running, so need to have this loaded into EEPROM and then reset the propeller to send the information again.)

Then I get the message on the terminal...

Stack Usage: 90

Next I commented out the last two new cogs being started up so I had this...

··· swCog[noparse][[/noparse]0] := cognew(SquareWave(5, clkfreq/20, clkfreq/10), @swStack)
'··· swCog[noparse][[/noparse]1] := cognew(SquareWave(6, clkfreq/100, clkfreq/5), @swStack[noparse][[/noparse]40])
'··· swCog[noparse][[/noparse]2] := cognew(SquareWave(9, clkfreq/2000, clkfreq/500), @swStack[noparse][[/noparse]80])

Then I loaded that into EEPROM, got the terminal up and running, then got this...

Stack Usage: 10

Next I commented out just the last one like this...

··· swCog[noparse][[/noparse]0] := cognew(SquareWave(5, clkfreq/20, clkfreq/10), @swStack)
··· swCog[noparse][[/noparse]1] := cognew(SquareWave(6, clkfreq/100, clkfreq/5), @swStack[noparse][[/noparse]40])
'··· swCog[noparse][[/noparse]2] := cognew(SquareWave(9, clkfreq/2000, clkfreq/500), @swStack[noparse][[/noparse]80])

...and I get...

Stack Usage: 50

Questions...

So I conclude that the stack usage "per cog" is 10 longs, correct?

And that the Stack Length object would only be valid while measuring the stack space used for one cog, but not multiple cogs at the same time correct?

So now the question is....

If I use Stack Length and it says my object is using 10 longs of stack space, then I would not want to declare *just* 10 longs, rather a little more to add a bit of leeway? Perhaps 12? Or what is best once you determine the actual stack space needed for an object?

Comments

  • whickerwhicker Posts: 749
    edited 2010-04-25 21:56
    I can only answer your last part:

    If you have tested every code path (different code executes depending on if a condition is true or false, or different code could run depending on the parameters passed).
    AND, if you are not going to make any more changes to the code, and you'll remember to add more stack if you ever do make a change, then you can set the stack space exactly.

    Otherwise, if you have the space, just add like 16 more bytes than what it needs. No reason to stress yourself out.
    If you have got every byte accounted for, it's a tough position to be in.

    I've never seen 100% efficient memory utilization in a commercial product. There's always something left over at the end for changes or bugfixes.

    I would think of the stack object as being very useful in terms of what order of magnitude of bytes you need: Do I need 10?, 100?, 1000? bytes for the stack?
  • bill190bill190 Posts: 769
    edited 2010-04-26 00:26
    Thank you!

    Also I've been playing around with this a bit more. It seems it actually uses 11 longs rather than 10. (Counting 0!)
  • kuronekokuroneko Posts: 3,623
    edited 2010-04-26 00:30
    bill190 said...
    And that the Stack Length object would only be valid while measuring the stack space used for one cog, but not multiple cogs at the same time correct?

    So now the question is....

    If I use Stack Length and it says my object is using 10 longs of stack space, then I would not want to declare *just* 10 longs, rather a little more to add a bit of leeway? Perhaps 12? Or what is best once you determine the actual stack space needed for an object?
    The issue here is you tell the object to monitor the stack of all three cogs. As it uses a specific fill pattern to detect stack usage it finds fragments of all 3 cogs which are spread out over 90 slots (10+30+10+30+10). Assuming an object invocation like you listed consumes the same stack no matter what frequency you should have just started the stack length object with @swStack{0} and 40.

    So yes, 10 is the stack usage for one cog. Using exactly that is OK. Myself, I use +2 (just a feeling, no rational reason(s)).
  • bill190bill190 Posts: 769
    edited 2010-04-26 15:22
    Thanks. You gave me a good idea and that was to modify the code a bit in the object with the stack(s) being tested.

    I modified it so I can pass the starting address of one specific cog and the ending address of that cog via the size.

    So I can run all 3 cogs now and measure the stack size used on just one cog - any of the 3.

    This is what I modified it to (perhaps this modification could be·written better?)...

    VAR
    · long StackBegin
    · long StackSize

    OBJ
    · Stk :· "Bill_Stack_Length"··· 'Include Stack Length Object

    PUB TestStack

    · StackBegin := @swStack[noparse][[/noparse]40]· ' Beginning location of stack for one cog.
    · StackSize :=·39············ ' Size of the cogs stack.

    · Stk.Init(StackBegin, StackSize)·

    ·TestSquareWave·············· 'Run method below.

    · waitcnt(clkfreq * 5 + cnt)·· 'Wait ample time for max stack usage
    · Stk.GetLength(30, 19200)···· 'Transmit results serially out P30 at 19,200 baud

    Post Edited (bill190) : 4/26/2010 3:37:58 PM GMT
  • bill190bill190 Posts: 769
    edited 2010-04-26 15:31
    Then I made two modifications to the Stack Length object file (copied it to my directory and renamed it to Bill_Stack_Length)

    The following adds 1 to the count so the stack size reported·is the correct size...

    · if ++USize == Size+1························································· 'If stack is full
    ··· USize~~···································································· '· flag as inconclusive

    · 'Bill modification to add 1 to string count
    · If USize > 1
    ··· USize++
    ·
    · {Convert to string}
    · Num.Init

    Then in the following I add character 13 (carrage return) to the serial output so each new message sent to the serial terminal will begin on a new line...

    · bytefill(@Text + 13, 0, 5)······················· 'Zero-terminate friendly string
    · bytemove(@Text + 12, UsedLongsStr, strsize(UsedLongsStr))

    ' Bill modification to add carrige return
    · bytemove(@Text + 12 + strsize(UsedLongsStr), string(13) , 1 )

    · UsedLongsStr := USize := @Text····························
  • kuronekokuroneko Posts: 3,623
    edited 2010-04-27 01:13
    bill190 said...
    The following adds 1 to the count so the stack size reported is the correct size...
      if ++USize == Size+1                                                          'If stack is full
        USize~~                                                                     '  flag as inconclusive
    
      'Bill modification to add 1 to string count
      If USize > 1
        USize++
    


    I disagree regarding the validity of that modification. The number you get back (originally) is the used stack size. What makes you think that you have to increase that count?
  • bill190bill190 Posts: 769
    edited 2010-04-27 02:28
    kuroneko said...

    I disagree regarding the validity of that modification. The number you get back (originally) is the used stack size. What makes you think that you have to increase that count?
    Good question and exactly the reason I am posting this topic! (To learn all about this!)

    What I did was reduce the size of the stack. Actually with just one cog running. When I reduced it to 10, I got an error. But with a stack size of 11, it worked ok and said my stack size was 10.

    As I recall the error returned was -1.

    So set stack size to 10 and I got a -1 error.
    Set stack size to 11 and it said my stack size was 10...
    ·
  • bill190bill190 Posts: 769
    edited 2010-04-27 02:33
    The following is from the Stack Length file...

    Returns:··· Pointer to string indicating actual utilization of stack, in form: "Stack Usage: #" where # is as follows:
    ············· -1 = inconclusive; stack may be too small, increase size and try again.
    ·············· 0 = stack never utilized.
    ············· >0 = maximum utilization (in longs) of stack up to this moment.
  • kuronekokuroneko Posts: 3,623
    edited 2010-04-27 02:44
    bill190 said...
    What I did was reduce the size of the stack. Actually with just one cog running. When I reduced it to 10, I got an error. But with a stack size of 11, it worked ok and said my stack size was 10.
    Yes, correct. I just wouldn't call it an error (note that it says maybe). If you set the stack size to 10 then all the markers (put there during Init()) are overwritten. So stack utilisation is inconclusive which is why you get the -1. The object simply can't tell if there is on overflow or not. Using 11+ tells you that stack usage is actually 10 (in this case the object's GetLength method could find at least one marker which makes it more obvious that 10 is acceptable, i.e. all but 1 out of 11 slots have been used). Yes, you'd get -1 as well for telling it that your stack is of size 8. But finding your minimal size involves starting pessimistic (i.e. big) and going down from there.

    It's just a matter of interpreting the result [noparse]:)[/noparse]

    Post Edited (kuroneko) : 4/27/2010 3:00:01 AM GMT
  • bill190bill190 Posts: 769
    edited 2010-04-27 02:58
    Hummm...

    Good points! I guess it would not be able to tell an exact size thinking about the way it works.

    Place markers to see if they are overwritten...

    XXXXXXXXXX

    Then the cog overwrites *all* the markers...

    YYYYYYYYYY

    Then stack length can't find any of its markers it left, so -1

    Thanks, I'm learning. I'll remove that modification...
  • iQuitiQuit Posts: 78
    edited 2010-04-27 03:10
    I have a question about using the stack length object. I would get a "y" printed to PST after my cog shut down--after the method had finished. Any ideas?
    Thanks, Dan

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    "She may not be very pretty now, but she was somebody's baby once." Bugs Bunny
  • kuronekokuroneko Posts: 3,623
    edited 2010-04-27 03:31
    iQuit said...
    I would get a "y" printed to PST after my cog shut down--after the method had finished. Any ideas?
    The serial data is sent while the caller is in GetLength. Once it returns the I/O pins are your responsibility again (note that shutting down a cog sets all pins to input again). So it's most likely some ghost data you see in your terminal (and having seen this myself I'll bet it's actually a "ÿ", character code $FF).
  • iQuitiQuit Posts: 78
    edited 2010-04-27 05:31
    You are correct sir. That was the funny little character I saw. So, do I pause before closing the cog, or just leave it open?

    Thanks kuroneko, Dan

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    "She may not be very pretty now, but she was somebody's baby once." Bugs Bunny
  • kuronekokuroneko Posts: 3,623
    edited 2010-04-27 05:35
    iQuit said...
    So, do I pause before closing the cog, or just leave it open?
    Personally I wouldn't bother. You could set the tx bit to 1 in your main cog but that would block subsequent attempts to send some data. It's only debug output after all.
Sign In or Register to comment.