Shop OBEX P1 Docs P2 Docs Learn Events
help w choosing stack size — Parallax Forums

help w choosing stack size

smthrllsmthrll Posts: 4
edited 2014-01-13 16:05 in Learn with BlocklyProp
Hello, I've been working thru the tutorials on propeller C. I'm having a bit of difficulty understanding the choosing of a stack size. Please look at the following snippet from the tutorial:


/* Blink Light with Simple Multicore and Locks.c

Version 0.94 for use with SimpleIDE 9.40 and its Simple Libraries

Multicore example for use with CMM or LMM memory models.

http://learn.parallax.com/propeller-c-tutorials
*/

#include "simpletools.h" // Include simpletools header

// For LMM cog 160 bytes declared as int
// Add enough for stack & calcs (50 bytes declared as int
unsigned int stack[(160 + (50 * 4)) / 4];

// Declare volatile variables that will not be optimized
// to one variable for both cogs to share.
volatile unsigned int pin;
volatile unsigned int tdelay;
volatile unsigned int lockID;

// Function prototype
void blink(void *par);

// Cog 0 starts here
int main()
{
pin = 26;
tdelay = 200;
lockID = locknew();
print("lockID = %d\n", lockID);
// Pass function pointer, optional parameter value,
// stack array address, and the stack's size to cogstart.
int cog = cogstart(&blink, NULL, stack, sizeof(stack));

Could somebody shed some light on the bold part: why (160 +(50

Comments

  • SRLMSRLM Posts: 5,045
    edited 2013-10-25 19:13
    I don't know how he got there. The root source of cogstart stacksize is the propeller.h documentation, which has the following line:
    The minimum stack size per thread today is 176 longs.
    
    stacksize = sizeof(_thread_state_t) + 3 * sizeof(long);
    

    That's a stacksize in bytes. And, it looks like from above that _thread_state_t is 176-12=164 bytes*, so if I were to rewrite the learn example I would do:
    stack[sizeof(_thread_state_t)/4 + 50)]
    

    Where /4 is to convert to ints (4 bytes per int), and 50 is the estimated or measured stack required for this specific range of calling choices. If it's a single function that doesn't call anything you could make it smaller, if it's a complex web of functions it should be bigger.

    As to why leave the math in there it's a matter of maintenance. It makes it easier to see how the number is derived, and since GCC will evaluate it at compile time there is no performance penalty. If you didn't have the math in there you'd just have to have a comment explaining how you got the number.

    * That's when it was written. Since then improvements may have decreased the size to 160 bytes.
  • smthrllsmthrll Posts: 4
    edited 2013-10-27 07:03
    Thanks for the explanation. It's about 90% clear to me... just one more foggy patch. You wrote ...that's a stack size in bytes... Isn't the minimum size 176 longs, not 176 bytes? A long is still 4 bytes, so would it be correct to say that the minimum stack size declared as int should be at least (176x4)?
  • SRLMSRLM Posts: 5,045
    edited 2013-10-27 09:51
    smthrll wrote: »
    Thanks for the explanation. It's about 90% clear to me... just one more foggy patch. You wrote ...that's a stack size in bytes... Isn't the minimum size 176 longs, not 176 bytes? A long is still 4 bytes, so would it be correct to say that the minimum stack size declared as int should be at least (176x4)?

    You've found a discrepancy in the documentation. I think the correct answer is ~176 bytes, not longs. At this point one of the PropGCC authors can answer best, but I'll hypothesize:

    In the demo code we have the following two lines:
    int stacksize = sizeof(_thread_state_t)+sizeof(int)*25;
    int *stack = (int*) malloc(stacksize);
    

    malloc takes bytes as a parameter (source), so it looks like the original author intended stacksize to be in bytes. I think it's a documentation error that it says long. It probably perpetuated from the cast to int* rather than keeping it as char*.

    You might be able to experimentally try and see what the minimum stack size is. Perhaps start with a really small stack (10 bytes?), and see what the failure mode is. Then increase the stack until it starts working. If it starts working at a value not around 176 bytes or 176*4 bytes then it's probably a coincidental success. But the easier method would just be to wait for one of the Gurus.
  • jazzedjazzed Posts: 11,803
    edited 2013-10-27 12:07
    Right, the minimum size is about 176 bytes which includes space for the _thread_state_t structure.
    I've updated the cogstart documentation.

    Using malloc for stack as SRLM suggests is a good idea to get a more accurate size.
    If you don't mind using vintage C99, it is also possible to declare an array dynamically.
  • John KauffmanJohn Kauffman Posts: 653
    edited 2014-01-13 08:10
    I'm trying to write simplest possible multi-core for folks coming from PBASIC and "Learning C"
    The objective: cog 0 starts two cogs each blinks an LED, one at 1 Hz other at 2 Hz. No global variables. CMM model.

    I don't understand why mine works with far less stack size than indicated in above posts. I'm using 40+25 which I copied from sample code (I'm embarrassed to forget where).
    After reading above I would think it would take the minimum of 160 (no additional for global variables which are not used).
    My only guess is CMM is different than LMM and LMM is discussed above.

    Anyone know why this works?
    /* two cogs each controlling an LED at different blink rates */
    
    #include "simpletools.h"      //includes cogstart()
    void blinkA(void *par);    // Forward declaration. Blink duration 1000 pin 26
    void blinkB(void *par);     // Forward declaration. Blink duration 500 pin 27
    unsigned int stackA[40 + 25];  // # members for stack space array 
    unsigned int stackB[40 + 25];  // # members for stack space array
    
    int main(){
      print("start main");  // check print to terminal
      cogstart(&blinkA, NULL, stackA, sizeof(stackA));
      cogstart(&blinkB, NULL, stackB, sizeof(stackB));
      while(1){}    //main does nothing more than launch    
    }
    
    void blinkA(void *par){ 
      while(1){high(26);pause(1000);  low(26);pause(1000);
      }
    }
    
    void blinkB(void *par){                         
      while(1){high(27); pause(500);   low(27); pause(500);
      }
    }
    
  • edited 2014-01-13 09:10
    Hi John,

    Your example code is declaring 185 [edit] I should have said 260 here, see correction and explanation in next post [/edit] bytes of stack space, so you have a few extra for locals. How far did you reduce the stacks before strange symptoms appeared?

    Andy

    P.S. The 40 + 25 was based on a 160 byte stack and some room for local variables. We should update our learn site examples, probably to 176/4 + some number/4.
  • twm47099twm47099 Posts: 867
    edited 2014-01-13 15:49
    Hi John,

    Your example code is declaring 185 bytes of stack space, so you have a few extra for locals. How far did you reduce the stacks before strange symptoms appeared?

    Andy

    P.S. The 40 + 25 was based on a 160 byte stack and some room for local variables. We should update our learn site examples, probably to 176/4 + some number/4.

    Andy,
    I'm confused (a little more than usual). Isn't "unsigned int stack[40 + 25];" equal to the size of 65 longs = 40*4 + 25*4 = 160 + 100 bytes = 260 bytes?

    But to summarize, I think that the minimum stack size declaration would be "unsigned int stack[44 + S];" which gives 176 bytes + 4*S, where S is based on "...space needed for local variables, parameters, and return address in the longest call chain that could ever be active."

    The phrase in quotes is taken from ersmith's response to a question I had asked regarding how to calculate needed stack space in the thread at the link below.

    http://forums.parallax.com/showthread.php/152866-In-C-how-do-you-calculate-stack_size-for-cogstart

    Comments requested to help reduce confusion.
    Thanks
    Tom
  • edited 2014-01-13 16:05
    Aach! You're right. What's that old saying...haste makes arithmetic errors? Thanks for the correction. Your summary looks good too.
Sign In or Register to comment.