-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Ensure USB host buffers are allocated in internal RAM #10633
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
base: main
Are you sure you want to change the base?
Conversation
This seems to work well. Tested on Fruit Jam rev D. |
I was testing this on my modified tinyUSB build and ran into a memory error when trying to run Fruitris so I tried on the stock Fruit Jam and got the same error:
|
Thinking about it, that makes sense. My sample code doesn't use any large buffers, and it calls Perhaps, instead of dynamically allocating SRAM buffers, |
cc @relic-se |
@tannewt Now that I've seen how you approached this PR, I think I could probably get a static buffer version of this working to test whether it would have fewer problems with SRAM heap allocation. No promises on results, but I'm gonna take a look at it. |
@RetiredWizard I wasn't able to reproduce your error with Fruitris. Were you doing anything special? My setup:
I did have to make a couple attempts to get all the project bundle files copied to CIRCUITPY. Initially, I tried ![]() |
Apparently having a launcher.conf.json file with:
is the difference, |
Oh, one other possible difference is that I'm using the packaged version of Fruitris from https://github.com/RetiredWizard/Fruit-Jam-OS_MyApps. Other than some minor audio changes from a pending PR I don't think there are any differences from the version from @relic-se respository |
oh.. so to trigger this, it's not just a matter of using Fruitris, but I would need to install Fruit Jam OS? |
Just made a PR with a static buffer version of the code from this PR if anybody wants to compare: |
Fruitris doesn't utilize that property at the moment, but my guess is that the initialization of that device within Fruit Jam OS before loading the application might have been the cause.
Thanks for your PR to fix this one! (relic-se/Fruit_Jam_Fruitris#9) I don't believe this should be a problem any longer. |
I'm not sure I want to go so far as a static allocation. Silently failing if a request is longer than the buffer isn't good and allocating more than you need seems subpar too. One thing we could do is share the temporary buffer amongst all devices. Right now it is per-device. Allocating the large framebuffers late after startup will also be risky. It's much better to do the largest allocation first and keep it. |
Some things to weigh here as you consider how to move forward with this:
|
This won't be under the program's control if we silently allocate a shorter buffer internally. I agree that the argument should be checked but it should be a sign of the device's response length, not an intermediate limitation.
My code doesn't allocate until a transfer with a PSRAM buffer is done. I'm not convinced that customizing this code is the right way to handle the fact that allocating a large framebuffer can fail sometimes. Do we know what is causing the buffer allocation in Fruitris and why it occurs before the new framebuffer is allocated? |
Taking a quick skim through the adafruit/Fruit-Jam-OS repo, I didn't see any sign of calls to |
Part of what I was thinking with the static buffer approach is that it would buy folks some extra breathing room by making heap fragmentation less likely. That way they wouldn't have to think as much about managing memory allocation when writing Python code. OTOH, you could definitely make an argument that people should consider memory management more in their Python code by calling |
gc.collect() isn't involved here. It manages the VM Python heap. The framebuffer error is caused by the "outer" heap fragmentation which separately manages the internal SRAM and the external PSRAM. The internal SRAM is only used for buffers that are used by DMA (like the framebuffer) and buffers that need to be accessed when PSRAM access is disabled (like the USB buffers.) |
Oh... interesting. So what can be done to manage outer heap fragmentation? Is that something people writing Python code have any control over? |
Don't try to allocate almost all of it into a framebuffer. :-P Not really, they don't have much control. There should be very few allocations there so the hope is that fragmentation doesn't become an issue. |
mmm... I hear you. Well, let me know if you come up with something else you'd like tested or if you want a modified version of my static allocation PR. |
While talking to Dan I realized I could simply free the temp buffer after using it instead of saving it for next time. This should prevent the fragmentation and reduce the number of concurrent allocations. Will do that now and then push it here. |
If I understand correctly, you're proposing to do a heap allocation and deallocation of the full size buffer for every I'm concerned that MIDI polling in particular is already apparently too slow such that it drops notes. |
This reduces memory use and prevents long term fragmentation.
Yup, just pushed. Please give it a test. I only made sure it compiles for Fruit Jam.
I suspect MIDI needs a separate higher level API that is implemented using TinyUSB's MIDI support for buffering. What is the way to do it in CPython on Linux? (This is similar to having a pyserial-like API for CDC.) |
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 me nervous. Feels a bit sketchy. Maybe it's totally fine. IDK.
In particular, I worry about whether static void _abort_transfer(tuh_xfer_t *xfer)
will fail in unpleasant ways under edge case conditions.
I tested the build for the latest changes and it works fine with my MIDI synth and gamepad stuff. The amount of stuck notes on the MIDI synth didn't seem any better or worse than before these changes. If RetiredWizard tries this and it works okay with Fruit Jam OS + Fruitris, then as far as I'm concerned, this is good to go. I have some reservations about |
Not sure. Aside from PyGame's |
I'm actually on a mini-vacation this weekend, but what kind of vacation would it be without the Fruit Jam along? 😁 I managed to get this artifact loaded up and Fruitris does run without giving the memory error. |
Hopefully fix #10562