Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Benchmark Laravel Package

dragon-code/benchmark

Lightweight PHP benchmarking helper to compare execution speed of multiple callbacks. Run named tests, repeat iterations, trim outliers for cleaner averages, and print results (min/max/avg/total + memory) to the console. Includes bench() helper and Benchmark class.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require dragon-code/benchmark --dev
    

    Add to composer.json under require-dev to avoid production bloat.

  2. First Benchmark:

    use function DragonCode\Benchmark\bench;
    
    bench()
        ->compare(
            'array_map': fn () => array_map('strtoupper', ['a', 'b', 'c']),
            'foreach': fn () => array_reduce(['a', 'b', 'c'], fn ($carry, $item) => $carry .= strtoupper($item), '')
        )
        ->toConsole();
    
  3. Key Files to Explore:

    • vendor/dragon-code/benchmark/src/ for core logic
    • tests/ for usage patterns and edge cases

First Use Case: Optimizing Query Builders

bench()
    ->iterations(50)
    ->compare(
        'eloquent': fn () => Model::where('active', true)->get(),
        'query': fn () => DB::select('SELECT * FROM models WHERE active = ?', [true])
    )
    ->toConsole();

Implementation Patterns

Daily Workflow Integration

1. Performance Debugging

// Compare two query approaches
bench()
    ->warmup(2)
    ->compare(
        'eager': fn () => Model::with('relations')->find(1),
        'lazy': fn () => Model::find(1)->load('relations')
    )
    ->toConsole();

2. CI/CD Performance Gates

// In PHPUnit tests
public function testPerformanceRegression()
{
    $result = bench()
        ->compare(
            'old': fn () => $this->oldAlgorithm(),
            'new': fn () => $this->newAlgorithm()
        )
        ->toData();

    $this->assertLessThan(1.5, $result['new']['avg']['time'] / $result['old']['avg']['time']);
}

3. Template/Service Layer Benchmarks

// Benchmark Blade vs. inline PHP
bench()
    ->beforeEach(fn ($name) => View::share('data', $this->generateTestData()))
    ->compare(
        'blade': fn () => view('template')->render(),
        'php': fn () => $this->renderInlineTemplate()
    )
    ->toConsole();

4. Data Preparation Patterns

// Warmup + data setup
bench()
    ->warmup(3)
    ->beforeEach(fn ($name, $iteration) => $this->setupTestData($iteration))
    ->compare(
        'collection': fn ($data) => collect($data)->sum('value'),
        'array': fn ($data) => array_reduce($data, fn($carry, $item) => $carry + $item['value'], 0))
    )
    ->toConsole();

5. Regression Testing

// In a dedicated benchmark test file
bench()
    ->snapshots(__DIR__.'/../.benchmarks')
    ->compare(
        'cache': fn () => Cache::get('key'),
        'db': fn () => DB::table('cache')->where('key', 'key')->first()
    )
    ->toAssert()
    ->toBeRegressionTime(max: 10)
    ->toBeRegressionMemory(max: 5);

Gotchas and Tips

Common Pitfalls

  1. Cold Start Bias:

    • Issue: First iteration often slower due to OPcache/JIT warmup
    • Fix: Always use ->warmup(2) for accurate results
  2. Memory Leak Misinterpretation:

    • Issue: max memory might spike due to garbage collection timing
    • Fix: Use ->deviations(3) to smooth out variations
  3. Snapshot Directory Conflicts:

    • Issue: Multiple developers overwriting .benchmarks/
    • Fix: Commit snapshots to version control or use relative paths:
      ->snapshots(__DIR__.'/../../.benchmarks')
      
  4. Callback Parameter Confusion:

    • Issue: Forgetting beforeEach return value is passed to main callback
    • Fix: Document parameter usage:
      ->beforeEach(fn ($name, $iteration) => $this->prepareData())
      ->compare(
          fn ($data) => $this->process($data), // $data comes from beforeEach
      )
      
  5. Progress Bar Interference:

    • Issue: Console output corruption in CI environments
    • Fix: Add early in pipeline:
      ->disableProgressBar()
      

Debugging Techniques

  1. Inspect Raw Data:

    $data = bench()->compare(...)->toData();
    dd($data['callback_name']['avg']['time']); // Debug specific metric
    
  2. Visualize Deviations:

    bench()
        ->deviations(5)
        ->round(4)
        ->compare(...)
        ->toConsole();
    
  3. Isolate Variables:

    // Compare with fixed inputs
    $testData = $this->generateConsistentData();
    bench()
        ->beforeEach(fn ($name) => $this->resetState())
        ->compare(
            fn () => $this->methodA($testData),
            fn () => $this->methodB($testData),
        );
    

Advanced Tips

  1. Custom Output Formatting:

    // Extend Benchmark class to add CSV output
    class CSVBenchmark extends Benchmark {
        public function toCSV(): string {
            // Implement custom CSV generation
        }
    }
    
  2. Database-Specific Warmup:

    bench()
        ->warmup(5)
        ->before(fn () => DB::connection()->getPdo()->exec('SET SESSION query_cache_type = ON'))
        ->compare(...);
    
  3. Parallel Benchmarking (Laravel 10+):

    // Use Laravel's task scheduling for parallel runs
    Dispatch::later(now()->addMinutes(1), function () {
        bench()->compare(...)->toConsole();
    });
    
  4. Memory Profiling Integration:

    // Combine with Xdebug
    bench()
        ->beforeEach(fn () => xdebug_start_trace())
        ->afterEach(fn () => xdebug_stop_trace())
        ->compare(...);
    
  5. Environment-Specific Config:

    // In a service provider
    Benchmark::macro('ciConfig', function() {
        return $this->disableProgressBar()->iterations(20);
    });
    
    // Usage
    bench()->ciConfig()->compare(...);
    

Configuration Quirks

  1. Iteration Thresholds:

    • Default 100 iterations may be overkill for fast operations (<1ms)
    • Reduce to 10-20 for microbenchmarks:
      ->iterations(15)->deviations(2)
      
  2. Snapshot File Naming:

    • Files are named after the calling file + line number
    • Use absolute paths for consistency:
      ->snapshots(__DIR__.'/../../benchmarks')
      
  3. Static Closure Caveats:

    • Avoid static closures in callbacks if they reference class properties
    • Use arrow functions or bind explicitly:
      ->compare(
          [$this, 'method'], // Instead of fn() => $this->method()
      )
      
  4. Memory Measurement Limitations:

    • May not capture peak memory in some PHP versions
    • For critical memory checks, combine with:
      memory_get_peak_usage(true) // In bytes
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope