Where's the RAM gone?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Where's the RAM gone?

2,437 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by graynomad on Fri Jul 27 21:16:39 MST 2012
I've been trying to write some heap/stack watching functions on a 1227 and seem to be getting results I don't expect.

Here's a cut down version of main()

int main(void) {
        uint32 heap_start = (uint32) malloc(1);
        uint32 psp = (uint32)__get_PSP;
}
which shows

heap_start  = 0x100005f8
psp = 0x4b9

and yet in the debugger I see

PSP = 0x10001f18
sp = 0x10001fe0

both of which seem reasonable given that RAM ends at 0x2000

Question 1,
What's with the __get_PSP call value of  0x4b9? Is that the correct way to get the SP?

Question 2,
I have a BSS of 1004 bytes and data of 308, that's 1312 bytes of RAM taken up.

8192 (8k RAM) - 1312 = 6880, so before any malloc()s I should have 6880 free bytes, Take off about 30 byes because the stack is already used so lets say there should be 6850 bytes of free RAM.

And yet the top of the heap is at 0x5f8,

0x2000 - 0x5f8 = 0x1a08 or 6664(DEC) bytes.

6850 - 6664 = 186, where have 186 bytes gone?

Does the startup code use some heap space?

Have I cocked up on my calcs or misunderstood get_PSP?
0 Kudos
Reply
17 Replies

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by graynomad on Sat Jan 05 17:52:26 MST 2013
heapGuardInit() is just a simple function I wrote to fill RAM with 0xAA.

#define    HEAPGUARD_VAL    0xAA
uint32            __heap_size;
uint8 *            __heap_start;
uint32             __free_ram;

void heapGuardInit(void) {
    __heap_size = 0;
    __heap_start = __end_of_heap;
    __free_ram = (stackPointer() - (uint32)__end_of_heap) & 0x1FFF;
    memset (__end_of_heap, HEAPGUARD_VAL, __free_ram - 16);
}

uint32 stackPointer(void) {
    return (uint32)__get_MSP();
}
I don't remember now which of those variables are defined by the system, I think __end_of_heap is. There may be other dependences, I'm using the LPCXpresso environment.
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by riscy00 on Sat Jan 05 12:26:58 MST 2013
Where is  this heapGuardInit() thing come from?

I googled it and found very little info...
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by graynomad on Mon Jul 30 04:20:33 MST 2012
[FONT=Arial][SIZE=2]Thanks whitecoe[/SIZE][/FONT][FONT=Arial][SIZE=2] that did the trick. No more heap usage and I also added CR_INTEGER_PRINTF which knocked over 4k from my program size.

[/SIZE][/FONT]  [FONT=Arial][SIZE=2]CR_PRINTF_CHAR makes the printf()s much slower as the documentation says so I can leave it out for testing. As long as I know how to kill the heap usage in the final thing.[/SIZE][/FONT]
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by whitecoe on Mon Jul 30 04:05:42 MST 2012
I suspect that you are setting the define up in the wrong place. Do it for the whole project (ie in Project Properties), rather than within your source file.

HTH!
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by graynomad on Mon Jul 30 03:41:45 MST 2012
[FONT=Arial][SIZE=2]Yes I see that this is documented behaviour that can be removed. But the recommended method doesn't seem to work.

I've got [/SIZE][/FONT][FONT=Arial][SIZE=2]CR_PRINTF_CHAR[/SIZE][/FONT][FONT=Arial][SIZE=2] defined __end_of_heap is 0x5cc and main() looks like this[/SIZE][/FONT]

#define CR_PRINTF_CHAR        1

int main(void) {

    heapGuardInit();
    printf ("%s\n", "qwerty");
   printf ("%s\n", "$GPGGA,092204.999,4250.5589,S,14718.5084")
Just after heapGuardInit() the heap looks like this.

0x100005CC  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
0x100005D8  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
0x100005E4  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
0x100005F0  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
0x100005FC  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
0x10000608  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
0x10000614  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
having been filled with 0xAA from __end_of_heap to just below the SP.

I step over the printf() and the heap looks like this

0x100005CC  00 00 00 10 02 00 00 00 00 00 00 00  ............
0x100005D8  71 77 65 72 74 79 0A 00 AA AA AA AA  qwerty..ªªªª
0x100005E4  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
0x100005F0  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
0x100005FC  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
0x10000608  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
__end_of_heap is now 0x5E0 so clearly some heap has been allocated and not freed.

Then I step over the second printf()

0x100005CC  00 00 00 10 0B 00 00 00 00 00 00 00  ............
0x100005D8  24 47 50 47 47 41 2C 30 39 32 32 30  $GPGGA,09220
0x100005E4  34 2E 39 39 39 2C 34 32 35 30 2E 35  4.999,4250.5
0x100005F0  35 38 39 2C 53 2C 31 34 37 31 38 2E  589,S,14718.
0x100005FC  35 30 38 34 0A 00 AA AA AA AA AA AA  5084..ªªªªªª
0x10000608  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
0x10000614  AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªª
__end_of_heap is now 0x604. It seems that the previous allocation has been freed and a new one performed.

So what happens if I do a malloc() in between the two printf()s?

    printf ("%s\n", "qwerty");
    void * x = (void*)malloc(1);
    printf ("%s\n", "$GPGGA,092204.999,4250.5589,S,14718.5084")
The malloc() does indeed go on top of the "qwerty" as you would expect if "qwerty" had been freed. And the following printf() allocates after my malloc().

So looking at the memory dump things are working OK if you ignore the fact that this version of printf() is not supposed to use the heap in the first place.

But __end_of_heap is not updated after the printf() call. Does free() deal with that variable properly?

I'm using Redlib(semihost) if that makes a difference.
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by CodeRedSupport on Mon Jul 30 00:20:25 MST 2012

Quote: graynomad

Interesting, it seems that printf() malloc()s then free()s for temp storage. That's not on for a robust system and it's probably quite large anyway so I'll need a lightweight version.


As documented here...

http://support.code-red-tech.com/CodeRedWiki/redlib_v2_notes

Note that you can change this behaviour by defining "[FONT=Courier New][SIZE=2]CR_PRINTF_CHAR[/SIZE][/FONT]".

The above FAQ also provides some information on heap behaviour at a general level.

For more general information on C library issues, please see the FAQs listed at:

http://support.code-red-tech.com/CodeRedWiki/CodeRedFAQ#CLibrary

Regards,
CodeRedSupport
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by graynomad on Sun Jul 29 08:10:16 MST 2012
Don't mind me, I'll just prattle on :)

Interesting, it seems that printf() malloc()s then free()s for temp storage. That's not on for a robust system and it's probably quite large anyway so I'll need a lightweight version.
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by graynomad on Sun Jul 29 07:37:19 MST 2012
Well __end_of_heap has turned up in the debugger's "variable" window, I have no idea where it came from, at least I can see the value and it looks like a malloc(1) actually allocates 12 bytes for some sort of structure plus the 1 byte you asked for. Add the word alignment and you lose 16 bytes in all.

Is there any way to get __end_of_heap programatically? EDIT: Never mind, I figured it out...don't ask :o

The map file now looks normal, maybe the last time I looked it was after a failed build and therefore was it not complete.

There are a few things of mine (globals) taking space but the worst offender is something called __Ciob that needs 320 bytes. Yikes! It's from stdio, something to do with printf maybe?

I'm learning good stuff but really all I wanted to do was write a test for free ram and move on to more interesting things.
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by graynomad on Sun Jul 29 00:54:22 MST 2012
The only .map file I can find looks nothing like any map file I've ever seen. There's no symbols or addresses or anything normal, just a list of object files that (I guess) have been included in the project.

As for _pvHeapStart and __end_of_heap, how do I access them? They both give "undeclared variable" errors.[I]

:confused:
[/I]
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by atomicdog on Sat Jul 28 19:32:23 MST 2012
The linker variable [I]_pvHeapStart[/I] is where the heap starts. [I]__end_of_heap[/I] is where the end of the heap is currently at.
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by atomicdog on Sat Jul 28 19:03:38 MST 2012
Have you looked at the [I].map[/I] file? It will show you what variables are taking up space.
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by graynomad on Sat Jul 28 17:31:44 MST 2012
Thank you very much atomicdog, that was the problem. Doh.

Now I can get proper numbers I still don't understand the RAM usage,

I have

data + bss = 1288

I use

uint32 heap_start = (uint32) malloc(1);

to find the start of the heap, this is the first thing main() does and I get a value of 0x5e4 which is 1508 DEC.

1508-1288 = 300 bytes.

I guess there are some allocations happening behind the scenes, for example malloc() itself would need a structure. But 300 bytes?
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by atomicdog on Sat Jul 28 14:17:58 MST 2012
Were you casting to uint32_t to get ride of a warning?
If so (and what you posted isn't a copy&paste error), your problem is that you're not calling the [I]__get_PSP[/I] function.

You have...
__get_PSP;
Should be...
__get_PSP();
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by graynomad on Sat Jul 28 01:32:07 MST 2012
Yes I wasn't sure so tried both, if I change to __get_MSP the returned value is 0x4e9 which is almost the same as __get_PSP (0x4b9).

I thought maybe that's a word address but if you x4 it's 0x12e4 which can't be right either.
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by atomicdog on Sat Jul 28 01:15:31 MST 2012
Don't you want the MSP instead? Since it's the default  SP.
You need to init/set the PSP before it will have sane/valid value.
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by graynomad on Fri Jul 27 22:27:08 MST 2012
:)

Ooo I left myself open for that one, and I grew up on a sheep farm as well.
0 Kudos
Reply

2,343 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by larryvc on Fri Jul 27 22:02:25 MST 2012
Where's the RAM gone?  Off following the EWE of course.:rolleyes:

Sorry, Rob.
0 Kudos
Reply