b4400a68e5
Baseline before backporting wp-data-optimizer v3.0.1-v3.4.6. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
129 lines
4.0 KiB
PHP
129 lines
4.0 KiB
PHP
<?php
|
|
/**
|
|
* HivePress hot-path benchmark — minimal before/after timing wrapper.
|
|
*
|
|
* Runs each provided sample query N times against a baseline (postmeta) and
|
|
* a target (hot zone / shadow table) and returns elapsed times + ratio. No
|
|
* fancy statistics — just `microtime(true)` deltas, mean, ratio.
|
|
*
|
|
* The CLI command (Sprint 4) will pass real production-like queries; for
|
|
* unit tests we exercise the timing harness with synthetic callables that
|
|
* sleep deterministically.
|
|
*
|
|
* Per Karpathy guideline: a stopwatch, not a profiler. Detailed trace
|
|
* exists in `wpdo_benchmarks` table when callers want history.
|
|
*
|
|
* @package WP_Data_Optimizer
|
|
* @since 3.0.0
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
if ( ! class_exists( 'TMDO_HivePress_Benchmark' ) ) {
|
|
|
|
/**
|
|
* Minimal benchmark harness.
|
|
*/
|
|
final class TMDO_HivePress_Benchmark {
|
|
|
|
/** Default iteration count per sample. */
|
|
public const DEFAULT_ITERATIONS = 50;
|
|
|
|
/**
|
|
* Run a single sample comparison.
|
|
*
|
|
* Each callable is invoked $iterations times. Returns mean ms for
|
|
* baseline, mean ms for target, and the speedup ratio (baseline/target).
|
|
*
|
|
* @param string $name Sample name (e.g. 'listing_search_5_filters').
|
|
* @param callable $baseline Callable representing the postmeta path.
|
|
* @param callable $target Callable representing the hot-zone path.
|
|
* @param int $iterations Iteration count (default 50).
|
|
*
|
|
* @return array{name:string, baseline_ms:float, target_ms:float, ratio:float, iterations:int}
|
|
*/
|
|
public static function compare( string $name, callable $baseline, callable $target, int $iterations = self::DEFAULT_ITERATIONS ): array {
|
|
$iterations = max( 1, $iterations );
|
|
$baseline_ms = self::run( $baseline, $iterations );
|
|
$target_ms = self::run( $target, $iterations );
|
|
|
|
return array(
|
|
'name' => $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<int,array{name:string, baseline:callable, target:callable, iterations?:int}> $samples Sample list.
|
|
*
|
|
* @return array{samples:array<int,array<string,mixed>>, 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<int,float> $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 )
|