-
Notifications
You must be signed in to change notification settings - Fork 3k
GCC - Add support to split heap across 2-RAM banks #9944
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
043b82a
to
62fc0e2
Compare
@deepikabhavnani Please fix the trailing whitespace that astyle found. |
Holding because @sg- has a problem with this in an offline conversation. |
Need think of solution for trim operation in malloc, once the allocated memory is freed and trimmed back to region 1, it will not get allocated again. |
I don't see the problem; the current sbrk implementation doesn't support malloc_trim anyway so we are not losing functionality. If we want to support it, the easiest solution would be to wrap it:
|
I need to check the free operation, if internally GCC does release of memory (not free) done at the end of last allocation which is usually done by passing -negative value to _sbrk(). We can have solution to that as well, just need to verify and add. |
@sg- I tried allocating and free entire heap memory multiple times with this example https://gist.github.com/deepikabhavnani/5a515f2bced590fa9a9688ecc864886d and it worked fine. GCC does not make the memory available to OS when we do free operation, it internally maintains the link list of all allocations and combines adjacent chunks to coalesce them. Verified by allocating and freeing different sizes of allocations. Reference : https://sourceware.org/glibc/wiki/MallocInternals |
62fc0e2
to
c37b361
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Maybe we can enable this MBED_SPLIT_HEAP in L476 as well ?
- what happened if MBED_SPLIT_HEAP is not enabled for a L475 chip ? Should we define memory regions in the ld file depending on this MBED_SPLIT_HEAP macro ?
@@ -3936,7 +3937,7 @@ | |||
} | |||
}, | |||
"detect_code": ["0468"], | |||
"macros_add": ["USBHOST_OTHER", "TWO_RAM_REGIONS"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand that this TWO_RAM_REGIONS macro should have been deleted in #9571
Note it is also defined for RHOMBIO_L476DMW1K
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Thanks will add fix for FixedRHOMBIO_L476DMW1K
in separate PR
👍
Adding macro in linker script will need tools update, instead shall we change. Shall I change |
Note for self -
This test should be updated for split heap support |
c37b361
to
ae939cb
Compare
targets/TARGET_STM/TARGET_STM32L4/TARGET_STM32L475xG/device/TOOLCHAIN_GCC_ARM/STM32L475XX.ld
Show resolved
Hide resolved
targets/TARGET_STM/TARGET_STM32L4/TARGET_STM32L475xG/device/TOOLCHAIN_GCC_ARM/STM32L475XX.ld
Show resolved
Hide resolved
ae939cb
to
27eed4b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no other actors in the system or "real system" for that matter, therefore releasing memory to the system is not needed.
27eed4b
to
ac16f56
Compare
* If the new address is outside the first region, start allocating from the second region. | ||
*/ | ||
if (once && (new_heap > (uint32_t) &__mbed_krbs_start_0)) { | ||
once = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does once do - either changing the name to be more clear about the intention or adding a comment. Or at least 1258 comment could include this boolean - it touches only address check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
once - is indicator of allowing to enter just once. I can update the comment to add more clarity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I meant by sbrk behavior is that if you try to allocate here more memory than is available in first region, the code moves to another region and you end up nothing being allocated from first region in the worst case. And you can't come back here either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, given the current behaviour of newlib's malloc, I don't think the once
flag is needed.
The regions must be in memory address order, or newlib malloc would get confused. (Is that known/documented for this feature? I spotted it by inspection of newlib source, and it makes sense given the normal POSIX function of sbrk
).
So the test could be if (heap <= (uint32_t) &__mbed_krbs_start_0 && new_heap > (uint32_t) &_mbed_krbs_start_0)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes looks fine, question:
I find the naming confusing: start_0
means it comes before _start
- it is in the lower ram bank (lower address) as heap starts pointing to start_0.
This could be trivial I might be just confused with _start
vs _start_0
naming - if I have a target with two RAM banks for heap and want to apply this start/0 to it - I would not know how to apply this to memory sections based on the release notes addition .
Why is it not _0 and _1 / first/second ?
@0xc0170 - I understand the confusion, but only reason to not update both to _0 and _1 was to have compatibility with old/existing definitions. Some targets have __mbed_krbs_start and __mbed_sbrk_start in their linker files. Let me know how I can improve to add more clarity (apart from changing to _0 and _1) |
CI started |
Test run: FAILEDSummary: 2 of 11 test jobs failed Failed test jobs:
|
Aborted build, we need CI time for 5.12.2 jobs today |
Can we start the CI on this? |
Why is that 5.13? And not 5.12.x? |
I believe because it is new feature. Initially it was 5.12.0, may be because of that? |
Hello @deepikabhavnani & others. At some point I was reporting allocation problems with pelion-enablement on L475 with this PR. There the allocation/freeing is made in order of 10 /20 / 40 / 60kb. The 40kB allocation failed in that test. There are several factors at play in here, originating from the newlib implementation. One of these factors is that the _sbrk allocation is aligned to 4kB, and it always tries to allocate one extra page. Second thing is that the allocator does not try to allocate only the missing bytes (e.g. for 40kB we would need ~20kB extra allocated, as we freed that already) but the whole deal (in this case 40kB) in addition. And this is where it fails in this case because with the extra page put on top there is not enough memory (only 63kB or so). Probably the only way to make this work in application is to preallocate (and free) the memory so that both regions are available for use (if you allocate too much on the first go, you end up skipping the first region altogether). We looked this with @kjbracey-arm and he has filed question of this behaviour in here https://answers.launchpad.net/gcc-arm-embedded/+question/680433 |
ci started |
Test run: SUCCESSSummary: 11 of 11 test jobs passed |
@juhoeskeli - Agree with larger chunks of memory it will be good to pre-allocate them or follow the allocation order of larger to small. In case of single RAM bank GCC can take care of merging the allocation regions, but in 2-region model if first block is 40K and another one 60K initial different sequence will result into different behavior. Example Sequence 1 - In order 10K, 20K, 40K, 60K Sequence 2 - In order 60K, 40K, 20K, 10K Sequence 2 - In order 60K, 20K, 40K, 10K @juhoeskeli - Please clarify if your observation aligns to this understanding. |
@deepikabhavnani I'm going to hold off on merging this until the question is answered |
Citing Kevin, from the link I posted earlier: "Best current work around from outside the library I can see is to have a "heap preload loop" at startup that allocates lots of small (<pagesize) blocks forcing the allocator to make maximally-efficient small sbrk calls, then releases them all."
I think the 60k allocation will not be successful, as the allocator tries to allocate that 60k from address after the 40k which was freed.
Yes, but what happens is that the RAM1 will be left unused and no way to reclaim that (due to how sbrk works - added a comment about this to relevant code section).
Yes, but what happens is that the RAM1 will be left unused and no way to reclaim that. You must free the 60k otherwise it will not work.
@deepikabhavnani @adbridge I would still go forward with this, as there is nothing wrong with the PR itself. It is the feature of newlib allocator. With all these caveats I feel it is still better system like this than without. A PR could be later made with workaround to this allocation issue. |
GCC/newlib still has the same basic problem in a single RAM bank. For example if you have 100K in a single region, the sequence The problem is that the And newlib also doesn't try harder - when We can avoid the issue by something like this on init:
I think I'd advocate adding that code to the pre-main startup for the GCC toolchain, on all builds. Only concern is code-size impact for blinky/bootloader. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving, despite discussion above - none of the issues are caused by this change which is sound. Would suggest removing the once
flag next time it's touched though.
Description
GCC - Add support to split heap across 2-RAM banks.
Commit messages provide more information.
Pull request type
Reviewers
@marcuschangarm @juhoeskeli @c1728p9
Release Notes
Mbed heap split into 2-Ram banks is added which can be enabled by compiling source with MBED_SPLIT_HEAP macro. Linker symbols
__mbed_sbrk_start
__mbed_krbs_start
__mbed_sbrk_start_0 __mbed_krbs_start_0
should be added by you in GCC linker script to state start and end of each HEAP region.