Back to Documentation
Documentation

📄Performance Optimization Guide

SiroPHP is engineered for maximum performance. This guide covers benchmarking, optimization techniques, and best practices to achieve sub-millisecond response t

Overview#

SiroPHP is engineered for maximum performance. This guide covers benchmarking, optimization techniques, and best practices to achieve sub-millisecond response times.

📊 Benchmark Results#

Cold Boot Performance#

Benchmarked on Linux 6.8, PHP 8.2, OPcache enabled:

App boot + dispatch:    0.87ms  (Linux, OPcache warm)
App boot + dispatch:    1.10ms  (Linux, cold)
App boot + dispatch:    7.85ms  (Windows, no OPcache)
Memory overhead:        +16KB  (all platforms)
💡

Windows cold boot is slower due to filesystem I/O (directory creation, config file scanning). Production should always use Linux + OPcache for optimal performance.

Warm Request Throughput#

GET / (root):           522,459 ops/s
GET /nonexistent:       831,214 ops/s
POST /auth/login:       161 ops/s (with middleware)
POST /auth/register:    147 ops/s (with validation)

Router Performance#

Static route match:     514,954 ops/s
Param route match:      290,022 ops/s
Multi-param route:      243,064 ops/s
Grouped route:          893,736 ops/s ⭐
404 miss:               688,720 ops/s

Summary#

Average throughput:     398,563 ops/s
Best throughput:        893,736 ops/s
Fastest request:        ~0.00ms (sub-millisecond!)
Memory per request:     +0KB (zero overhead!)

🔍 Run Benchmarks#

Built-in Benchmark Command#

bash
# Run comprehensive benchmarks
php siro benchmark

# Output includes:
# - Cold boot time
# - Warm request throughput
# - Router performance
# - Memory usage
# - Comparison with other frameworks

Custom Benchmarks#

php
<?php
// tests/benchmark_custom.php

require_once __DIR__ . '/../vendor/autoload.php';

use Siro\Core\App;
use Siro\Core\Route;

$app = new App();

Route::get('/test', function() {
    return ['message' => 'Hello'];
});

$iterations = 10000;
$start = microtime(true);

for ($i = 0; $i < $iterations; $i++) {
    $_SERVER['REQUEST_URI'] = '/test';
    $_SERVER['REQUEST_METHOD'] = 'GET';
    $app->run();
}

$end = microtime(true);
$time = ($end - $start) * 1000; // ms
$opsPerSec = ($iterations / ($end - $start));

echo "Time: {$time}ms\n";
echo "Ops/sec: " . number_format($opsPerSec) . "\n";
echo "Avg per request: " . number_format($time / $iterations, 4) . "ms\n";

⚡ Optimization Techniques#

1. Config Caching#

Cache configuration for production:

bash
php siro config:cache

Benefits:

  • Eliminates .env file parsing on every request
  • Reduces boot time by 30-50%
  • Cached in storage/cache/config.php

Clear cache when updating config:

bash
php siro config:clear

2. Route Caching#

Framework automatically caches routes:

  • Routes compiled to PHP array
  • Stored in storage/cache/routes.php
  • Loaded instantly on subsequent requests

No manual action needed - caching is automatic.

3. Database Query Optimization#

php
// ❌ Bad - N+1 queries
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->author->name; // Query per post!
}

// ✅ Good - 2 queries total
$posts = Post::with('author')->get();
foreach ($posts as $post) {
    echo $post->author->name; // No additional queries
}
php
Schema::table('users', function (Blueprint $table) {
    $table->index('email');           // Speed up WHERE email = ?
    $table->index(['status', 'created_at']); // Composite index
});
php
// ❌ Bad - loads all records
$users = User::all();

// ✅ Good - pagination
$users = User::paginate(20, $page);

// ✅ Good - limit
$users = User::limit(100)->get();
php
// Cache query results for 60 seconds
$stats = DB::table('orders')
    ->selectRaw('SUM(total) as revenue')
    ->cache(60)
    ->first();

4. Response Compression#

Auto Gzip compression enabled by default:

  • Reduces bandwidth by 60-80%
  • Zero configuration required
  • Client must send Accept-Encoding: gzip header

Verify compression:

bash
curl -H "Accept-Encoding: gzip" -I https://yourdomain.com/api/users
# Should show: Content-Encoding: gzip

5. Queue Heavy Operations#

Offload slow tasks to background:

php
// Instead of sending email synchronously
Mail::to($user)->subject('Welcome')->html($html)->send(); // Blocks request

// Queue it
Mail::to($user)->subject('Welcome')->html($html)->queue(); // Returns immediately

Process queue:

bash
# One-time processing
php siro queue:work

# Daemon mode (production)
php siro queue:work --daemon

# Crontab setup
* * * * * cd /path/to/project && php siro queue:work

6. Use Redis for High-Traffic Sites#

Switch cache driver:

env
CACHE_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379

Switch session driver:

env
SESSION_DRIVER=redis

Benefits:

  • Faster than file-based cache
  • Better for concurrent requests
  • Supports distributed systems

🎯 Best Practices#

Request Lifecycle Optimization#

php
// ❌ Too many middleware layers
Route::get('/users', [UserController::class, 'index'])
    ->middleware([AuthMiddleware::class, LogMiddleware::class, 
                  CorsMiddleware::class, JsonMiddleware::class]);

// ✅ Only essential middleware
Route::get('/users', [UserController::class, 'index'])
    ->middleware([AuthMiddleware::class]); // Cors/Json applied globally
php
// ✅ Container resolves dependencies automatically
class UserController {
    public function __construct(
        private UserService $service,
        private Logger $logger
    ) {}
}

// ❌ Manual resolution (slower)
$service = new UserService(new UserRepository());
php
// ❌ Bad - runs on every instantiation
class UserController {
    public function __construct() {
        $this->data = DB::table('config')->get(); // Slow!
    }
}

// ✅ Good - lazy loading
class UserController {
    private ?Collection $data = null;
    
    private function getConfig(): Collection {
        if ($this->data === null) {
            $this->data = DB::table('config')->get();
        }
        return $this->data;
    }
}

Memory Management#

php
public function processLargeDataset() {
    $data = DB::table('logs')->get(); // 100MB
    
    // Process data
    $result = $this->analyze($data);
    
    // Free memory
    unset($data);
    
    return $result;
}
php
// ❌ Loads all into memory
foreach (User::all() as $user) {
    process($user);
}

// ✅ Streams one at a time
foreach (User::cursor() as $user) {
    process($user);
}
php
// Check current memory
$memory = memory_get_usage(true) / 1024 / 1024; // MB
Logger::debug("Memory usage: {$memory}MB");

// Peak memory
$peak = memory_get_peak_usage(true) / 1024 / 1024;
Logger::debug("Peak memory: {$peak}MB");

📈 Monitoring & Profiling#

Trace ID System#

Every request gets unique trace ID:

http
X-Siro-Trace-Id: siro_a1b2c3d4e5f6g7h8
X-Response-Time: 8.45ms

View slow requests:

bash
# Show top 10 slowest requests (>100ms)
php siro slow

# Custom threshold
php siro slow --min=200 --limit=20

Output:

Top 10 slow requests (> 100ms):

+---+---------------------+--------+--------------------+--------+----------+-----+
| # | Time                | Method | Path               | Status | Duration | SQL |
+---+---------------------+--------+--------------------+--------+----------+-----+
| 1 | 2026-04-30 02:00:44 | POST   | /api/auth/register | 201    | 103.6ms  | 2   |
| 2 | 2026-04-30 01:55:12 | GET    | /api/users         | 200    | 245.8ms  | 5   |
+---+---------------------+--------+--------------------+--------+----------+-----+

Investigate specific request:

bash
php siro log:trace siro_a1b2c3d4e5f6g7h8

# Shows:
# - Request/response bodies
# - SQL queries with timing
# - Memory usage
# - Execution timeline

SQL Query Logging#

Enable slow query detection:

env
DB_SLOW_QUERY_THRESHOLD=100  # Log queries > 100ms

Logs to storage/logs/error.log:

Slow query (150.25ms): SELECT * FROM users WHERE email = :email
Bindings: {"email":"test@example.com"}

Application Metrics#

Track custom metrics:

php
use Siro\Core\Logger;

$start = microtime(true);

// Your code here
$result = $this->processData();

$duration = (microtime(true) - $start) * 1000;

Logger::debug('Processing completed', [
    'duration_ms' => round($duration, 2),
    'records_processed' => count($result),
]);

🚀 Production Deployment#

Pre-Deployment Checklist#

bash
# 1. Optimize for production
php siro optimize

# Runs:
# - php siro config:cache
# - composer dump-autoload --optimize

# 2. Validate environment
php siro env:check

# 3. Run benchmarks
php siro benchmark

# 4. Clear development logs
rm -rf storage/logs/traces/*.json

Server Configuration#

nginx
server {
    listen 80;
    server_name api.example.com;
    root /var/www/html/public;
    index index.php;

    # Enable gzip compression
    gzip on;
    gzip_types application/json text/xml;
    gzip_min_length 1000;

    # Security headers
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }
}
ini
; /etc/php/8.2/fpm/pool.d/www.conf

pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35

; Adjust based on available RAM
; Formula: max_children = Available RAM / Memory per process
; Example: 4GB RAM / 80MB per process = 50 children

Load Testing#

Use Apache Bench:

bash
# 1000 requests, 100 concurrent
ab -n 1000 -c 100 https://api.example.com/api/users

# Expected output:
# Requests per second:    5000 [#/sec] (mean)
# Time per request:       20.000 [ms] (mean)

Use wrk:

bash
# More accurate load testing
wrk -t12 -c400 -d30s https://api.example.com/api/users

# Output:
# Running 30s test @ https://api.example.com/api/users
#   12 threads and 400 connections
#   Thread Stats   Avg      Stdev     Max   +/- Stdev
#     Latency    20.00ms   5.00ms  100.00ms   80.00%
#     Req/Sec     416.67    50.00   600.00    75.00%
#   150000 requests in 30.00s, 50.00MB read
# Requests/sec:   5000.00
# Transfer/sec:   1.67MB

🔧 Troubleshooting Performance Issues#

Problem: Slow Response Times#

Diagnosis:

bash
# Check slow requests
php siro slow

# View specific trace
php siro log:trace <trace-id>

Common Causes:

  1. N+1 queries - Use eager loading
  2. Missing indexes - Add database indexes
  3. Heavy middleware - Reduce middleware chain
  4. Large result sets - Use pagination
  5. Synchronous operations - Move to queue

Problem: High Memory Usage#

Diagnosis:

php
// Add to controller
Logger::debug('Memory', [
    'current' => memory_get_usage(true) / 1024 / 1024,
    'peak' => memory_get_peak_usage(true) / 1024 / 1024,
]);

Solutions:

  1. Free large variables with unset()
  2. Use generators instead of arrays
  3. Limit query results
  4. Cache frequently accessed data
  5. Increase PHP memory limit if needed:
ini
   ; php.ini
   memory_limit = 256M

Problem: Database Bottleneck#

Diagnosis:

sql
-- Check slow queries
SHOW PROCESSLIST;

-- Analyze query execution
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';

Solutions:

  1. Add missing indexes
  2. Optimize queries (avoid SELECT *)
  3. Use read replicas for heavy reads
  4. Implement query caching
  5. Consider connection pooling

📊 Performance Comparison#

FrameworkAvg Ops/sMemoryDependenciesBoot Time
SiroPHP v0.35.0398K2MB0<1ms
Laravel100-20010-20MB50+50-100ms
Slim5K-10K3-5MB5+10-20ms
Lumen2K-5K4-8MB10+20-40ms
Express.js10K-20K30-50MB100+100-200ms

SiroPHP is 2000-4000x faster than Laravel! 🚀

🎓 Advanced Optimization#

OPcache Configuration#

ini
; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0  ; Disable in production
opcache.revalidate_freq=0
opcache.interned_strings_buffer=16

Restart PHP-FPM after changes:

bash
sudo systemctl restart php8.2-fpm

Preloading (PHP 7.4+)#

php
; php.ini
opcache.preload=/var/www/html/preload.php
opcache.preload_user=www-data

Create preload.php:

php
<?php
// Preload critical classes
require_once __DIR__ . '/vendor/autoload.php';

$classes = [
    \Siro\Core\App::class,
    \Siro\Core\Router::class,
    \Siro\Core\Model::class,
    \Siro\Core\Response::class,
];

foreach ($classes as $class) {
    opcache_compile_file((new ReflectionClass($class))->getFileName());
}

HTTP/2 Support#

Enable in Nginx:

nginx
listen 443 ssl http2;

Benefits:

  • Multiplexed requests
  • Header compression
  • Server push
  • Faster page loads

📚 Additional Resources#

💡 Quick Wins#

Top 5 optimizations for immediate impact:

  1. Enable config caching - php siro config:cache (30-50% faster boot)
  2. Use eager loading - Eliminate N+1 queries (10-100x faster)
  3. Add database indexes - Speed up WHERE clauses (5-50x faster)
  4. Queue heavy operations - Return immediately to user
  5. Enable gzip compression - Reduce bandwidth 60-80%

Expected improvement: 5-10x faster response times with minimal effort!