From 0cf8803608f3e0660edf88b28950f71ec73ceeab Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 20 Oct 2026 23:50:18 +0200 Subject: [PATCH] [perf] Profile the real worker in hotspot profiler via --xdebug Without --xdebug, Rector's XdebugHandler restarts the process without xdebug before the container boots, so the cachegrind only covered the thin pre-restart launcher (proc_close + bootstrap, no processing rows). Passing --xdebug skips the restart and keeps xdebug live for the real in-process run, which --withoutParallel() already keeps in this same process. The profile now ranks the actual FileTypeMapper / NodeScopeResolver / RectorRunner work. --- scripts/rector-hotspot-profile.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/rector-hotspot-profile.php b/scripts/rector-hotspot-profile.php index 1bd231e0d2c..328b99a674c 100644 --- a/scripts/rector-hotspot-profile.php +++ b/scripts/rector-hotspot-profile.php @@ -99,8 +99,12 @@ public function run(): void private function profileRun(string $configPath, string $profileDirectory): string { + // --xdebug is essential: without it Rector's XdebugHandler restarts the process without + // xdebug before the container boots, so the profile would only cover the thin pre-restart + // launcher. With it the restart is skipped and xdebug stays live for the real run, which + // --withoutParallel() (see buildConfig) keeps in this same process - no worker child. $rectorCommand = sprintf( - '%s -d %s -d %s -d %s -d %s %s process --dry-run --no-progress-bar --output-format=json --config=%s', + '%s -d %s -d %s -d %s -d %s %s process --dry-run --no-progress-bar --xdebug --output-format=json --config=%s', escapeshellarg(PHP_BINARY), escapeshellarg('xdebug.mode=profile'), escapeshellarg('xdebug.start_with_request=yes'),