Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
204
tests/Performance/PerformanceTimingComparisonTest.php
Normal file
204
tests/Performance/PerformanceTimingComparisonTest.php
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Performance;
|
||||
|
||||
use App\Framework\Core\ValueObjects\Duration;
|
||||
use App\Framework\DateTime\SystemClock;
|
||||
use App\Framework\DateTime\SystemHighResolutionClock;
|
||||
use App\Framework\Performance\EnhancedPerformanceCollector;
|
||||
use App\Framework\Performance\PerformanceCategory;
|
||||
use App\Framework\Performance\PerformanceCollector;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Performance comparison tests between hrtime() and microtime() implementations
|
||||
*/
|
||||
final class PerformanceTimingComparisonTest extends TestCase
|
||||
{
|
||||
private SystemClock $clock;
|
||||
|
||||
private SystemHighResolutionClock $highResClock;
|
||||
|
||||
private PerformanceCollector $microtimeCollector;
|
||||
|
||||
private EnhancedPerformanceCollector $hrtimeCollector;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->clock = new SystemClock();
|
||||
$this->highResClock = new SystemHighResolutionClock($this->clock);
|
||||
|
||||
$this->microtimeCollector = new PerformanceCollector(true);
|
||||
$this->hrtimeCollector = new EnhancedPerformanceCollector($this->clock, $this->highResClock);
|
||||
}
|
||||
|
||||
public function testHrtimePrecisionVsMicrotime(): void
|
||||
{
|
||||
$iterations = 1000;
|
||||
|
||||
// Test a very fast operation multiple times
|
||||
$fastOperation = fn () => array_sum([1, 2, 3, 4, 5]);
|
||||
|
||||
// Benchmark with hrtime()
|
||||
$hrtimeResults = $this->hrtimeCollector->benchmark('hrtime_test', $fastOperation, $iterations);
|
||||
|
||||
// Benchmark with microtime() - simulate multiple measurements
|
||||
$microtimeDurations = [];
|
||||
for ($i = 0; $i < $iterations; $i++) {
|
||||
$start = microtime(true);
|
||||
$fastOperation();
|
||||
$end = microtime(true);
|
||||
$microtimeDurations[] = Duration::fromSeconds($end - $start);
|
||||
}
|
||||
|
||||
// Calculate microtime statistics
|
||||
$microtimeNanos = array_map(fn (Duration $d) => $d->toNanoseconds(), $microtimeDurations);
|
||||
$microtimeAvg = Duration::fromNanoseconds((int) (array_sum($microtimeNanos) / count($microtimeNanos)));
|
||||
|
||||
// Assert precision differences
|
||||
$this->assertInstanceOf(Duration::class, $hrtimeResults['average']);
|
||||
$this->assertInstanceOf(Duration::class, $hrtimeResults['min']);
|
||||
$this->assertInstanceOf(Duration::class, $hrtimeResults['max']);
|
||||
|
||||
// hrtime() should provide more consistent results (lower variance)
|
||||
$hrtimeVariance = $this->calculateDurationVariance([
|
||||
$hrtimeResults['min'],
|
||||
$hrtimeResults['average'],
|
||||
$hrtimeResults['max'],
|
||||
]);
|
||||
|
||||
$microtimeVariance = $this->calculateDurationVariance($microtimeDurations);
|
||||
|
||||
// Output comparison results
|
||||
echo "\n=== Performance Timing Comparison ===\n";
|
||||
echo "Iterations: {$iterations}\n";
|
||||
echo "hrtime() Average: " . $hrtimeResults['average']->toMicroseconds() . " μs\n";
|
||||
echo "microtime() Average: " . $microtimeAvg->toMicroseconds() . " μs\n";
|
||||
echo "hrtime() Min: " . $hrtimeResults['min']->toMicroseconds() . " μs\n";
|
||||
echo "hrtime() Max: " . $hrtimeResults['max']->toMicroseconds() . " μs\n";
|
||||
echo "hrtime() Variance: {$hrtimeVariance} ns²\n";
|
||||
echo "microtime() Variance: {$microtimeVariance} ns²\n";
|
||||
|
||||
// Validate that both systems work
|
||||
$this->assertGreaterThan(0, $hrtimeResults['average']->toNanoseconds());
|
||||
$this->assertGreaterThan(0, $microtimeAvg->toNanoseconds());
|
||||
|
||||
// hrtime() should generally be more precise for very fast operations
|
||||
// Note: Result is only returned for single iteration benchmarks
|
||||
if ($iterations === 1) {
|
||||
$this->assertNotNull($hrtimeResults['result'], 'hrtime benchmark should return result');
|
||||
}
|
||||
}
|
||||
|
||||
public function testNanosecondPrecisionMeasurement(): void
|
||||
{
|
||||
// Test that we can measure very small durations with nanosecond precision
|
||||
$veryFastOp = fn () => 1 + 1;
|
||||
|
||||
$result = $this->hrtimeCollector->measureDuration($veryFastOp);
|
||||
|
||||
$this->assertArrayHasKey('result', $result);
|
||||
$this->assertArrayHasKey('duration', $result);
|
||||
$this->assertInstanceOf(Duration::class, $result['duration']);
|
||||
$this->assertEquals(2, $result['result']);
|
||||
|
||||
// Should be able to measure durations in nanoseconds
|
||||
$nanoseconds = $result['duration']->toNanoseconds();
|
||||
$this->assertIsInt($nanoseconds);
|
||||
$this->assertGreaterThanOrEqual(0, $nanoseconds);
|
||||
|
||||
echo "Very fast operation duration: {$nanoseconds} ns\n";
|
||||
}
|
||||
|
||||
public function testCollectorAccuracyComparison(): void
|
||||
{
|
||||
$operation = function () {
|
||||
// Simulate some work
|
||||
for ($i = 0; $i < 1000; $i++) {
|
||||
$x = sqrt($i);
|
||||
}
|
||||
|
||||
return $x;
|
||||
};
|
||||
|
||||
// Measure with both collectors
|
||||
$this->microtimeCollector->startTiming('test', PerformanceCategory::BENCHMARK);
|
||||
$result1 = $operation();
|
||||
$this->microtimeCollector->endTiming('test');
|
||||
|
||||
$enhancedResult = $this->hrtimeCollector->measure('test_enhanced', PerformanceCategory::BENCHMARK, $operation);
|
||||
|
||||
// Get measurements
|
||||
$microtimeMetric = $this->microtimeCollector->getMetric('test');
|
||||
$hrtimeMetric = $this->hrtimeCollector->getMetric('test_enhanced');
|
||||
|
||||
$this->assertNotNull($microtimeMetric);
|
||||
$this->assertNotNull($hrtimeMetric);
|
||||
|
||||
$microtimeDuration = $microtimeMetric->getAverageDuration();
|
||||
$hrtimeDuration = $hrtimeMetric->getAverageDuration();
|
||||
|
||||
// Both should measure similar durations for the same operation
|
||||
$this->assertInstanceOf(Duration::class, $microtimeDuration);
|
||||
$this->assertInstanceOf(Duration::class, $hrtimeDuration);
|
||||
|
||||
// Results should be the same
|
||||
$this->assertEquals($result1, $enhancedResult);
|
||||
|
||||
echo "Microtime duration: " . $microtimeDuration->toMicroseconds() . " μs\n";
|
||||
echo "hrtime duration: " . $hrtimeDuration->toMicroseconds() . " μs\n";
|
||||
}
|
||||
|
||||
public function testHighResolutionClockFeatures(): void
|
||||
{
|
||||
// Test the additional features of the high-resolution clock
|
||||
$startTime = $this->hrtimeCollector->getHighResTime();
|
||||
usleep(1000); // 1ms sleep
|
||||
$endTime = $this->hrtimeCollector->getHighResTime();
|
||||
|
||||
$this->assertIsInt($startTime);
|
||||
$this->assertIsInt($endTime);
|
||||
$this->assertGreaterThan($startTime, $endTime);
|
||||
|
||||
// Test duration creation
|
||||
$duration = $this->hrtimeCollector->createDurationFromNanoseconds($endTime - $startTime);
|
||||
$this->assertInstanceOf(Duration::class, $duration);
|
||||
|
||||
// Should be approximately 1ms (allowing for system variation)
|
||||
$microseconds = $duration->toMicroseconds();
|
||||
$this->assertGreaterThan(800, $microseconds); // At least 0.8ms
|
||||
$this->assertLessThan(2000, $microseconds); // Less than 2ms
|
||||
|
||||
echo "Sleep measurement: {$microseconds} μs (expected ~1000 μs)\n";
|
||||
}
|
||||
|
||||
public function testRequestDurationAccuracy(): void
|
||||
{
|
||||
// Test total request duration measurement
|
||||
$requestStart = $this->hrtimeCollector->getTotalRequestDuration();
|
||||
$this->assertInstanceOf(Duration::class, $requestStart);
|
||||
|
||||
// Should have some duration since collector was created
|
||||
$this->assertGreaterThan(0, $requestStart->toMicroseconds());
|
||||
|
||||
usleep(500); // 0.5ms
|
||||
|
||||
$requestAfterSleep = $this->hrtimeCollector->getTotalRequestDuration();
|
||||
$this->assertGreaterThan($requestStart->toMicroseconds(), $requestAfterSleep->toMicroseconds());
|
||||
|
||||
echo "Request duration before sleep: " . $requestStart->toMicroseconds() . " μs\n";
|
||||
echo "Request duration after sleep: " . $requestAfterSleep->toMicroseconds() . " μs\n";
|
||||
}
|
||||
|
||||
private function calculateDurationVariance(array $durations): float
|
||||
{
|
||||
$nanoseconds = array_map(fn (Duration $d) => $d->toNanoseconds(), $durations);
|
||||
$mean = array_sum($nanoseconds) / count($nanoseconds);
|
||||
|
||||
$squaredDiffs = array_map(fn ($value) => ($value - $mean) ** 2, $nanoseconds);
|
||||
|
||||
return array_sum($squaredDiffs) / count($squaredDiffs);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user