Optimize PMCFG generation#206
Open
adelon wants to merge 2 commits into
Open
Conversation
Avoid materializing full boxed FId alternative lists and then regrouping all productions at the end of PMCFG generation. Store FId alternatives in compact unboxed arrays and accumulate productions directly by result FId and function ID. Keep the existing compression condition for complete Cartesian products, so the generated PMCFG structure is preserved. This reduces allocation and peak memory for parameter-heavy grammars. For example, for the Finnish RGL grammar, compile time drops from 27.2s to 4.3s and peak memory drops from 15 GB to 631 MB, about 6.3x faster and 24x lower peak memory.
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.
Hi @krangelov, this is the PMCFG generation optimization we discussed in Göteborg.
It would be awesome if you could take a look and see if this looks reasonable to you.
Summary
This PR optimizes
GF.Compile.GeneratePMCFG, particularly for parameter-heavy grammars.I looked into profiling and optimizing this after running into memory pressure situations while using the German and Finnish RGL grammars in some GF experiments.
Previously,
getFIdsenumeratedFIdalternatives as boxed lists. Each PMCFG rule then stored its full argument alternatives in aProduction. At the end,getPMCFGgrouped the production set by(result FId, FunId)and applied the Cartesian-product compression.This patch changes the intermediate data structures:
FIdAltsstores alternatives in an unboxed array. They use dense 0-based bounds, so their derived Ord matches the previous list ordering of alternatives.FIdFactorsstores weighted parameter-choice factors.PMCFGEnvstores productions already grouped by(FId, FunId).ProdGroupkeeps the distinct argument products, per-argument unions, andareaSum.This avoids constructing a large boxed
Set Productionand then rebuilding the same grouping at the end. Compression behaviour is still preserved.The following are probably the most correctness-sensitive to review:
fIdAltsFromFactors, which does the enumeration into an unboxed array, and replaces an enumeration viareverse (solutions (variants schema) ())ProdGroupfinalization, which replaces the old grouping ingetPMCFGMeasurements
I benchmarked compile/link runs for 10 RGL grammars (using GHC 9.6.7 and
-O1). Finnish improved the most with 24x lower peak memory and 6.3x faster compilation. Simpler grammars like English are essentially unchanged.Testing
I tried to keep the changes as local as possible and preserve as much of the existing behaviour as I could.
The code builds for me with
cabal build allunder GHC 9.6.7, as well asstack buildfor the Stack configs from GHC 8.4.4 through GHC 9.6.7. The test suite also passes.I have a separate "scratchpad" copy of GF where I tested/compared the optimized and original PMCFG generation with some local test hooks. I also compiled 46 RGL grammars with both the 3.12 release and the optimized version, and the resulting PGF files were identical.
It looks like there might be some edge cases where the current Cartesian-product compression is a bit too aggressive. But this was handled the same in the previous version. I will look at this in more detail and maybe open a separate issue/PR for that later.