Created
August 16, 2026 06:49
-
-
Save staabm/7154c8b38df6c740f5f9ab58052b0fec to your computer and use it in GitHub Desktop.
instanceof_fast_path_repro.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @ -0,0 +1,133 @@ | |
| <?php | |
| declare(strict_types=1); | |
| /** | |
| * Reproducer for commit 559d1f63893f5262ad3da2cbb748b77d56a8af2f: | |
| * "Defer SAVE_OPLINE() on the INSTANCEOF fast path" | |
| * | |
| * Run this on a build before and after that commit. | |
| * The instance-of cases should get faster after the change. | |
| */ | |
| if (PHP_SAPI !== 'cli') { | |
| fwrite(STDERR, "Run from CLI.\n"); | |
| exit(1); | |
| } | |
| class HitTarget | |
| { | |
| } | |
| interface HitMarker | |
| { | |
| } | |
| final class HitChild extends HitTarget implements HitMarker | |
| { | |
| } | |
| function run_case(string $label, int $rounds, callable $fn): array | |
| { | |
| $times = []; | |
| $sink = 0; | |
| $sink ^= $fn(); | |
| for ($r = 0; $r < $rounds; $r++) { | |
| $start = hrtime(true); | |
| $sink ^= $fn(); | |
| $times[] = (hrtime(true) - $start) / 1e9; | |
| } | |
| sort($times); | |
| return [ | |
| 'label' => $label, | |
| 'best' => $times[0], | |
| 'avg' => array_sum($times) / count($times), | |
| 'sink' => $sink, | |
| ]; | |
| } | |
| $iterations = isset($argv[1]) ? max(1, (int) $argv[1]) : 30_000_000; | |
| $rounds = isset($argv[2]) ? max(1, (int) $argv[2]) : 7; | |
| gc_disable(); | |
| $className = HitTarget::class; | |
| $markerName = HitMarker::class; | |
| $hitTarget = new HitTarget(); | |
| $hitChild = new HitChild(); | |
| $cases = [ | |
| run_case('baseline', $rounds, static function () use ($iterations): int { | |
| $sum = 0; | |
| for ($i = 0; $i < $iterations; $i++) { | |
| if (($i & 1) === 0) { | |
| $sum++; | |
| } | |
| } | |
| return $sum; | |
| }), | |
| run_case('class-hit', $rounds, static function () use ($iterations, $hitTarget, $className): int { | |
| $sum = 0; | |
| for ($i = 0; $i < $iterations; $i++) { | |
| if ($hitTarget instanceof $className) { | |
| $sum++; | |
| } | |
| } | |
| return $sum; | |
| }), | |
| run_case('interface-hit', $rounds, static function () use ($iterations, $hitChild, $markerName): int { | |
| $sum = 0; | |
| for ($i = 0; $i < $iterations; $i++) { | |
| if ($hitChild instanceof $markerName) { | |
| $sum++; | |
| } | |
| } | |
| return $sum; | |
| }), | |
| ]; | |
| $byLabel = []; | |
| foreach ($cases as $row) { | |
| $byLabel[$row['label']] = $row; | |
| } | |
| printf( | |
| "PHP %s\niterations=%d rounds=%d\n\n", | |
| PHP_VERSION, | |
| $iterations, | |
| $rounds | |
| ); | |
| echo str_pad('case', 18) . str_pad('best(s)', 12) . str_pad('avg(s)', 12) . "sink\n"; | |
| echo str_repeat('-', 52) . "\n"; | |
| foreach ($cases as $row) { | |
| printf( | |
| "%-18s%-12.6f%-12.6f%d\n", | |
| $row['label'], | |
| $row['best'], | |
| $row['avg'], | |
| $row['sink'] | |
| ); | |
| } | |
| echo "\ninstanceof / baseline ratios (best time, lower is better):\n"; | |
| printf( | |
| "%-18s %.4fx\n", | |
| 'class-hit', | |
| $byLabel['class-hit']['best'] / $byLabel['baseline']['best'] | |
| ); | |
| printf( | |
| "%-18s %.4fx\n", | |
| 'interface-hit', | |
| $byLabel['interface-hit']['best'] / $byLabel['baseline']['best'] | |
| ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment