Files
2meet-data-optimizer-hivepr…/includes/hivepress/class-tmdo-hivepress-benchmark.php
T
wpdev b4400a68e5 chore: initial snapshot of 2meet-data-optimizer-hivepress-addon v0.1.0
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
2026-07-31 05:06:36 +08:00

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 )