Skip to content

Commit 7658e65

Browse files
committed
Refactor Benchmark classes for improved memory tracking and analysis; enhance output formatting and add detailed statistics display
1 parent dd3e4b5 commit 7658e65

File tree

4 files changed

+165
-107
lines changed

4 files changed

+165
-107
lines changed

src/Benchmark/Utils/BenchmarkAnalyzer.php

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,69 +35,69 @@ public function analyze(array $runs): array
3535
];
3636
}
3737

38-
private function filterOutliers(array $runs): array
38+
private function filterOutliers(array $runs): array
3939
{
4040
$times = array_column($runs, 'duration_ms');
41-
41+
4242
if (count($times) < 50) {
4343
return $runs;
4444
}
45-
45+
4646
$mean = array_sum($times) / count($times);
4747
$variance = array_sum(array_map(fn($x) => pow($x - $mean, 2), $times)) / count($times);
4848
$stdDev = sqrt($variance);
49-
49+
5050
$threshold = $this->config->getOutlierThreshold();
5151
$filteredRuns = [];
5252
$outliersRemoved = 0;
53-
53+
5454
foreach ($runs as $run) {
5555
$zScore = abs(($run['duration_ms'] - $mean) / $stdDev);
56-
56+
5757
if ($zScore <= $threshold) {
5858
$filteredRuns[] = $run;
5959
} else {
6060
$outliersRemoved++;
6161
}
6262
}
63-
63+
6464
if (count($filteredRuns) < $this->config->getMinRunsAfterFilter()) {
6565
return $this->filterOutliersWithThreshold($runs, $threshold * 1.5);
6666
}
67-
67+
6868
if (!empty($filteredRuns)) {
6969
$filteredRuns[0]['outliers_removed'] = $outliersRemoved;
7070
$filteredRuns[0]['original_run_count'] = count($runs);
7171
}
72-
72+
7373
return $filteredRuns;
7474
}
75-
75+
7676
private function filterOutliersWithThreshold(array $runs, float $threshold): array
7777
{
7878
$times = array_column($runs, 'duration_ms');
7979
$mean = array_sum($times) / count($times);
8080
$variance = array_sum(array_map(fn($x) => pow($x - $mean, 2), $times)) / count($times);
8181
$stdDev = sqrt($variance);
82-
82+
8383
$filteredRuns = [];
8484
$outliersRemoved = 0;
85-
85+
8686
foreach ($runs as $run) {
8787
$zScore = abs(($run['duration_ms'] - $mean) / $stdDev);
88-
88+
8989
if ($zScore <= $threshold) {
9090
$filteredRuns[] = $run;
9191
} else {
9292
$outliersRemoved++;
9393
}
9494
}
95-
95+
9696
if (!empty($filteredRuns)) {
9797
$filteredRuns[0]['outliers_removed'] = $outliersRemoved;
9898
$filteredRuns[0]['original_run_count'] = count($runs);
9999
}
100-
100+
101101
return $filteredRuns;
102102
}
103103

@@ -120,23 +120,27 @@ private function analyzeTiming(array $runs, array $times): array
120120

121121
private function analyzeMemoryUsage(array $runs): array
122122
{
123-
$memoryNets = array_column($runs, 'memory_net');
123+
$memoryNets = array_column($runs, 'memory_net');
124+
$memoryDeltas = array_column($runs, 'memory_delta');
125+
$memoryRetained = array_column($runs, 'memory_retained');
126+
124127
$initializationCost = $runs[0]['memory_net'] ?? 0;
125128

126-
// Calculate growth after initialization (skip first run)
127129
$subsequentRuns = array_slice($memoryNets, 1);
128130
$avgGrowthAfterInit = empty($subsequentRuns) ? 0 : array_sum($subsequentRuns) / count($subsequentRuns);
129131

130-
$hasLeak = $avgGrowthAfterInit > 10240; // More than 10KB average growth
132+
$hasLeak = $avgGrowthAfterInit > 10240;
131133

132134
return [
133135
'initialization_cost' => $initializationCost,
134-
'avg_memory_delta' => array_sum(array_column($runs, 'memory_delta')) / count($runs),
135-
'avg_memory_net' => array_sum($memoryNets) / count($memoryNets),
136+
'avg_memory_delta' => array_sum($memoryDeltas) / count($memoryDeltas),
137+
'avg_memory_net' => array_sum($memoryNets) / count($memoryNets),
138+
'avg_memory_retained' => array_sum($memoryRetained) / count($memoryRetained),
136139
'avg_growth_after_init' => $avgGrowthAfterInit,
137140
'has_leak' => $hasLeak,
138141
'leak_severity' => $this->getLeakSeverity($avgGrowthAfterInit),
139-
'peak_memory' => max(array_column($runs, 'memory_after'))
142+
'peak_memory' => max(array_column($runs, 'memory_after')),
143+
'peak_memory_after_gc' => max(array_column($runs, 'memory_after_gc'))
140144
];
141145
}
142146

src/Benchmark/Utils/BenchmarkExecutor.php

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function execute(string $name, callable $callback): array
2222

2323
if ($this->config->isOutputEnabled()) {
2424
echo "🚀 Running benchmark: {$name}\n";
25-
echo str_repeat('-', 50)."\n";
25+
echo str_repeat('-', 50) . "\n";
2626
}
2727

2828
$runs = [];
@@ -76,16 +76,13 @@ private function executeWarmup(callable $callback): void
7676

7777
private function executeRun(callable $callback, bool $isWarmup = false, int $runNumber = 0, int $baselineMemory = 0): array
7878
{
79-
// Pre-run measurements
8079
$memoryBefore = $this->config->isMemoryTrackingEnabled() ? memory_get_usage(true) : 0;
8180
$peakBefore = $this->config->isMemoryTrackingEnabled() ? memory_get_peak_usage(true) : 0;
8281

83-
// Timing
8482
$startTime = $this->config->isHighPrecisionEnabled() && function_exists('hrtime')
8583
? hrtime(true)
8684
: microtime(true);
8785

88-
// Execute callback
8986
$result = null;
9087
$exception = null;
9188

@@ -95,17 +92,20 @@ private function executeRun(callable $callback, bool $isWarmup = false, int $run
9592
$exception = $e;
9693
}
9794

98-
// Post-run measurements
9995
$duration = $this->calculateDuration($startTime);
10096
$memoryAfter = $this->config->isMemoryTrackingEnabled() ? memory_get_usage(true) : 0;
10197
$peakAfter = $this->config->isMemoryTrackingEnabled() ? memory_get_peak_usage(true) : 0;
10298

103-
// Force garbage collection if enabled
99+
$actualMemoryDelta = $memoryAfter - $memoryBefore;
100+
$actualNetUsage = $memoryAfter - $baselineMemory;
101+
102+
$memoryAfterGc = $memoryAfter;
104103
if ($this->config->isGarbageCollectionEnabled() && $this->config->isMemoryTrackingEnabled()) {
105104
$this->environment->forceGarbageCollection();
105+
$memoryAfterGc = memory_get_usage(true);
106106
}
107107

108-
$memoryAfterGc = $this->config->isMemoryTrackingEnabled() ? memory_get_usage(true) : 0;
108+
$retainedMemory = $memoryAfterGc - $baselineMemory;
109109

110110
return [
111111
'run_number' => $runNumber,
@@ -115,8 +115,9 @@ private function executeRun(callable $callback, bool $isWarmup = false, int $run
115115
'memory_before' => $memoryBefore,
116116
'memory_after' => $memoryAfter,
117117
'memory_after_gc' => $memoryAfterGc,
118-
'memory_delta' => $memoryAfter - $memoryBefore,
119-
'memory_net' => $memoryAfterGc - $baselineMemory,
118+
'memory_delta' => $actualMemoryDelta,
119+
'memory_net' => $actualNetUsage,
120+
'memory_retained' => $retainedMemory,
120121
'peak_memory_delta' => $peakAfter - $peakBefore,
121122
'result' => $result,
122123
'exception' => $exception,
@@ -129,11 +130,11 @@ private function calculateDuration(float|int $startTime): float
129130
if ($this->config->isHighPrecisionEnabled() && function_exists('hrtime')) {
130131
$endTime = hrtime(true);
131132

132-
return ($endTime - $startTime) / 1e6;
133+
return ($endTime - $startTime) / 1e6;
133134
} else {
134135
$endTime = microtime(true);
135136

136-
return ($endTime - $startTime) * 1000;
137+
return ($endTime - $startTime) * 1000;
137138
}
138139
}
139140

@@ -151,9 +152,9 @@ private function displayRunResult(array $run): void
151152
}
152153

153154
if ($run['exception']) {
154-
$output .= ' ❌ ERROR: '.$run['exception']->getMessage();
155+
$output .= ' ❌ ERROR: ' . $run['exception']->getMessage();
155156
}
156157

157-
echo $output."\n";
158+
echo $output . "\n";
158159
}
159160
}

0 commit comments

Comments
 (0)