$name, 'baseline_ms' => $baseline_ms, 'target_ms' => $target_ms, 'ratio' => $target_ms > 0.0 ? round( $baseline_ms / $target_ms, 2 ) : 0.0, 'iterations' => $iterations, ); } /** * Run a callable N times, return mean elapsed milliseconds. * * @param callable $callback Callable under test. * @param int $iterations Iteration count. */ public static function run( callable $callback, int $iterations ): float { $total = 0.0; for ( $i = 0; $i < $iterations; $i++ ) { $start = microtime( true ); $callback(); $total += ( microtime( true ) - $start ) * 1000.0; } return round( $total / $iterations, 3 ); } /** * Run a sequence of comparisons and produce a summary report. * * @param array $samples Sample list. * * @return array{samples:array>, geomean_ratio:float, sample_count:int} */ public static function run_suite( array $samples ): array { $results = array(); $ratios = array(); foreach ( $samples as $sample ) { if ( ! isset( $sample['name'], $sample['baseline'], $sample['target'] ) ) { continue; } $result = self::compare( (string) $sample['name'], $sample['baseline'], $sample['target'], (int) ( $sample['iterations'] ?? self::DEFAULT_ITERATIONS ) ); $results[] = $result; if ( $result['ratio'] > 0.0 ) { $ratios[] = $result['ratio']; } } return array( 'samples' => $results, 'geomean_ratio' => self::geometric_mean( $ratios ), 'sample_count' => count( $results ), ); } /** * Geometric mean — preferred summary statistic for ratios because it * doesn't bias toward outliers like arithmetic mean does. * * @param array $values Ratios. */ public static function geometric_mean( array $values ): float { if ( empty( $values ) ) { return 0.0; } $product = 1.0; foreach ( $values as $v ) { $product *= max( 0.0001, (float) $v ); } return round( pow( $product, 1.0 / count( $values ) ), 2 ); } } } // end if ( ! class_exists )