gmdate('c'), 'php_version' => PHP_VERSION, 'php_sapi' => PHP_SAPI, 'os' => $os, 'architecture' => php_uname('m'), 'cpu' => $cpu, 'memory' => $memory, 'opcache_cli' => ini_get('opcache.enable_cli') ?: '0', 'memory_limit' => ini_get('memory_limit') ?: 'unknown', 'extensions' => array_values(array_intersect(['json', 'openssl', 'zlib', 'mbstring', 'pdo_sqlite'], get_loaded_extensions())), 'timezone' => date_default_timezone_get(), 'clock' => 'hrtime(true)', 'rounds' => $GLOBALS['rounds'] ?? 7, ]; } $definitions = asamb_benchmark_definitions($workDir); $results = []; $globalChecksum = 0; foreach ($definitions as $slug => $definition) { $iterations = (int)$definition['iterations']; $variants = $definition['variants']; $samples = []; foreach ($variants as $name => $_) { $samples[$name] = []; } // Warm-up each variant to reduce first-run effects. foreach ($variants as $callable) { for ($i = 0; $i < max(1, (int)floor($iterations / 8)); $i++) { $globalChecksum ^= (int)$callable(); } } for ($round = 0; $round < $rounds; $round++) { $names = array_keys($variants); // Deterministic rotation changes execution order without hiding reproducibility. $offset = $round % count($names); $names = array_merge(array_slice($names, $offset), array_slice($names, 0, $offset)); if ($round % 2 === 1) { $names = array_reverse($names); } foreach ($names as $name) { $callable = $variants[$name]; gc_collect_cycles(); $start = hrtime(true); $checksum = 0; for ($i = 0; $i < $iterations; $i++) { $checksum ^= (int)$callable(); } $elapsed = hrtime(true) - $start; $globalChecksum ^= $checksum; $samples[$name][] = $elapsed / $iterations; } } $variantResults = []; foreach ($samples as $name => $values) { $median = percentile($values, 0.5); $variantResults[$name] = [ 'median_ns_per_op' => round($median, 2), 'p25_ns_per_op' => round(percentile($values, 0.25), 2), 'p75_ns_per_op' => round(percentile($values, 0.75), 2), 'ops_per_second' => $median > 0 ? round(1_000_000_000 / $median, 2) : 0, 'samples_ns_per_op' => array_map(static fn($v) => round((float)$v, 2), $values), 'extra' => $definition['extra'][$name] ?? [], ]; } uasort($variantResults, static fn($a, $b) => $a['median_ns_per_op'] <=> $b['median_ns_per_op']); $winner = array_key_first($variantResults); $slowest = array_key_last($variantResults); $winnerMedian = $variantResults[$winner]['median_ns_per_op']; $slowestMedian = $variantResults[$slowest]['median_ns_per_op']; $results[$slug] = [ 'slug' => $slug, 'iterations_per_sample' => $iterations, 'rounds' => $rounds, 'winner' => $winner, 'slowest' => $slowest, 'spread_percent' => $winnerMedian > 0 ? round((($slowestMedian / $winnerMedian) - 1) * 100, 2) : 0, 'variants' => $variantResults, ]; fwrite(STDOUT, sprintf("%-34s %s\n", $slug, $winner)); } $payload = [ 'schema_version' => 1, 'environment' => environment_snapshot(), 'checksum' => $globalChecksum, 'studies' => $results, ]; file_put_contents($outputDir . '/results.json', json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR)); // One compact CSV with one row per variant for independent reuse. $csv = fopen($outputDir . '/results.csv', 'wb'); fputcsv($csv, ['study', 'variant', 'median_ns_per_op', 'p25_ns_per_op', 'p75_ns_per_op', 'ops_per_second', 'winner']); foreach ($results as $study) { foreach ($study['variants'] as $name => $variant) { fputcsv($csv, [$study['slug'], $name, $variant['median_ns_per_op'], $variant['p25_ns_per_op'], $variant['p75_ns_per_op'], $variant['ops_per_second'], $name === $study['winner'] ? 'yes' : 'no']); } } fclose($csv); fwrite(STDOUT, "Results written to {$outputDir}\n");