- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
167 lines
5.2 KiB
PHP
167 lines
5.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Performance;
|
|
|
|
use App\Framework\Performance\Contracts\PerformanceCollectorInterface;
|
|
use App\Framework\Performance\PerformanceCategory;
|
|
use App\Framework\Core\ValueObjects\Duration;
|
|
|
|
/**
|
|
* Base class for performance tests
|
|
*
|
|
* Provides utilities for benchmarking and performance measurement
|
|
*/
|
|
abstract readonly class PerformanceTestCase
|
|
{
|
|
public function __construct(
|
|
protected PerformanceCollectorInterface $collector
|
|
) {}
|
|
|
|
/**
|
|
* Benchmark a callable operation
|
|
*
|
|
* @param callable $operation The operation to benchmark
|
|
* @param int $iterations Number of iterations to run
|
|
* @param string $name Benchmark name for reporting
|
|
* @return PerformanceBenchmarkResult
|
|
*/
|
|
protected function benchmark(
|
|
callable $operation,
|
|
int $iterations = 1000,
|
|
string $name = 'benchmark'
|
|
): PerformanceBenchmarkResult {
|
|
// Warmup run
|
|
$operation();
|
|
|
|
// Clear any existing metrics
|
|
gc_collect_cycles();
|
|
|
|
$durations = [];
|
|
$memoryUsages = [];
|
|
$startMemory = memory_get_usage(true);
|
|
$startTime = microtime(true);
|
|
|
|
for ($i = 0; $i < $iterations; $i++) {
|
|
$iterationStart = hrtime(true);
|
|
$iterationMemoryStart = memory_get_usage(true);
|
|
|
|
$operation();
|
|
|
|
$iterationEnd = hrtime(true);
|
|
$iterationMemoryEnd = memory_get_usage(true);
|
|
|
|
$durations[] = ($iterationEnd - $iterationStart) / 1e6; // Convert to milliseconds
|
|
$memoryUsages[] = $iterationMemoryEnd - $iterationMemoryStart;
|
|
}
|
|
|
|
$endTime = microtime(true);
|
|
$endMemory = memory_get_usage(true);
|
|
|
|
$totalTime = ($endTime - $startTime) * 1000; // milliseconds
|
|
$avgTime = $totalTime / $iterations;
|
|
$minTime = min($durations);
|
|
$maxTime = max($durations);
|
|
$medianTime = $this->calculateMedian($durations);
|
|
$p95Time = $this->calculatePercentile($durations, 95);
|
|
$p99Time = $this->calculatePercentile($durations, 99);
|
|
|
|
$avgMemory = array_sum($memoryUsages) / count($memoryUsages);
|
|
$peakMemory = $endMemory - $startMemory;
|
|
|
|
$operationsPerSecond = 1000 / $avgTime;
|
|
|
|
return new PerformanceBenchmarkResult(
|
|
name: $name,
|
|
iterations: $iterations,
|
|
totalTimeMs: $totalTime,
|
|
avgTimeMs: $avgTime,
|
|
minTimeMs: $minTime,
|
|
maxTimeMs: $maxTime,
|
|
medianTimeMs: $medianTime,
|
|
p95TimeMs: $p95Time,
|
|
p99TimeMs: $p99Time,
|
|
avgMemoryBytes: (int) $avgMemory,
|
|
peakMemoryBytes: $peakMemory,
|
|
operationsPerSecond: $operationsPerSecond
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Assert performance meets threshold
|
|
*/
|
|
protected function assertPerformanceThreshold(
|
|
PerformanceBenchmarkResult $result,
|
|
float $maxAvgTimeMs,
|
|
?int $maxMemoryBytes = null
|
|
): void {
|
|
if ($result->avgTimeMs > $maxAvgTimeMs) {
|
|
throw new \RuntimeException(
|
|
"Performance threshold exceeded: {$result->name} took {$result->avgTimeMs}ms (limit: {$maxAvgTimeMs}ms)"
|
|
);
|
|
}
|
|
|
|
if ($maxMemoryBytes !== null && $result->peakMemoryBytes > $maxMemoryBytes) {
|
|
$peakMb = round($result->peakMemoryBytes / 1024 / 1024, 2);
|
|
$limitMb = round($maxMemoryBytes / 1024 / 1024, 2);
|
|
throw new \RuntimeException(
|
|
"Memory threshold exceeded: {$result->name} used {$peakMb}MB (limit: {$limitMb}MB)"
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Record benchmark result in performance collector
|
|
*/
|
|
protected function recordBenchmark(
|
|
PerformanceBenchmarkResult $result,
|
|
PerformanceCategory $category = PerformanceCategory::CUSTOM
|
|
): void {
|
|
$this->collector->recordMetric(
|
|
"benchmark_{$result->name}",
|
|
$category,
|
|
$result->avgTimeMs,
|
|
[
|
|
'iterations' => $result->iterations,
|
|
'min_ms' => $result->minTimeMs,
|
|
'max_ms' => $result->maxTimeMs,
|
|
'median_ms' => $result->medianTimeMs,
|
|
'p95_ms' => $result->p95TimeMs,
|
|
'p99_ms' => $result->p99TimeMs,
|
|
'ops_per_sec' => $result->operationsPerSecond,
|
|
'memory_avg_mb' => round($result->avgMemoryBytes / 1024 / 1024, 2),
|
|
'memory_peak_mb' => round($result->peakMemoryBytes / 1024 / 1024, 2)
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Calculate median value
|
|
*/
|
|
private function calculateMedian(array $values): float
|
|
{
|
|
sort($values);
|
|
$count = count($values);
|
|
$middle = floor($count / 2);
|
|
|
|
if ($count % 2 === 0) {
|
|
return ($values[$middle - 1] + $values[$middle]) / 2;
|
|
}
|
|
|
|
return $values[$middle];
|
|
}
|
|
|
|
/**
|
|
* Calculate percentile value
|
|
*/
|
|
private function calculatePercentile(array $values, int $percentile): float
|
|
{
|
|
sort($values);
|
|
$count = count($values);
|
|
$index = ceil($count * ($percentile / 100)) - 1;
|
|
|
|
return $values[(int) max(0, min($index, $count - 1))];
|
|
}
|
|
}
|