Page 1 of 2

Confusion with calculation of ram usage

Posted: Sat Mar 08, 2014 12:11 pm
by seulater
Before i start, i am beyond embarrassed to ask this question. At the same time i am man enough to admit my shortcomings and ask the question for clarity to make me better.

After all these years of coding i just noticed this today, which is what blows my mind.
In a nut shell why does the ram usage calculate properly if i create a global array, but if i then add another array inside a function it does not take this into account as well.

If i create a global array, such as:

Code: Select all

char buff[1024]; 
void main(void)
{
} 
and compile i see how much ram is being used. No problem.. and if i increase buff to say [2048] i again compile and see that even more ram is being used. Still not a problem.

Now here is where the problem comes in for me. Say i now do this.

Code: Select all

char buff[1024]; 

void MyFunction(void)
{
    char buffer[4096];

    buffer[0] = 0;
}


void main(void)
{
    MyFunction();
} 
When i compile the above i get the same ram results as if i never added the MyFunction, function. In fact i can even change buffer[4096] to buffer[8192], re-compile and still that ram usage will stay the same. How can this be ???

In my mind when i see this issue of the ram size not increasing i am thinking this: Say we inherited a project from another user with 20-40 .cpp files. We were told just to add one small change to it. At this point becuase the ram is not increasing in size when using arrays inside a function how can we as the programmer know if we are actually going to be reading / writing data into some other variable space.

If this was pointers i would totally get it because the compiler does not know how much i want to store, but with an array it knows because i told it when i created the array.

Re: Confusion with calculation of ram usage

Posted: Sat Mar 08, 2014 1:12 pm
by Ridgeglider
Seulater:
Whenever a function is called that uses local variables, they're pushed onto the stack of whatever task loop has called the function. Finding out about the RAM allocation of that stack space is where the functions OSDumpTCBStacks() and OSDumpTasks() come in to play. With them, you can see how much space has been allocated for each task, and how much actually has been used. This allows you to tune task space using OSTaskCreatewName() or OSTaskCreate(), instead of using the defaults built into OSSimpleTaskCreate() or OSSimpleTaskCreatewName() macros. Note that when you use the 'wName' variants, the name you've used for the task shows up in the OSDumpTasks, or OSDumpTCBStacks output instead of just the task prio numbers: ie MUCH easier to interpret!

To allow the dump functions to work, make sure to uncomment the

#define UCOS_STACKCHECK (1)

line in predef.h and rebuild the system.

Forrest wrote up a pretty good usage guide: http://forum.embeddedethernet.com/viewt ... f=5&t=1411
See also C:\nburn\docs\NetBurnerRuntimeLibrary\uCOSLibrary.pdf

I bet the .map file would shed light on the stacks that are assigned as well as the static vars too , but I haven't poked around there for a while....?

Hope this helps.
Ridge

Re: Confusion with calculation of ram usage

Posted: Sat Mar 08, 2014 1:39 pm
by Chris Ruff
wOW that is some automatic array size! I usually try to keep automatic variables less than 300 bytes. But then, that's. Just me...
Chris

Re: Confusion with calculation of ram usage

Posted: Sat Mar 08, 2014 2:01 pm
by seulater
wOW that is some automatic array size! I usually try to keep automatic variables less than 300 bytes. But then, that's. Just me...
Chris
Mainly it was for example, but lets talk about your comment as i am curious and it may help to see where i am jacked up at.

If there was a global array and i needed to parse through it and change some things to a different value and then pump that out say to a socket. how would you then do that keeping under 300 ? For instance.

Code: Select all

char main_string[4096];   

void Manipulate(void)
{
    char temp_string[4096];

    strcpy(temp_string, main_string);

    // some code here to check for certain values and replace them 
    // now we are done manipulating so lets shove it out on a TCP socket.

}

void main(void)
{
    Manipulate();
}



In my thoughts, i create char temp_string[4096]; in the function, when the function exits it can release that ram back to the system. But if I instead make it another global variable then i tie up more ram forever.

Re: Confusion with calculation of ram usage

Posted: Sat Mar 08, 2014 2:32 pm
by Chris Ruff
There is a LOT of RAM available. I would use the global temp ram array and not use the task stack
Chris

Re: Confusion with calculation of ram usage

Posted: Sat Mar 08, 2014 3:49 pm
by seulater
Lets switch this up.

We agree that when placing a variable in a function does not change the ram size. So then lets say someone created a large application which used all ram minus 1 byte. We inherit this application from another coder and know nothing about it. We know it compiles and runs fine.
We are told to make a simple change to it. So we add a new function and in there we add another variable, unsigned char x=0;
We then re-compile, ram size does not change, and it works. No problem because we had that last byte left.
Now we add another variable to that same function, unsigned char y=0; Re- compile and all compiles well, however in actuality we are over our ram usage by one byte. No when we run our program it gets jacked up and we have no idea why.

How do coders handle this type of situation then if the compiler does not accurately represent just how much ram we are using.

Re: Confusion with calculation of ram usage

Posted: Sat Mar 08, 2014 4:40 pm
by rsg
The problem is that you are confusing where the function-local variable is allocated from, and what the global memory in use function (sorry, I don't remember what that is called) is reporting. Local variables, which is what you are changing the size of, are allocated dynamically (or should I say, "automatically") from the stack. That memory use function takes into account the entire stack, as it is allocated statically. So that is why it never changes the value it reports when you simply change the size of the local variable.

So, from the global point of view, the entire stack for a task is allocated, and in use, from the get-go. Even if you only use one byte, the entire stack will be counted as "in-use"; similarly, if the stack is half-used, fully-used, or any other value, it entire size is counted as in use.

To put it a different way, all you are affecting is your stack usage - there, your changes will be seen. Allocating large structures on the stack is dangerous - not forbidden, because it can work, but dangerous because stack overflows can be nasty beasts to track down. That is why Chris is suggesting using a global array, which the linker (and therefore, that function) can account for. Alternatively, you can use malloc (or new) to dynamically allocate memory; these will fail, and report to you that failure. This at least gives you a fighting chance to deal with the problem. The compiler and linker can't tell you when you have overrun your stack, because that depends on how much stuff is already on it - which is a run-time condition.

Hope this helps!
Bob

Re: Confusion with calculation of ram usage

Posted: Sat Mar 08, 2014 4:49 pm
by rnixon
If it helps code readability, leave it in the function but make it static so its allocated from global memory instead of being an auto-var on the task stack. I agree with the previous poster that I keep all auto-vars very small, like 300 bytes or less. I've tracked down enough stack overflow issues in my past to want to avoid it by a huge margin. See static example below.


void MyFunction(void)
{
static char buffer[4096];

buffer[0] = 0;
}

Re: Confusion with calculation of ram usage

Posted: Sat Mar 08, 2014 4:56 pm
by Ridgeglider
If you're declaring local variables that are pushed onto the stack when functions run, you need to look at how much of the allotted stack space is actually being used. Not sure if this is a complete list, but I think the RAM usage has to be the sum of whatever static and global vars are created, plus the sum of the stack space allotted for each task, plus whatever heap is used during ISRs. As long as the space used by the call list of functions within a task's stack stays in the allotted space, you're OK. What makes this tough to analyze up front is that RAM usage is dynamic and depends on the call list which can, of course depend on the external events that generate that call list. That's why OSDumpTCBStacks() is useful because it shows the highwater mark for RAM usage with the allotted space for each task over a period of time during which you exercise the system. The stack memory is reported as part of the overall RAM used. When the system starts, however very little of each of the allotted stacks' space is actually used. As you use the system, the stack space an any instant goes up and down although the amount reported is always the maximum allotted to the stack.

Re: Confusion with calculation of ram usage

Posted: Sat Mar 08, 2014 7:04 pm
by seulater
Thanks guys for the tips. But i am not getting my point across. It seems to many are looking at the example i posted as what i am actually doing rather than looking at it as an example to get the point across. It seems to be causing them to focus on the example and the question.

rsg, gave me a good enough explanation that i feel takes care of it for me.