1+ <?php
2+
3+ declare (strict_types=1 );
4+
5+ require_once __DIR__ . '/../vendor/autoload.php ' ;
6+
7+ use PivotPHP \Core \Http \Request ;
8+ use PivotPHP \Core \Http \Response ;
9+ use PivotPHP \Core \Http \Factory \OptimizedHttpFactory ;
10+ use PivotPHP \Core \Core \Application ;
11+ use PivotPHP \Core \Routing \Router ;
12+
13+ /**
14+ * Simple Performance Benchmark for CI Environments
15+ *
16+ * Optimized for GitHub Actions and other CI environments:
17+ * - Lower iterations for faster execution
18+ * - Focus on core performance metrics
19+ * - CI-friendly output format
20+ */
21+ class SimpleBenchmark
22+ {
23+ private int $ iterations ;
24+ private array $ results = [];
25+ private bool $ usePooling = true ;
26+
27+ public function __construct (int $ iterations = 500 ) // Lower default for CI
28+ {
29+ $ this ->iterations = $ iterations ;
30+
31+ // Initialize optimized factory with CI-friendly settings
32+ OptimizedHttpFactory::initialize ([
33+ 'enable_pooling ' => $ this ->usePooling ,
34+ 'warm_up_pools ' => true ,
35+ 'enable_metrics ' => true ,
36+ 'initial_size ' => 10 , // Smaller pool for CI
37+ 'max_size ' => 50 , // Smaller max pool for CI
38+ ]);
39+ }
40+
41+ public function run (): void
42+ {
43+ echo "🚀 Express PHP Framework - Performance Benchmark \n" ;
44+ echo "================================================ \n\n" ;
45+
46+ // Skip extensive warmup in CI
47+ $ this ->quickWarmup ();
48+
49+ echo "📊 Running benchmarks with {$ this ->iterations } iterations... \n\n" ;
50+
51+ // Core benchmarks - optimized for CI
52+ $ this ->benchmarkRequestCreation ();
53+ $ this ->benchmarkResponseCreation ();
54+ $ this ->benchmarkHybridOperations ();
55+ $ this ->benchmarkObjectPooling ();
56+ $ this ->benchmarkRouteProcessing ();
57+
58+ $ this ->displayResults ();
59+ $ this ->displayPoolingMetrics ();
60+ }
61+
62+ private function quickWarmup (): void
63+ {
64+ // Minimal warmup for CI environments
65+ for ($ i = 0 ; $ i < 50 ; $ i ++) { // Much smaller warmup
66+ $ request = OptimizedHttpFactory::createServerRequest ('GET ' , '/test ' );
67+ $ response = OptimizedHttpFactory::createResponse ();
68+ unset($ request , $ response );
69+ }
70+ }
71+
72+ private function benchmarkRequestCreation (): void
73+ {
74+ echo "📋 Benchmarking Request Creation... \n" ;
75+
76+ $ start = hrtime (true );
77+
78+ for ($ i = 0 ; $ i < $ this ->iterations ; $ i ++) {
79+ $ request = OptimizedHttpFactory::createServerRequest ('GET ' , '/api/test ' );
80+ unset($ request );
81+ }
82+
83+ $ end = hrtime (true );
84+ $ elapsed = ($ end - $ start ) / 1_000_000_000 ; // Convert to seconds
85+ $ opsPerSec = (int )($ this ->iterations / $ elapsed );
86+
87+ $ this ->results ['request_creation ' ] = $ opsPerSec ;
88+
89+ echo " ✅ Completed in " . number_format ($ elapsed , 4 ) . "s \n" ;
90+ echo " 📈 " . number_format ($ opsPerSec ) . " ops/sec \n\n" ;
91+ }
92+
93+ private function benchmarkResponseCreation (): void
94+ {
95+ echo "📋 Benchmarking Response Creation... \n" ;
96+
97+ $ start = hrtime (true );
98+
99+ for ($ i = 0 ; $ i < $ this ->iterations ; $ i ++) {
100+ $ response = OptimizedHttpFactory::createResponse ();
101+ unset($ response );
102+ }
103+
104+ $ end = hrtime (true );
105+ $ elapsed = ($ end - $ start ) / 1_000_000_000 ;
106+ $ opsPerSec = (int )($ this ->iterations / $ elapsed );
107+
108+ $ this ->results ['response_creation ' ] = $ opsPerSec ;
109+
110+ echo " ✅ Completed in " . number_format ($ elapsed , 4 ) . "s \n" ;
111+ echo " 📈 " . number_format ($ opsPerSec ) . " ops/sec \n\n" ;
112+ }
113+
114+ private function benchmarkHybridOperations (): void
115+ {
116+ echo "📋 Benchmarking Hybrid Operations... \n" ;
117+
118+ $ start = hrtime (true );
119+
120+ for ($ i = 0 ; $ i < $ this ->iterations ; $ i ++) {
121+ $ request = OptimizedHttpFactory::createServerRequest ('POST ' , '/api/users ' );
122+ $ response = OptimizedHttpFactory::createResponse ();
123+
124+ // Simulate Express.js style operations
125+ $ response ->status (201 );
126+ $ response ->header ('Content-Type ' , 'application/json ' );
127+
128+ unset($ request , $ response );
129+ }
130+
131+ $ end = hrtime (true );
132+ $ elapsed = ($ end - $ start ) / 1_000_000_000 ;
133+ $ opsPerSec = (int )($ this ->iterations / $ elapsed );
134+
135+ $ this ->results ['hybrid_operations ' ] = $ opsPerSec ;
136+
137+ echo " ✅ Completed in " . number_format ($ elapsed , 4 ) . "s \n" ;
138+ echo " 📈 " . number_format ($ opsPerSec ) . " ops/sec \n\n" ;
139+ }
140+
141+ private function benchmarkObjectPooling (): void
142+ {
143+ echo "📋 Benchmarking Object Pooling... \n" ;
144+
145+ $ start = hrtime (true );
146+
147+ for ($ i = 0 ; $ i < $ this ->iterations ; $ i ++) {
148+ $ request = OptimizedHttpFactory::createServerRequest ('GET ' , '/pool/test ' );
149+ $ response = OptimizedHttpFactory::createResponse ();
150+
151+ // Pool operations
152+ unset($ request , $ response );
153+ }
154+
155+ $ end = hrtime (true );
156+ $ elapsed = ($ end - $ start ) / 1_000_000_000 ;
157+ $ opsPerSec = (int )($ this ->iterations / $ elapsed );
158+
159+ $ this ->results ['object_pooling ' ] = $ opsPerSec ;
160+
161+ echo " ✅ Completed in " . number_format ($ elapsed , 4 ) . "s \n" ;
162+ echo " 📈 " . number_format ($ opsPerSec ) . " ops/sec \n\n" ;
163+ }
164+
165+ private function benchmarkRouteProcessing (): void
166+ {
167+ echo "📋 Benchmarking Route Processing... \n" ;
168+
169+ // Simple route processing simulation
170+ $ routes = [
171+ 'GET:/test ' => function () { return 'test ' ; },
172+ 'POST:/api/users ' => function () { return 'create ' ; },
173+ 'GET:/api/users/123 ' => function () { return 'show ' ; },
174+ ];
175+
176+ $ start = hrtime (true );
177+
178+ for ($ i = 0 ; $ i < $ this ->iterations ; $ i ++) {
179+ // Simulate route matching
180+ foreach ($ routes as $ pattern => $ handler ) {
181+ if (is_callable ($ handler )) {
182+ $ result = true ; // Simulate successful match
183+ }
184+ }
185+ }
186+
187+ $ end = hrtime (true );
188+ $ elapsed = ($ end - $ start ) / 1_000_000_000 ;
189+ $ opsPerSec = (int )(($ this ->iterations * count ($ routes )) / $ elapsed );
190+
191+ $ this ->results ['route_processing ' ] = $ opsPerSec ;
192+
193+ echo " ✅ Completed in " . number_format ($ elapsed , 4 ) . "s \n" ;
194+ echo " 📈 " . number_format ($ opsPerSec ) . " ops/sec \n\n" ;
195+ }
196+
197+ private function displayResults (): void
198+ {
199+ echo "📊 BENCHMARK RESULTS \n" ;
200+ echo "=================== \n\n" ;
201+
202+ $ totalTime = 0 ;
203+ foreach ($ this ->results as $ test => $ opsPerSec ) {
204+ $ testName = str_replace ('_ ' , ' ' , ucwords ($ test , '_ ' ));
205+ $ time = $ this ->iterations / $ opsPerSec ;
206+ $ totalTime += $ time ;
207+
208+ echo sprintf ("%-20s: %s ops/sec (%.4fs) \n" ,
209+ $ testName ,
210+ number_format ($ opsPerSec ),
211+ $ time
212+ );
213+ }
214+
215+ // Calculate average performance
216+ $ avgPerformance = (int )(array_sum ($ this ->results ) / count ($ this ->results ));
217+
218+ echo "\n📈 Average Performance: " . number_format ($ avgPerformance ) . " ops/sec \n" ;
219+ echo "⏱️ Total Time: " . number_format ($ totalTime , 4 ) . "s \n" ;
220+ echo "🧠 Peak Memory: " . number_format (memory_get_peak_usage () / 1024 / 1024 , 0 ) . " MB \n" ;
221+ echo "💾 Current Memory: " . number_format (memory_get_usage () / 1024 / 1024 , 0 ) . " MB \n" ;
222+ }
223+
224+ private function displayPoolingMetrics (): void
225+ {
226+ // Check if getPoolingMetrics method exists
227+ if (!method_exists (OptimizedHttpFactory::class, 'getPoolingMetrics ' )) {
228+ echo "\n♻️ OBJECT POOLING METRICS \n" ;
229+ echo "========================= \n\n" ;
230+ echo "Pool metrics not available in current version. \n" ;
231+ echo "Memory efficiency: " . number_format (memory_get_usage () / 1024 / 1024 , 1 ) . " MB used \n" ;
232+ return ;
233+ }
234+
235+ $ metrics = OptimizedHttpFactory::getPoolingMetrics ();
236+
237+ if (!empty ($ metrics )) {
238+ echo "\n♻️ OBJECT POOLING METRICS \n" ;
239+ echo "========================= \n\n" ;
240+
241+ echo "Pool Efficiency: \n" ;
242+ foreach ($ metrics as $ type => $ metric ) {
243+ if (isset ($ metric ['reuse_rate ' ])) {
244+ $ rate = number_format ($ metric ['reuse_rate ' ], 1 );
245+ $ status = $ metric ['reuse_rate ' ] >= 80 ? '🟢 ' : ($ metric ['reuse_rate ' ] >= 50 ? '🟡 ' : '🔴 ' );
246+ echo " $ status " . ucfirst ($ type ) . " Reuse Rate : $ status {$ rate }% \n" ;
247+ }
248+ }
249+
250+ echo "\nMemory Usage: \n" ;
251+ echo " Current: " . number_format (memory_get_usage () / 1024 / 1024 , 0 ) . " MB \n" ;
252+ echo " Peak: " . number_format (memory_get_peak_usage () / 1024 / 1024 , 0 ) . " MB \n" ;
253+
254+ // Simple recommendations
255+ echo "\nRecommendations: \n" ;
256+ $ avgReuse = 0 ;
257+ $ count = 0 ;
258+ foreach ($ metrics as $ metric ) {
259+ if (isset ($ metric ['reuse_rate ' ])) {
260+ $ avgReuse += $ metric ['reuse_rate ' ];
261+ $ count ++;
262+ }
263+ }
264+
265+ if ($ count > 0 ) {
266+ $ avgReuse = $ avgReuse / $ count ;
267+ if ($ avgReuse >= 90 ) {
268+ echo " • Excellent pool utilization across all components \n" ;
269+ } elseif ($ avgReuse >= 70 ) {
270+ echo " • Good pool utilization with room for optimization \n" ;
271+ } else {
272+ echo " • Pool utilization could be improved \n" ;
273+ }
274+ }
275+ }
276+ }
277+ }
278+
279+ // Run if called directly
280+ if (basename (__FILE__ ) === basename ($ _SERVER ['SCRIPT_NAME ' ])) {
281+ $ iterations = isset ($ argv [1 ]) ? (int )$ argv [1 ] : 500 ;
282+ $ benchmark = new SimpleBenchmark ($ iterations );
283+ $ benchmark ->run ();
284+
285+ echo "\n✅ Benchmark completed successfully! \n" ;
286+ }
0 commit comments