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
Profiling investigation revealed that the lookup maps are already lazily cached and NOT rebuilt per parse cycle. The clear() method (called between parses) intentionally does not invalidate the lookup maps. The buildLookupMaps samples in the async-profiler output come from:
First-time map build on fresh containers -- In single-shot CLI mode (AeshRuntimeRunner), each JVM invocation creates a fresh container, so the maps are built once on the first findLongOption/findBareLongOption call during parsing.
The actual optimization here is smaller than originally estimated: build the lookup maps eagerly at construction time instead of lazily on first lookup, so the cost is paid during container creation rather than during the first parse. This also eliminates the wasted build-invalidate cycles in doGenerateHelp()/doGenerateVersion() (which call findOption() triggering a map build, then immediately invalidate the maps).
Original Problem (corrected)
ProcessedCommand.buildLookupMaps() creates four HashMap instances and populates them from the options list. Currently this happens lazily on the first findOption/findLongOption/findBareLongOption call. The constructor has a wasteful pattern:
constructor → addOption() × N → maps stay null
→ doGenerateHelp() → findOption("help") triggers buildLookupMaps()
→ adds help option → invalidateLookupMaps()
→ doGenerateVersion() → findOption("version") triggers buildLookupMaps()
→ adds version option → invalidateLookupMaps()
→ (end) maps are null again → rebuilt on first parse lookup
Proposed Fix
Add buildLookupMaps() as the last line of the constructor, after all options (including help/version) are added
Change doGenerateHelp()/doGenerateVersion() to use a direct linear scan for the duplicate check instead of findOption(), avoiding the premature map build
Remove the invalidateLookupMaps() calls from those methods (maps have not been built yet)
Impact
Small but clean improvement. Eliminates the lazy-init null-check overhead on every find*Option() call during parsing, and removes the wasted build-invalidate-rebuild cycle during construction.
Note: The bigger win is #577 (cache resolved lazy children), which eliminates the creation of 11 new child ProcessedCommand objects per parse iteration entirely. Implement #577 first, then re-profile to assess if #573 still provides measurable benefit.
Updated Understanding (2026-08-17)
Profiling investigation revealed that the lookup maps are already lazily cached and NOT rebuilt per parse cycle. The
clear()method (called between parses) intentionally does not invalidate the lookup maps. ThebuildLookupMapssamples in the async-profiler output come from:resolveAllLazyChildren()creates brand-newProcessedCommandobjects for each subcommand (with null maps), and their first option lookup triggersbuildLookupMaps(). This is actually Cache resolved lazy children instead of rebuilding child parsers on every parse #577 (cache resolved lazy children).AeshRuntimeRunner), each JVM invocation creates a fresh container, so the maps are built once on the firstfindLongOption/findBareLongOptioncall during parsing.The actual optimization here is smaller than originally estimated: build the lookup maps eagerly at construction time instead of lazily on first lookup, so the cost is paid during container creation rather than during the first parse. This also eliminates the wasted build-invalidate cycles in
doGenerateHelp()/doGenerateVersion()(which callfindOption()triggering a map build, then immediately invalidate the maps).Original Problem (corrected)
ProcessedCommand.buildLookupMaps()creates fourHashMapinstances and populates them from the options list. Currently this happens lazily on the firstfindOption/findLongOption/findBareLongOptioncall. The constructor has a wasteful pattern:Proposed Fix
buildLookupMaps()as the last line of the constructor, after all options (including help/version) are addeddoGenerateHelp()/doGenerateVersion()to use a direct linear scan for the duplicate check instead offindOption(), avoiding the premature map buildinvalidateLookupMaps()calls from those methods (maps have not been built yet)Impact
Small but clean improvement. Eliminates the lazy-init null-check overhead on every
find*Option()call during parsing, and removes the wasted build-invalidate-rebuild cycle during construction.Note: The bigger win is #577 (cache resolved lazy children), which eliminates the creation of 11 new child
ProcessedCommandobjects per parse iteration entirely. Implement #577 first, then re-profile to assess if #573 still provides measurable benefit.