diff --git a/bench/ast_resolver_no_cloning_bench.php b/bench/ast_resolver_no_cloning_bench.php new file mode 100644 index 00000000000..e2e94826829 --- /dev/null +++ b/bench/ast_resolver_no_cloning_bench.php @@ -0,0 +1,86 @@ +create(); +$rectorConfig->boot(); + +/** @var AstResolver $astResolver */ +$astResolver = $rectorConfig->make(AstResolver::class); + +$classNames = []; +$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__ . '/../src/PhpParser')); +foreach ($iterator as $fileInfo) { + if ($fileInfo->getExtension() !== 'php') { + continue; + } + + $contents = (string) file_get_contents($fileInfo->getPathname()); + if (preg_match('#^namespace (.+);#m', $contents, $namespaceMatch) !== 1) { + continue; + } + + if (preg_match('#^(?:final |abstract |readonly )*(?:class|interface|trait|enum) (\w+)#m', $contents, $classMatch) !== 1) { + continue; + } + + $classNames[] = $namespaceMatch[1] . '\\' . $classMatch[1]; +} + +$parsedFileNodesProperty = new ReflectionProperty(AstResolver::class, 'parsedFileNodes'); + +$cpuSeconds = static function (): float { + $usage = getrusage(); + return $usage['ru_utime.tv_sec'] + $usage['ru_utime.tv_usec'] / 1_000_000 + + $usage['ru_stime.tv_sec'] + $usage['ru_stime.tv_usec'] / 1_000_000; +}; + +$run = static function () use ($astResolver, $classNames, $parsedFileNodesProperty): int { + $parsedFileNodesProperty->setValue($astResolver, []); + gc_collect_cycles(); + $memoryBefore = memory_get_usage(); + + $resolved = 0; + foreach ($classNames as $className) { + if ($astResolver->resolveClassFromName($className) !== null) { + ++$resolved; + } + } + + gc_collect_cycles(); + $GLOBALS['retainedMemory'] = memory_get_usage() - $memoryBefore; + + return $resolved; +}; + +// warm up autoloading / reflection, excluded from timing +$resolved = $run(); + +$cpuStart = $cpuSeconds(); +for ($repeat = 0; $repeat < REPEAT; ++$repeat) { + $run(); +} + +$cpu = $cpuSeconds() - $cpuStart; + +printf('AstResolver::resolveClassFromName benchmark%s', PHP_EOL); +printf(' classes=%d resolved=%d repeat=%d%s', count($classNames), $resolved, REPEAT, PHP_EOL); +printf(' cpu=%.4fs retained-cache-memory=%.2f MB peak=%.2f MB%s', $cpu, $GLOBALS['retainedMemory'] / 1024 / 1024, memory_get_peak_usage() / 1024 / 1024, PHP_EOL); diff --git a/src/PhpParser/AstResolver.php b/src/PhpParser/AstResolver.php index b6d2a03eb01..37c5f3b400a 100644 --- a/src/PhpParser/AstResolver.php +++ b/src/PhpParser/AstResolver.php @@ -23,8 +23,8 @@ use PHPStan\Reflection\Php\PhpPropertyReflection; use PHPStan\Reflection\ReflectionProvider; use Rector\NodeNameResolver\NodeNameResolver; -use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator; use Rector\NodeTypeResolver\NodeTypeResolver; +use Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver; use Rector\PhpParser\Node\BetterNodeFinder; use Rector\PhpParser\Parser\RectorParser; use Rector\Reflection\MethodReflectionResolver; @@ -48,12 +48,12 @@ final class AstResolver public function __construct( private readonly RectorParser $rectorParser, - private readonly NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator, private readonly NodeNameResolver $nodeNameResolver, private readonly ReflectionProvider $reflectionProvider, private readonly NodeTypeResolver $nodeTypeResolver, private readonly MethodReflectionResolver $methodReflectionResolver, private readonly BetterNodeFinder $betterNodeFinder, + private readonly PHPStanNodeScopeResolver $phpStanNodeScopeResolver ) { } @@ -289,9 +289,9 @@ private function parseFileNameToDecoratedNodes(?string $fileName): array throw $throwable; } - return $this->parsedFileNodes[$fileName] = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile( + return $this->parsedFileNodes[$fileName] = $this->phpStanNodeScopeResolver->processNodes( + $stmts, $fileName, - $stmts ); }