From 4f3c83ec552533870574645198d6a8042405c5b9 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 15 May 2024 01:51:59 +0700 Subject: [PATCH 1/6] [Performance] Ensure call $reflector->reflectAllClasses() once on Worker take 3 --- rector.php | 2 +- src/Application/ApplicationFileProcessor.php | 5 ++ src/Caching/Enum/CacheKey.php | 5 ++ src/Console/Command/ProcessCommand.php | 7 ++ .../LazyContainerFactory.php | 7 +- .../DynamicSourceLocatorProvider.php | 65 ++++++++++++++++++- .../DynamicSourceLocatorDecorator.php | 5 ++ 7 files changed, 92 insertions(+), 4 deletions(-) diff --git a/rector.php b/rector.php index e1d06692eaa..8c31af20b24 100644 --- a/rector.php +++ b/rector.php @@ -29,8 +29,8 @@ __DIR__ . '/rules', __DIR__ . '/rules-tests', __DIR__ . '/tests', - __DIR__ . '/utils', __DIR__ . '/config', + __DIR__ . '/utils', ]) ->withRootFiles() ->withImportNames(removeUnusedImports: true) diff --git a/src/Application/ApplicationFileProcessor.php b/src/Application/ApplicationFileProcessor.php index 5588508074b..1ca5e13829e 100644 --- a/src/Application/ApplicationFileProcessor.php +++ b/src/Application/ApplicationFileProcessor.php @@ -9,6 +9,7 @@ use Rector\Configuration\Option; use Rector\Configuration\Parameter\SimpleParameterProvider; use Rector\Configuration\VendorMissAnalyseGuard; +use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider; use Rector\Parallel\Application\ParallelFileProcessor; use Rector\Provider\CurrentFileProvider; use Rector\Testing\PHPUnit\StaticPHPUnitEnvironment; @@ -50,6 +51,7 @@ public function __construct( private readonly FileProcessor $fileProcessor, private readonly ArrayParametersMerger $arrayParametersMerger, private readonly VendorMissAnalyseGuard $vendorMissAnalyseGuard, + private readonly DynamicSourceLocatorProvider $dynamicSourceLocatorProvider ) { } @@ -71,6 +73,9 @@ public function run(Configuration $configuration, InputInterface $input): Proces return new ProcessResult([], []); } + // trigger cache class names collection + $this->dynamicSourceLocatorProvider->provide(); + $this->configureCustomErrorHandler(); /** diff --git a/src/Caching/Enum/CacheKey.php b/src/Caching/Enum/CacheKey.php index 66512c05905..df5df985508 100644 --- a/src/Caching/Enum/CacheKey.php +++ b/src/Caching/Enum/CacheKey.php @@ -18,4 +18,9 @@ final class CacheKey * @var string */ public const FILE_HASH_KEY = 'file_hash'; + + /** + * @var string + */ + public const CLASSNAMES_HASH_KEY = 'classnames_hash'; } diff --git a/src/Console/Command/ProcessCommand.php b/src/Console/Command/ProcessCommand.php index 5c2b9655289..dd9c7c3d0f6 100644 --- a/src/Console/Command/ProcessCommand.php +++ b/src/Console/Command/ProcessCommand.php @@ -6,7 +6,9 @@ use Rector\Application\ApplicationFileProcessor; use Rector\Autoloading\AdditionalAutoloader; +use Rector\Caching\Cache; use Rector\Caching\Detector\ChangedFilesDetector; +use Rector\Caching\Enum\CacheKey; use Rector\ChangesReporting\Output\JsonOutputFormatter; use Rector\Configuration\ConfigInitializer; use Rector\Configuration\ConfigurationFactory; @@ -37,6 +39,7 @@ public function __construct( private readonly SymfonyStyle $symfonyStyle, private readonly MemoryLimiter $memoryLimiter, private readonly ConfigurationFactory $configurationFactory, + private readonly Cache $cache ) { parent::__construct(); } @@ -72,6 +75,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $paths = $configuration->getPaths(); + // ensure clear classnames collection caches on repetitive call + $key = CacheKey::CLASSNAMES_HASH_KEY . '_' . $this->dynamicSourceLocatorDecorator->getCacheClassNameKey(); + $this->cache->clean($key); + // 1. add files and directories to static locator $this->dynamicSourceLocatorDecorator->addPaths($paths); if ($this->dynamicSourceLocatorDecorator->isPathsEmpty()) { diff --git a/src/DependencyInjection/LazyContainerFactory.php b/src/DependencyInjection/LazyContainerFactory.php index 10472589b8a..1ffc1937905 100644 --- a/src/DependencyInjection/LazyContainerFactory.php +++ b/src/DependencyInjection/LazyContainerFactory.php @@ -180,6 +180,7 @@ use Rector\StaticTypeMapper\PhpParser\StringNodeMapper; use Rector\StaticTypeMapper\PhpParser\UnionTypeNodeMapper; use Rector\StaticTypeMapper\StaticTypeMapper; +use Rector\Util\FileHasher; use Rector\Utils\Command\MissingInSetCommand; use Rector\Utils\Command\OutsideAnySetCommand; use Symfony\Component\Console\Application; @@ -469,7 +470,11 @@ static function (Container $container): DynamicSourceLocatorProvider { $rectorConfig->afterResolving( DynamicSourceLocatorProvider::class, static function (DynamicSourceLocatorProvider $dynamicSourceLocatorProvider, Container $container): void { - $dynamicSourceLocatorProvider->autowire($container->make(ReflectionProvider::class)); + $dynamicSourceLocatorProvider->autowire( + $container->make(ReflectionProvider::class), + $container->make(Cache::class), + $container->make(FileHasher::class) + ); } ); diff --git a/src/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php b/src/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php index 165e1868db5..014ae82ec24 100644 --- a/src/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php +++ b/src/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php @@ -14,8 +14,11 @@ use PHPStan\Reflection\BetterReflection\SourceLocator\OptimizedDirectorySourceLocatorFactory; use PHPStan\Reflection\BetterReflection\SourceLocator\OptimizedSingleFileSourceLocator; use PHPStan\Reflection\ReflectionProvider; +use Rector\Caching\Cache; +use Rector\Caching\Enum\CacheKey; use Rector\Contract\DependencyInjection\ResetableInterface; use Rector\Testing\PHPUnit\StaticPHPUnitEnvironment; +use Rector\Util\FileHasher; /** * @api phpstan external @@ -36,15 +39,25 @@ final class DynamicSourceLocatorProvider implements ResetableInterface private ReflectionProvider $reflectionProvider; + private Cache $cache; + + private FileHasher $fileHasher; + public function __construct( private readonly FileNodesFetcher $fileNodesFetcher, private readonly OptimizedDirectorySourceLocatorFactory $optimizedDirectorySourceLocatorFactory ) { } - public function autowire(ReflectionProvider $reflectionProvider): void + public function autowire( + ReflectionProvider $reflectionProvider, + Cache $cache, + FileHasher $fileHasher + ): void { $this->reflectionProvider = $reflectionProvider; + $this->cache = $cache; + $this->fileHasher = $fileHasher; } public function setFilePath(string $filePath): void @@ -52,6 +65,22 @@ public function setFilePath(string $filePath): void $this->filePaths = [$filePath]; } + public function getCacheClassNameKey(): string + { + $paths = []; + + foreach ($this->filePaths as $filePath) { + $paths[] = (string) realpath($filePath); + } + + foreach ($this->directories as $directory) { + $paths[] = (string) realpath($directory); + } + + $paths = array_filter($paths); + return CacheKey::CLASSNAMES_HASH_KEY . '_' . $this->fileHasher->hash((string) json_encode($paths)); + } + /** * @param string[] $files */ @@ -109,6 +138,19 @@ public function reset(): void $this->aggregateSourceLocator = null; } + /** + * @param class-string[] $classNamesCache + */ + private function locateCachedClassNames(array $classNamesCache): void + { + foreach ($classNamesCache as $classNameCache) { + try { + $this->reflectionProvider->getClass($classNameCache); + } catch (ClassNotFoundException) { + } + } + } + /** * @param OptimizedSingleFileSourceLocator[]|NewOptimizedDirectorySourceLocator[] $sourceLocators */ @@ -123,19 +165,38 @@ private function collectClasses(AggregateSourceLocator $aggregateSourceLocator, return; } + $key = CacheKey::CLASSNAMES_HASH_KEY . '_' . $this->getCacheClassNameKey(); + $classNamesCache = $this->cache->load($key, CacheKey::CLASSNAMES_HASH_KEY); + + if (is_string($classNamesCache)) { + $classNamesCache = json_decode($classNamesCache); + if (is_array($classNamesCache)) { + $this->locateCachedClassNames($classNamesCache); + return; + } + } + $reflector = new DefaultReflector($aggregateSourceLocator); + $classNames = []; // trigger collect "classes" on get class on locate identifier try { $reflections = $reflector->reflectAllClasses(); foreach ($reflections as $reflection) { + $className = $reflection->getName(); + // make 'classes' collection try { - $this->reflectionProvider->getClass($reflection->getName()); + $this->reflectionProvider->getClass($className); } catch (ClassNotFoundException) { + continue; } + + $classNames[] = $className; } } catch (CouldNotReadFileException) { } + + $this->cache->save($key, CacheKey::CLASSNAMES_HASH_KEY, json_encode($classNames)); } } diff --git a/src/StaticReflection/DynamicSourceLocatorDecorator.php b/src/StaticReflection/DynamicSourceLocatorDecorator.php index 7263db4371d..dde4bd5c73b 100644 --- a/src/StaticReflection/DynamicSourceLocatorDecorator.php +++ b/src/StaticReflection/DynamicSourceLocatorDecorator.php @@ -21,6 +21,11 @@ public function __construct( ) { } + public function getCacheClassNameKey(): string + { + return $this->dynamicSourceLocatorProvider->getCacheClassNameKey(); + } + /** * @param string[] $paths */ From 1381ed0ad4a221af95953ea4cabe26d2b0e511d8 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 15 May 2024 01:55:41 +0700 Subject: [PATCH 2/6] config --- rector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rector.php b/rector.php index 8c31af20b24..e1d06692eaa 100644 --- a/rector.php +++ b/rector.php @@ -29,8 +29,8 @@ __DIR__ . '/rules', __DIR__ . '/rules-tests', __DIR__ . '/tests', - __DIR__ . '/config', __DIR__ . '/utils', + __DIR__ . '/config', ]) ->withRootFiles() ->withImportNames(removeUnusedImports: true) From d403e42a64216da3d9393204f09f3d14ae889fff Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 15 May 2024 02:05:04 +0700 Subject: [PATCH 3/6] show progress bar first --- src/Application/ApplicationFileProcessor.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Application/ApplicationFileProcessor.php b/src/Application/ApplicationFileProcessor.php index 1ca5e13829e..a2b7623e06d 100644 --- a/src/Application/ApplicationFileProcessor.php +++ b/src/Application/ApplicationFileProcessor.php @@ -73,9 +73,6 @@ public function run(Configuration $configuration, InputInterface $input): Proces return new ProcessResult([], []); } - // trigger cache class names collection - $this->dynamicSourceLocatorProvider->provide(); - $this->configureCustomErrorHandler(); /** @@ -103,6 +100,9 @@ public function run(Configuration $configuration, InputInterface $input): Proces $preFileCallback = null; } + // trigger cache class names collection + $this->dynamicSourceLocatorProvider->provide(); + if ($configuration->isParallel()) { $processResult = $this->runParallel($filePaths, $configuration, $input, $postFileCallback); } else { From 018a33ac8720f0acf2de61919c9060b10bb67752 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 15 May 2024 02:17:21 +0700 Subject: [PATCH 4/6] clear early cache class names collection on ApplicationFileProcessor --- src/Application/ApplicationFileProcessor.php | 9 ++++++++- src/Console/Command/ProcessCommand.php | 9 +-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Application/ApplicationFileProcessor.php b/src/Application/ApplicationFileProcessor.php index a2b7623e06d..4d6416b1c61 100644 --- a/src/Application/ApplicationFileProcessor.php +++ b/src/Application/ApplicationFileProcessor.php @@ -5,7 +5,9 @@ namespace Rector\Application; use Nette\Utils\FileSystem as UtilsFileSystem; +use Rector\Caching\Cache; use Rector\Caching\Detector\ChangedFilesDetector; +use Rector\Caching\Enum\CacheKey; use Rector\Configuration\Option; use Rector\Configuration\Parameter\SimpleParameterProvider; use Rector\Configuration\VendorMissAnalyseGuard; @@ -51,7 +53,8 @@ public function __construct( private readonly FileProcessor $fileProcessor, private readonly ArrayParametersMerger $arrayParametersMerger, private readonly VendorMissAnalyseGuard $vendorMissAnalyseGuard, - private readonly DynamicSourceLocatorProvider $dynamicSourceLocatorProvider + private readonly DynamicSourceLocatorProvider $dynamicSourceLocatorProvider, + private readonly Cache $cache ) { } @@ -73,6 +76,10 @@ public function run(Configuration $configuration, InputInterface $input): Proces return new ProcessResult([], []); } + // ensure clear classnames collection caches on repetitive call + $key = CacheKey::CLASSNAMES_HASH_KEY . '_' . $this->dynamicSourceLocatorProvider->getCacheClassNameKey(); + $this->cache->clean($key); + $this->configureCustomErrorHandler(); /** diff --git a/src/Console/Command/ProcessCommand.php b/src/Console/Command/ProcessCommand.php index dd9c7c3d0f6..502b9425bab 100644 --- a/src/Console/Command/ProcessCommand.php +++ b/src/Console/Command/ProcessCommand.php @@ -6,9 +6,7 @@ use Rector\Application\ApplicationFileProcessor; use Rector\Autoloading\AdditionalAutoloader; -use Rector\Caching\Cache; use Rector\Caching\Detector\ChangedFilesDetector; -use Rector\Caching\Enum\CacheKey; use Rector\ChangesReporting\Output\JsonOutputFormatter; use Rector\Configuration\ConfigInitializer; use Rector\Configuration\ConfigurationFactory; @@ -38,8 +36,7 @@ public function __construct( private readonly OutputFormatterCollector $outputFormatterCollector, private readonly SymfonyStyle $symfonyStyle, private readonly MemoryLimiter $memoryLimiter, - private readonly ConfigurationFactory $configurationFactory, - private readonly Cache $cache + private readonly ConfigurationFactory $configurationFactory ) { parent::__construct(); } @@ -75,10 +72,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $paths = $configuration->getPaths(); - // ensure clear classnames collection caches on repetitive call - $key = CacheKey::CLASSNAMES_HASH_KEY . '_' . $this->dynamicSourceLocatorDecorator->getCacheClassNameKey(); - $this->cache->clean($key); - // 1. add files and directories to static locator $this->dynamicSourceLocatorDecorator->addPaths($paths); if ($this->dynamicSourceLocatorDecorator->isPathsEmpty()) { From 901f08e07fbfecfe4c021863cfa7b3c62a00f2be Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 15 May 2024 02:19:29 +0700 Subject: [PATCH 5/6] fix phpstan --- .../SourceLocatorProvider/DynamicSourceLocatorProvider.php | 2 ++ src/StaticReflection/DynamicSourceLocatorDecorator.php | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php b/src/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php index 014ae82ec24..0ee74483263 100644 --- a/src/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php +++ b/src/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php @@ -176,6 +176,8 @@ private function collectClasses(AggregateSourceLocator $aggregateSourceLocator, } } + dump('here'); + $reflector = new DefaultReflector($aggregateSourceLocator); $classNames = []; diff --git a/src/StaticReflection/DynamicSourceLocatorDecorator.php b/src/StaticReflection/DynamicSourceLocatorDecorator.php index dde4bd5c73b..7263db4371d 100644 --- a/src/StaticReflection/DynamicSourceLocatorDecorator.php +++ b/src/StaticReflection/DynamicSourceLocatorDecorator.php @@ -21,11 +21,6 @@ public function __construct( ) { } - public function getCacheClassNameKey(): string - { - return $this->dynamicSourceLocatorProvider->getCacheClassNameKey(); - } - /** * @param string[] $paths */ From 174df1ffe630810058c99c69be739511744a43bb Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 15 May 2024 02:19:44 +0700 Subject: [PATCH 6/6] fix phpstan --- .../SourceLocatorProvider/DynamicSourceLocatorProvider.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php b/src/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php index 0ee74483263..014ae82ec24 100644 --- a/src/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php +++ b/src/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php @@ -176,8 +176,6 @@ private function collectClasses(AggregateSourceLocator $aggregateSourceLocator, } } - dump('here'); - $reflector = new DefaultReflector($aggregateSourceLocator); $classNames = [];