Add large payload bench - #311
Conversation
|
The problem with PHPDocs is that in a lot of cases you're dealing with small strings, not huge strings. Could you make phplrt faster so that it also wins on small texts? |
|
You can extract all phpdoc from some popular libraries (symfony, doctrine, ...) and benchmark time to parse all of them to get realistic performance impact. Generated parsers should be faster in general, but they need to be carefully optimized for PHP performance characteristics, which are very different from C performance characteristics. |
Yes, as I said in previous issue:
In short, it's almost impossible without adding an alternative runtime, only getting close. That's why I started with replacing Hoa in the previous issue. I left PHPDoc parsing for "future features". In more detail, the lexer:
In direct comparison, PCRE2 itself is ~15% faster in phplrt, but due to the objects and amount of data, it takes ~30% more time to construct token objects, assign, analyze, etc.
So:
I have no idea why PHPStan is slowing down on 2kb+, since PHPStan's algo is close to perfect. But the algo is slightly different from here:
phplrt works exactly the same, but:
At this stage, the algo are almost identical, and we get something like:
This avoids creating unnecessary AST objects multiple times in cases where the parser doesn't yet know what's going on. This is precisely why PHPLRT is faster on large datasets, as the current PHPStan implementation has a lot of rollbacks, which lead to unnecessary checks and unnecessary AST constructions (but this isn't certain), like:
But this is also a downside, since phplrt then starts building an AST from the trace. But PHPStan already has one ready.
To summarize, phplrt performs 2 parsing cycles, while PHPStan only performs 1. This makes phplrt slower on small datasets but faster on large ones (because it simply doesn't do extra work during unnecessary rollbacks). However, it does perform "extra work" upfront to prevent this from happening. It also saves additional information about tracing, "expected tokens," and other things, which adds another 10-20% to the processing time needed to get meaningful errors, like this:
It also operates on objects, which adds another layer... I have some ideas on how to speed things up, for example, by implementing a second runtime (effectively duplicating it) that won't generate a trace but will immediately generate an AST. This will speed things up on small volumes, as it will return one cycle of execution. Or getting rid of the recursive descent entirely, replacing it with a loop and inlining all the rules - this should speed up the runtime by 10-15% overall, but it will turn the code into complete crap... In general, I'll try to speed up the parsing even more, but overall the problem is that the functionality that speeds up and makes the parsing more stable is also the same thing that slows down the parsing on small volumes. Something like JIT. It speeds up if there's a lot of data, but slows down if it's a one-time simple operation. |
|
P.S. Well, I also need to lower the PHP version to at least version ^8.1 so that the tool can be considered for future PHPStan 3.x |

Please note that the phplrt implementation doesn't build an AST, as I didn't want to touch original grammar, which adds about 10% to the speed.
The PR only highlights regression and instability in the PHPStan type parser with increasing input payload size, as @ondrejmirtes requested.
Results (~14x times slower):
P.S. In case of size increase (~28x times slower):
etc.