Reduce allocations on parser hot paths to improve performance#279
Reduce allocations on parser hot paths to improve performance#279jfmengels merged 4 commits intostil4m:masterfrom
Conversation
|
Thank you ❤️
That's wrong.
Have you benchmarked if this specific step actually makes things faster compared to just removing the |
This is true for positive int literals and string literals, but not for negative int literals. Here's a script that shows the compiled output: https://gist.github.com/dillonkearns/289891a7fa75b95b0336ffa25f0f77d6 $ curl https://gist.githubusercontent.com/dillonkearns/289891a7fa75b95b0336ffa25f0f77d6/raw/7dfdb3a092f3b94858a635d6ddb1da5ee27ceb7e/elm-eq-demo.sh | sh
Elm 0.19.1 --optimize output:
x == -1 => _Utils_eq(x, -1); // not optimized (negation is a prefix expression)
x == 1 => x === 1; // optimized (positive int literal)
s == "hi" => s === 'hello'; // optimized (string literal)
x < 0 => x < 0 // direct comparison
Good point, I agree that this was redundant before so better to just remove it. For reference, these were originally added in a series of commits that referred to "Use JS comparison where possible". I think it was likely attempting to get the Elm compiler output to use I went ahead and removed it in this particular area for now. Thanks for the review! |
|
Thank you, this is a big perf increase! |
This gives about 10-30% faster parsing beyond the results of #278 (15-44% faster between #278 and this PR combined), as measured by running the benchmarks against
~/.elm/0.19.1/.Optimizations
str ++ ""to parser construction time in symbol/keyword functions. Previously this string concatenation ran on every parse attempt. Now it's computed once when the parser is built.< 0instead of== -1since==compiles to_Utils_eqwhich allocates an empty[]on every call.< 0compiles to_Utils_cmpwhich is allocation-free. These checks run thousands of times per file (once per identifier, number, and symbol first-char check).charCodeIsLower,charCodeIsUpper,charCodeIsDigitrange checks directly inunicodeIsAlphaNumOrUnderscoreFast. This eliminates 3 function calls per character on the hottest path in the parser.isNotRelevant(comment character scanning) to useIntcomparison instead ofCharequality via_Utils_eq.subExpressionfirst-character dispatch so number literals go directly tonumberExpressioninstead of falling through tooneOf3which tries two reference parsers first before reaching the number parser.