-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add movable supervisor allocations #3695
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
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.
One minor thing. Overall it looks like a huge improvement. Thank you! I restarted the CI hoping to see how well it fits.
I'd also like @jepler to take a look. He did a number of the displayio uses.
The added commit should fix the mimxrt10xx and esp32s2 failures (and not break the rest). Will absorb this into the first commit on the next rebase (unless there are objections). However, could someone who is familiar with that port take a look at ports/cxd56/supervisor/port.c? Its Regarding the code size, it occurs to me that I should |
@kamtom480 would know about the stack on the cxd56. |
@cwalther You're right. |
OK, I’ll change it here. Would you also like a PR to change it in the current code, independently of this one? I’m not sure if this will go into the next stable release. |
@cwalther Ok, I understand. In that case, I will test this change tomorrow and if everything works, I will create PR. |
In the current code (before my change) it’s a bit more involved than just changing a |
@cwalther Thank you for finding this. I created PR. |
I was mistaken about the failing M0 boards – some of them include |
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 did not fully follow the implementation of allocate_memory_node or supervisor_move_memory, but I feel I understand them at the high level anyway, and the high level is solid. If there are bugs we can shake them out.
I resolved the merge conflicts locally, but three builds still don't fit without other changes. I may look at it further to see if I can find the necessary savings. @cwalther is there any part of this we can disable on flash-constrained builds, or is it all-or-nothing? |
This allows calls to `allocate_memory()` while the VM is running, it will then allocate from the GC heap (unless there is a suitable hole among the supervisor allocations), and when the VM exits and the GC heap is freed, the allocation will be moved to the bottom of the former GC heap and transformed into a proper supervisor allocation. Existing movable allocations will also be moved to defragment the supervisor heap and ensure that the next VM run gets as much memory as possible for the GC heap. By itself this breaks terminalio because it violates the assumption that supervisor_display_move_memory() still has access to an undisturbed heap to copy the tilegrid from. It will work in many cases, but if you're unlucky you will get garbled terminal contents after exiting from the vm run that created the display. This will be fixed in the following commit, which is separate to simplify review.
Moving memory is now done by the infrastructure and neither necessary nor correct here anymore.
Hybrid allocation is now part of the infrastructure. Moving memory contents would not be necessary because displayio can recreate them, but does not hurt.
Hybrid allocation is now part of the infrastructure. Moving memory contents would not be necessary because displayio can recreate them, but does not hurt.
It not only caused crashes with requests larger than 64K (can happen with RGBMatrix), but also generated a lot longer code than necessary.
Avoids wasted memory and makes it easier to keep track of who needs how much for future additions.
After talking to @dhalbert on Discord, he plans to disable complex arithmetic to get space for deep sleep. This may leave enough space to let us incorporate this pull request too. |
Thanks for the notice, I haven’t been on Discord for a few days. I’m working on the code size, but with no great gains yet. I have one optimization that recovers 64 bytes, but not enough for the metro_m0_express. Will push that shortly, also fixing the conflicts.
Thanks for the review. For that matter, I think it’s important that some of you maintainers understand this code to some extent, because I can’t promise that I will always be around to maintain it (though I’ll do my best).
On the boards that use no movable allocations (that does not include the metro_m0_express), |
When no features are enabled that use movable allocations, supervisor_move_memory() is not needed.
Building this branch merged together with #3767, BOARD=metro_m0_express TRANSLATION=de_DE has 744 bytes free. |
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 good to go except that we need 3767 to go in first so we have the flash space.
The goto issue was discussed and OK'd.
The last commit eliminates the But do take a critical look at it if you want to merge right away, I may be too tired for such things right now. 🙂 |
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.
Looks good to me! Thank you!
This allows calls to
allocate_memory()
while the VM is running, it will then allocate from the GC heap (unless there is a suitable hole among the supervisor allocations), and when the VM exits and the GC heap is freed, the allocation will be moved to the bottom of the former GC heap and transformed into a proper supervisor allocation. Existing movable allocations will also be moved to defragment the supervisor heap and ensure that the next VM run gets as much memory as possible for the GC heap.Allocations embedded in the GC heap are tracked using the same
supervisor_allocation
struct as proper supervisor allocations, transparently to clients. Clients can deal with moving memory either by holding onto theirsupervisor_allocation
(which stays valid across the move) and getting itsptr
(which changes) every time they need to dereference it, or if they held onto theptr
directly, get notified using a callback when it changes. The only time moves happen is at the end of a VM run.This unifies a couple of existing ad-hoc mechanisms doing similar things with the terminal tilegrid, Sharp display framebuffer, and RGBMatrix, and provides the infrastructure for future applications of saving information from one VM run into the next, such as which file to run next (#1084 + #3454), exception traceback from the previous run (#1084, PR forthcoming), and USB descriptors (#1015).
Rationale for the internal design:
supervisor_allocation
s can no longer match the order in memory, as GC allocations can come in any order. The order, still needed by the regular supervisor heap administration, therefore needs to be tracked in some other way. Let’s use a linked list (or two, one for the low and one for the high side – that also allows treating them the same in some places).next
pointers need to be part of the allocated blocks themselves so that the GC can find them, rather than some external structure likesupervisor_allocation
. This introduces thesupervisor_allocation_node
struct, of which thedata
block given to the client is only a part.length
fromsupervisor_allocation
tosupervisor_allocation_node
too, so that it only takes up memory when actually used. To avoid putting thesupervisor_allocation_node
definition and theALLOCATION_NODE
macro in the public header, client access to the length is mediated by a function,get_allocation_length()
.MOVABLE
flag (which unlike the existingHOLE
flag can also be set on allocations that are in use by clients) in thelength
field without confusing clients.supervisor_allocation
is forsupervisor_allocation*
to act as a “handle” or “pointer-to-pointer” to enable clients to deal with moving memory. Keeping it a single-field struct rather than changing it totypedef uint32_t* supervisor_allocation
improves type safety somewhat.malloc
-like API and want to hold onto block pointers directly instead of through a “handle”, such as Protomatter in the RGBMatrix case, there needs to be a way of mapping from old to new pointer during a move notification. This is achieved by makingallocation_from_ptr()
expect the old pointer during that time, with the old pointers set aside higher up in the stack.