You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Optimized the root channel lookup in create_search_channels() by replacing the repeated linear search with a lookup table indexed by (ciphone, ci2phone).
Previously, each dictionary word performed an O(n_root_chan) scan to locate an existing root channel, increasing the time required to construct the search tree.
Added a dynamically allocated lookup table based on the number of Context-Independent (CI) phones in the acoustic model, enabling O(1) root channel lookup.
The optimization only changes the lookup mechanism used during search tree construction. The search tree structure and recognition behavior remain unchanged.
Validation
Wrote a benchmark for Decoder.add_word(update=True) to evaluate the performance of rebuilding the search tree.
The benchmark identified create_search_channels() as a performance bottleneck, specifically the repeated linear search for existing root channels.
Reran the benchmark after implementing the optimization and verified the performance improvement.
All existing functionality tests pass successfully with no functional regressions observed.
Nice optimization — replacing the O(n_root_chan) linear scan in create_search_channels() with an O(1)root_lookup[ciphone][ci2phone] table is a clean win. The lookup is logically equivalent to the original: the table is zero-initialized so NULL means "not found", it is populated exactly when a new root channel is created, and single-phone words continue before the lookup (ngram_search_fwdtree.c:202) so the ciphone/ci2phone indices are always valid CI phones in [0, n_ci). The root_chan_t *** type matches ckd_calloc_2d(n_ci, n_ci, sizeof(root_chan_t *)).
One issue to fix before merge, though: root_lookup is never freed.
It is allocated in init_search_tree() but deinit_search_tree() (which frees every other search-tree array) does not free it. deinit_search_tree() runs both at teardown (ngram_fwdtree_deinit) and before every rebuild (ngram_fwdtree_reinit), so the whole n_ci × n_ci table leaks on every search-tree build — including each Decoder.add_word(update=True), which is exactly the path this PR optimizes.
Confirmed under AddressSanitizer/LeakSanitizer (Linux/GCC), single decoder lifecycle via test_fwdtree:
Direct leak of 336 byte(s) in 1 object(s) (row pointers, n_ci=42)
Indirect leak of 14112 byte(s) in 1 object(s) (42 x 42 table)
SUMMARY: AddressSanitizer: 14448 byte(s) leaked in 2 allocation(s).
#3 init_search_tree src/ngram_search_fwdtree.c:85
That is ~14 KB per build, and it grows without bound across repeated add_word(update=True).
The fix is one line, added to deinit_search_tree() alongside the other frees:
With that added, the LeakSanitizer run comes back clean. deinit_search_tree() is the right place since it is paired with the init_search_tree() that allocates the table, covering both the rebuild and teardown paths.
Good catch. root_lookup was missing from deinit_search_tree(), causing a leak on every search-tree rebuild. I've added the corresponding ckd_free_2d() and verified that the leak is resolved.
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
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.
Changes Proposed
create_search_channels()by replacing the repeated linear search with a lookup table indexed by(ciphone, ci2phone).Validation
Decoder.add_word(update=True)to evaluate the performance of rebuilding the search tree.create_search_channels()as a performance bottleneck, specifically the repeated linear search for existing root channels.Performance Results
Decoder.add_word(update=True)