PHPackages                             alexandrebulete/laravel-benchmark - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. alexandrebulete/laravel-benchmark

ActiveLibrary[Testing &amp; Quality](/categories/testing)

alexandrebulete/laravel-benchmark
=================================

A comprehensive benchmark system for Laravel applications

1.0.3(5mo ago)231↓100%MITPHPPHP ^8.2

Since Dec 10Pushed 5mo agoCompare

[ Source](https://github.com/AlexandreBulete/laravel-benchmark)[ Packagist](https://packagist.org/packages/alexandrebulete/laravel-benchmark)[ RSS](/packages/alexandrebulete-laravel-benchmark/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (11)Versions (5)Used By (0)

Laravel Benchmark
=================

[](#laravel-benchmark)

A comprehensive benchmark system for Laravel applications. Safely test performance with isolated database, automatic cleanup, production protection, **dynamic command generation**, and **intelligent optimization suggestions**.

[![Latest Stable Version](https://camo.githubusercontent.com/9ecd5620d329d2daa14f4741758a15e777409780003f9b9006e1fa4f6ce289fb/68747470733a2f2f706f7365722e707567782e6f72672f616c6578616e64726562756c6574652f6c61726176656c2d62656e63686d61726b2f762f737461626c65)](https://packagist.org/packages/alexandrebulete/laravel-benchmark)[![License](https://camo.githubusercontent.com/3b44956a59cf1200ec0660a8463bca130710361cca4933b6ec9ca16dea0daac9/68747470733a2f2f706f7365722e707567782e6f72672f616c6578616e64726562756c6574652f6c61726176656c2d62656e63686d61726b2f6c6963656e7365)](https://packagist.org/packages/alexandrebulete/laravel-benchmark)

Features
--------

[](#features)

- 🔒 **Production Safe** - Automatically disabled in production environment
- 🗄️ **Isolated Database** - Separate benchmark database to avoid data pollution
- 📊 **Detailed Metrics** - Execution time, memory usage, and peak memory tracking
- 🐳 **Docker Ready** - Includes Docker Compose template for benchmark database
- 🛠️ **Artisan Commands** - Easy-to-use CLI for creating and running benchmarks
- 🧹 **Auto Cleanup** - Database is wiped after each benchmark
- ⚡ **Dynamic Commands** - Auto-generate CLI commands with custom options
- 🧠 **Advisor** - Automatic N+1 detection, slow query alerts, and optimization suggestions
- 📈 **Baseline &amp; Regression** - Save baselines and detect performance regressions
- 🔄 **Multiple Iterations** - Run benchmarks multiple times for stable, statistically meaningful results

Requirements
------------

[](#requirements)

- PHP 8.2 or higher
- Laravel 10, 11, or 12

Installation
------------

[](#installation)

```
composer require alexandrebulete/laravel-benchmark --dev
```

Then run the installation command:

```
php artisan benchmark:install --docker
```

Quick Start
-----------

[](#quick-start)

### 1. Create a benchmark with a command code

[](#1-create-a-benchmark-with-a-command-code)

```
# With --code: auto-creates "benchmark:users" command
php artisan make:benchmark UserProcessingBenchmark --code=users

# Without --code: use benchmark:run ClassName
php artisan make:benchmark SimpleBenchmark
```

### 2. Define CLI options in your benchmark

[](#2-define-cli-options-in-your-benchmark)

```
class UserProcessingBenchmark extends BenchmarkCase
{
    // Auto-set by --code option, creates "benchmark:users"
    protected static ?string $code = 'users';

    // Define CLI options
    protected static array $options = [
        'count' => ['default' => 1000, 'description' => 'Number of users'],
    ];

    protected function applyOptions(array $options): void
    {
        $this->count = $options['count'];
    }

    public function benchmark(): void
    {
        // Your benchmark logic
    }
}
```

### 3. Run your benchmark

[](#3-run-your-benchmark)

```
# Using dynamic command with options
php artisan benchmark:users --count=10000

# Or using generic command
php artisan benchmark:run UserProcessingBenchmark
```

🔄 Multiple Iterations - Stable &amp; Reliable Results
-----------------------------------------------------

[](#-multiple-iterations---stable--reliable-results)

By default, benchmarks run **5 iterations** to provide statistically stable results. This eliminates variance from garbage collection, CPU cache, and other system factors.

### Why Multiple Iterations?

[](#why-multiple-iterations)

A single benchmark run can be misleading due to:

- ❄️ **Cold cache** on first run
- 🗑️ **Garbage collection** pauses
- 💻 **CPU scheduling** variations
- 🔄 **I/O fluctuations**

Running multiple iterations and using the **median** provides much more reliable results.

### Sample Output

[](#sample-output)

```
╔════════════════════════════════════════════════════════════╗
║        BENCHMARK RESULTS (5 iterations)                    ║
╚════════════════════════════════════════════════════════════╝

Individual Runs:
  3.42s  |  3.61s  |  3.38s  |  3.55s  |  3.41s

Statistics:
+---------------+----------------------------------------+
| Metric        | Value                                  |
+---------------+----------------------------------------+
| Average       | 3.47s                                  |
| Median        | 3.42s (used for baseline)              |
| Min / Max     | 3.38s / 3.61s                          |
| Std Deviation | ±0.09s (2.6%)                          |
| P95           | 3.58s                                  |
| Stability     | Very Stable                            |
+---------------+----------------------------------------+

```

### Controlling Iterations

[](#controlling-iterations)

```
# Override default iterations
php artisan benchmark:users --iterations=10

# Add warmup runs (discarded from stats)
php artisan benchmark:users --iterations=5 --warmup=2
```

### Warmup Runs

[](#warmup-runs)

Warmup runs execute the benchmark but discard results - useful for:

- Filling CPU caches
- JIT compilation warmup
- Database connection pooling

```
# 5 measured runs + 2 warmup (7 total runs, first 2 discarded)
php artisan benchmark:users --iterations=5 --warmup=2
```

```
  [WARMUP] Running iteration W1...
       ○ 4.12s (discarded)
  [WARMUP] Running iteration W2...
       ○ 3.89s (discarded)
  [RUN] Running iteration 1...
       ✓ 3.42s | Memory: 35.1 MB | Score: 72/100
  [RUN] Running iteration 2...
       ✓ 3.38s | Memory: 34.8 MB | Score: 74/100
  ...

```

### Statistics Provided

[](#statistics-provided)

MetricDescription**Average**Mean of all runs**Median**Middle value (used for baselines)**Min / Max**Range of results**Std Deviation**Variance measure (±value and %)**P95 / P99**95th/99th percentile**Stability**Assessment based on variance**Stability Grades:**

- `Very Stable` (&lt; 5% variance)
- `Stable` (&lt; 10% variance)
- `Moderate Variance` (&lt; 20% variance)
- `High Variance` (&gt; 20% variance)

### Configuration

[](#configuration)

In `config/benchmark.php`:

```
'iterations' => [
    // Default number of iterations
    'default' => env('BENCHMARK_ITERATIONS', 5),

    // Bounds
    'min' => 1,
    'max' => 100,

    // Default warmup runs
    'warmup' => env('BENCHMARK_WARMUP', 0),

    // Show individual run times
    'show_individual' => true,

    // Warn if variance exceeds this %
    'variance_warning_threshold' => 15,
],
```

### High Variance Warning

[](#high-variance-warning)

When results are unstable, you'll see a warning:

```
⚠️  High variance detected (18.3%). Results may be unstable.
   Consider running with more iterations: --iterations=10

```

This helps you know when your benchmark environment may be affecting results.

🧠 Advisor - Intelligent Query Analysis
--------------------------------------

[](#-advisor---intelligent-query-analysis)

The Advisor automatically analyzes all SQL queries during your benchmark and provides actionable optimization suggestions.

### What it detects

[](#what-it-detects)

RuleDescription**N+1 Queries**Same query pattern executed multiple times**Slow Queries**Individual queries exceeding time threshold**Hotspots**Code locations generating most DB activity**Duplicates**Exact same queries executed multiple times### Sample Output

[](#sample-output-1)

```
╔════════════════════════════════════════════════════════════════╗
║                    📊 ADVISOR REPORT                           ║
╚════════════════════════════════════════════════════════════════╝

  🏆 Performance Score: 72/100 Acceptable
  [██████████████░░░░░░]

Database Statistics:
┌──────────────────┬─────────────┐
│ Total Queries    │ 1,401       │
│ Unique Queries   │ 7           │
│ Total DB Time    │ 2.86s       │
│ DB Time %        │ 79.1%       │
└──────────────────┴─────────────┘

Issues Found:
  🔴 6 critical

Potential Optimization:
  💰 Estimated time savings: ~2.34s if all N+1 issues are fixed
  📈 Potential score: 95/100 (currently 72)

Optimization Suggestions:

🔴 [n_plus_one] Possible N+1 Query
   100 identical queries (total: 100.58ms, avg: 1.01ms)
   💰 Potential savings: ~80.46ms
   📍 App\Models\User::hasEnabledRemindersNotifications()
   → Add eager loading: ->with('settings')
   → Or load after: $model->load('settings')
   SQL: select * from `user_settings` where `user_id` = ?...

🔴 [n_plus_one] Possible N+1 Query
   300 identical queries (total: 260.77ms, avg: 0.87ms)
   💰 Potential savings: ~208.62ms
   📍 App\DTOs\Notification\CloudMessageDTO::fromModel()
   → Add eager loading: ->with('user')
   → This could reduce queries from N to 1
   SQL: select * from `users` where `id` = ? limit 1

Top 5 Locations by Query Count:
┌──────────────────────────────────────────────────────┬─────────┬──────────┐
│ Location                                             │ Queries │ Time     │
├──────────────────────────────────────────────────────┼─────────┼──────────┤
│ CloudMessageDTO::fromModel()                         │ 600     │ 520.55ms │
│ RuleService::processRule()                           │ 300     │ 1.09s    │
│ NotificationRepository::create()                     │ 300     │ 1.04s    │
└──────────────────────────────────────────────────────┴─────────┴──────────┘

Score Breakdown:
  -30 N+1 query issues
  -10 High DB time (79.1%)
  -15 Low query uniqueness (0.5%)
  +5 No critical issues

Analysis completed in 31.16ms

```

### Performance Score

[](#performance-score)

The Advisor calculates a **Performance Score (0-100)** based on:

FactorImpactN+1 queries-8 to -15 per issueSlow queries-10 to -20 per issueHigh DB time (&gt;70%)-10 to -15Low query uniqueness-5 to -15**Bonuses**+5 to +10 for clean code**Grades:**

- 🏆 **A (90-100)**: Excellent
- ✅ **B (80-89)**: Good
- ⚠️ **C (70-79)**: Acceptable
- 🔧 **D (60-69)**: Needs Work
- ❌ **E (50-59)**: Poor
- 🔴 **F (0-49)**: Critical

### Smart Suggestions

[](#smart-suggestions)

The Advisor analyzes your SQL to provide **specific** eager loading suggestions:

```
SQL: SELECT * FROM user_settings WHERE user_id = ?

→ Add eager loading: ->with('settings')
→ Or load after: $model->load('settings')

```

Instead of generic advice, it detects the table and suggests the exact relationship name.

### Disabling Advisor

[](#disabling-advisor)

```
class MyBenchmark extends BenchmarkCase
{
    // Disable for this specific benchmark
    protected bool $withAdvisor = false;

    // Or disable at runtime
    public function benchmark(): void
    {
        $this->withAdvisor(false);
    }
}
```

Or globally via environment:

```
BENCHMARK_ADVISOR_ENABLED=false
```

### Configuring Thresholds

[](#configuring-thresholds)

In `config/benchmark.php`:

```
'advisor' => [
    'enabled' => true,
    'rules' => [
        'n_plus_one' => [
            'enabled' => true,
            'threshold' => 10,          // Min similar queries to flag
            'critical_count' => 100,    // Count for critical severity
            'critical_time_ms' => 1000, // Time for critical severity
        ],
        'slow_query' => [
            'enabled' => true,
            'threshold_ms' => 100,      // Warning threshold
            'critical_ms' => 1000,      // Critical threshold
        ],
        'hotspot' => [
            'enabled' => true,
            'threshold_percent' => 50,  // % of queries/time
            'min_queries' => 10,        // Min queries to analyze
        ],
        'duplicate' => [
            'enabled' => true,
            'threshold' => 2,           // Min duplicates to flag
        ],
    ],
],
```

Dynamic Commands
----------------

[](#dynamic-commands)

The killer feature! Define `$code` and `$options` in your benchmark class, and a CLI command is **automatically generated**.

```
class NotificationBenchmark extends BenchmarkCase
{
    protected static ?string $code = 'notifications';

    protected static array $options = [
        'users' => ['default' => 1000, 'description' => 'Number of users'],
        'rules' => ['default' => 3, 'description' => 'Rules per user'],
    ];
}
```

This auto-creates:

```
php artisan benchmark:notifications --users=1000000 --rules=5
```

List all available benchmarks and their codes:

```
php artisan benchmark:list
```

```
╔══════════════════════════════════════════════════════════════════╗
│ Class                          │ Code          │ Command         │
╠══════════════════════════════════════════════════════════════════╣
│ NotificationProcessingBenchmark│ notifications │ benchmark:notif │
│ UserProcessingBenchmark        │ users         │ benchmark:users │
│ SimpleBenchmark                │ -             │ benchmark:run   │
╚══════════════════════════════════════════════════════════════════╝

```

Configuration
-------------

[](#configuration-1)

After installation, customize settings in `config/benchmark.php`:

```
return [
    'enabled' => env('BENCHMARK_ENABLED', false),

    'database' => [
        'connection' => env('BENCHMARK_DB_CONNECTION', 'benchmark'),
    ],

    'namespace' => 'Tests\\Benchmark\\Suites',
    'path' => 'tests/Benchmark/Suites',

    'advisor' => [
        'enabled' => true,
        // ... rule configurations
    ],
];
```

Environment Variables
---------------------

[](#environment-variables)

```
BENCHMARK_ENABLED=true
BENCHMARK_ADVISOR_ENABLED=true
BENCHMARK_ITERATIONS=5
BENCHMARK_WARMUP=0
DB_BENCHMARK_HOST=db_benchmark
DB_BENCHMARK_PORT=3306
DB_BENCHMARK_DATABASE=benchmark
DB_BENCHMARK_USERNAME=benchmark
DB_BENCHMARK_PASSWORD=benchmark
```

Docker Setup
------------

[](#docker-setup)

```
# Start with benchmark database
docker compose -f compose.yml -f compose.benchmark.yml up -d
```

Creating Benchmarks
-------------------

[](#creating-benchmarks)

### Full Example

[](#full-example)

```
