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
AP_Scripting: allow expansion of memory for scripting at runtime #26517
base: master
Are you sure you want to change the base?
Conversation
f942493
to
f91f37c
Compare
My only real concern is that the user won't notice. I think we should call the error handler in scripting so it will make a fuss and print the warning lots and will trigger a pre-arm. If we do that I think its fine to allow it to run when disarmed too. Currently just running out of memory only tells you that there is not enough, I think this method would be able to tell how much is needed. Ideally the users gets this error then puts the value into the heap size param and then never sees it again. |
that would make their script fail, which loses the main reason for this PR which is to handle cases where a less common path in a script (eg. a failsafe handling) takes you over your memory limit and a critical script fails |
Sorry, bad wording, I didn't mean you actually error out, just call the |
When this says "makes it possible", what does that mean? From the dev call discussion it sounded like the RAM will be automatically allocated if needed when armed, which actually makes sense, but that's a bit more proactive than "makes it possible". Could you make it a bit clearer what's actually happening? |
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.
Some notes to make things cleaner.
@@ -23,7 +23,19 @@ class MultiHeap { | |||
// size, unlike realloc() | |||
void *change_size(void *ptr, uint32_t old_size, uint32_t new_size); | |||
|
|||
struct alloc_header { | |||
void *heap; |
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.
This is going to bump the size of every allocation by four bytes. Do we know how many allocations a typical scripting environment uses? Is four bytes sufficient alignment for the allocation?
: _vm_steps(vm_steps), | ||
_debug_options(debug_options), | ||
terminal(_terminal) | ||
{ | ||
_heap.create(heap_size, 4); | ||
const bool allow_heap_expansion = !option_is_set(AP_Scripting::DebugOption::DISABLE_HEAP_EXPANSION); | ||
_heap.create(heap_size, 10, allow_heap_expansion, 20*1024); |
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.
The reserve size is 10K smaller than the minimum allocation size. Therefore the check is redundant, and a successful heap allocation could leave 0 bytes free.
// round up to multiple of 30k to allocate, and allow for heap overhead | ||
const uint32_t alloc_size = MAX(size+heap_overhead, 30*1024U); |
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 don't think this can be described as rounding.
#ifdef HAL_DEBUG_BUILD | ||
if (ptr != nullptr) { | ||
struct alloc_header *h = ((struct alloc_header *)ptr)-1U; | ||
if (h->size != old_size) { | ||
INTERNAL_ERROR(AP_InternalError::error_t::invalid_arg_or_result); | ||
} | ||
} | ||
#endif |
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.
This makes the check done by Util::heap_realloc
redundant; that check should be removed.
if (heaps[i] == nullptr) { | ||
heaps[i] = hal.util->allocate_heap_memory(alloc_size); | ||
if (heaps[i] == nullptr) { | ||
return nullptr; |
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.
Do we need to try smaller sizes due to the multiple memory block concern like is done on init?
// not using the first argument when size is zero. | ||
hal.util->heap_realloc(heaps[0], ptr, 0, 0); | ||
struct alloc_header *h = ((struct alloc_header *)ptr)-1U; | ||
hal.util->heap_realloc(h->heap, h, 0, 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.
Now that we only use Util::heap_realloc
as malloc
or free
, should it be split into two functions? That would simplify its implementation.
this allows for new heaps to be added at runtime for lua scripting if you run out of memory while armed
f91f37c
to
98c2963
Compare
This makes it possible to expand the MultiHeap used by scripting at runtime. This means if the user underestimates the right value for SCR_HEAP_SIZE and they have free memory (which they usually do on a H7) then it will allocate more memory with a warning
Note that:
This PR also cleans up the handling of scripting debug options
The motivation for this PR is there is really no way to predict in advance how much memory a set of scripts will need, so users may under-estimate and the scripts fail at a critical time
This PR also fixes an issue where realloc may fail if there is no room in the current sub-heap. We now always alloc/copy/ree. ChibiOS was doing this within a heap already, so this doesn't cost any more, but means it fixes a path for script failure
This was test flown on a Pixhawk6X