mpdecode_core: slice one shared subs pool per c/v-node array - #77
Open
LA7LKA wants to merge 1 commit into
Open
Conversation
init_c_v_nodes() called CALLOC() once per c_node and once per v_node for their subs arrays - potentially thousands of small, irregularly-sized allocations per decoded frame, all freed again at the end of the same run_ldpc_decoder() call. On a memory-constrained embedded target (STM32F7, ~16 KB of heap actually available under a real application's other static usage) that churn fragments the heap badly enough to fail a request well before the nominal total bytes are exhausted - confirmed on hardware: a 24-byte allocation failing with a 16200-byte allocation (DecodedBits) having just succeeded moments earlier in the same call. Every CALLOC()/MALLOC() in this file is followed by an unchecked assert(), so a failed allocation is fatal in any build without -DNDEBUG. Node degree is already fully known before any subs allocation happens, so this sums the total up front and hands out each node's subs as a slice of one shared CALLOC() instead of its own. Same total bytes, same per-node layout and population logic (untouched), just contiguous rather than thousands of separately-managed chunks - fragmentation between nodes is no longer possible. c_nodes[0].subs/v_nodes[0].subs are now the only real allocation base pointers; run_ldpc_decoder()'s cleanup is updated to match (freeing any other node's subs would corrupt the heap, since it's no longer a real malloc()/calloc() return value). Reproduced and fixed against FreeDV 700D (H_16200_9720) on an STM32F746 running the full application (USB Audio Class, HMI, OLED, etc. all resident) - RX decode now completes cleanly where it previously hung every time on the first real frame. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
init_c_v_nodes() called CALLOC() once per c_node and once per v_node for their subs arrays - potentially thousands of small, irregularly-sized allocations per decoded frame, all freed again at the end of the same run_ldpc_decoder() call. On a memory-constrained embedded target (STM32F7, ~16 KB of heap actually available under a real application's other static usage) that churn fragments the heap badly enough to fail a request well before the nominal total bytes are exhausted - confirmed on hardware: a 24-byte allocation failing with a 16200-byte allocation (DecodedBits) having just succeeded moments earlier in the same call. Every CALLOC()/MALLOC() in this file is followed by an unchecked assert(), so a failed allocation is fatal in any build without -DNDEBUG.
Node degree is already fully known before any subs allocation happens, so this sums the total up front and hands out each node's subs as a slice of one shared CALLOC() instead of its own. Same total bytes, same per-node layout and population logic (untouched), just contiguous rather than thousands of separately-managed chunks - fragmentation between nodes is no longer possible. c_nodes[0].subs/v_nodes[0].subs are now the only real allocation base pointers; run_ldpc_decoder()'s cleanup is updated to match (freeing any other node's subs would corrupt the heap, since it's no longer a real malloc()/calloc() return value).
Reproduced and fixed against FreeDV 700D (H_16200_9720) on an STM32F746 running the full application (USB Audio Class, HMI, OLED, etc. all resident) - RX decode now completes cleanly where it previously hung every time on the first real frame.