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); } }