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

Stopwatch Laravel Package

symfony/stopwatch

Symfony Stopwatch is a lightweight profiling utility to measure execution time and memory usage in PHP. Start/stop named events, record laps, and group timings into sections (phases) to benchmark code paths and understand performance bottlenecks.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

Install via Composer:

composer require symfony/stopwatch

First Use Case: Profiling a Laravel Controller

use Symfony\Component\Stopwatch\Stopwatch;

public function index(Stopwatch $stopwatch)
{
    $stopwatch->start('controller_execution');

    // Your controller logic here
    $data = $this->fetchData();

    $event = $stopwatch->stop('controller_execution');

    // Log or display results
    \Log::info('Controller took ' . $event->getDuration() . 'ms');

    return view('home', compact('data'));
}

Key Starting Points

  1. Basic Timing: Use start()/stop() for granular profiling.
  2. Sections: Group related events (e.g., openSection('database')).
  3. Laps: Track intermediate steps within an event (lap('query_execution')).
  4. Dependency Injection: Laravel automatically resolves Stopwatch via service container.

Where to Look First


Implementation Patterns

Common Workflows

1. Middleware Profiling

public function handle($request, Closure $next, Stopwatch $stopwatch)
{
    $stopwatch->start('middleware_execution');

    $response = $next($request);

    $event = $stopwatch->stop('middleware_execution');
    \Log::debug('Middleware took ' . $event->getDuration() . 'ms');

    return $response;
}

2. Service Layer Instrumentation

public function fetchUserData(Stopwatch $stopwatch)
{
    $stopwatch->start('fetch_user_data');

    // Business logic
    $user = User::find($id);

    $stopwatch->lap('database_query');
    $data = $this->processUserData($user);

    $event = $stopwatch->stop('fetch_user_data');
    \Log::info('User data fetch: ' . $event->getDuration() . 'ms');

    return $data;
}

3. CLI/Artisan Commands

protected function execute(InputInterface $input, OutputInterface $output, Stopwatch $stopwatch)
{
    $stopwatch->start('command_execution');

    // Command logic
    $this->processFiles();

    $event = $stopwatch->stop('command_execution');
    $output->writeln(sprintf('Command took %dms', $event->getDuration()));
}

4. Database Query Profiling

public function getSlowQueries(Stopwatch $stopwatch)
{
    $stopwatch->start('query_execution');

    $results = DB::select('SELECT * FROM large_table');

    $event = $stopwatch->stop('query_execution');
    \Log::warning('Query took ' . $event->getDuration() . 'ms');

    return $results;
}

Integration Tips

Laravel-Specific Patterns

  1. Service Provider Binding:

    public function register()
    {
        $this->app->singleton(Stopwatch::class, function () {
            return new Stopwatch();
        });
    }
    
  2. Global Profiling Middleware:

    $router->middleware('profile', function ($request, $next, Stopwatch $stopwatch) {
        $stopwatch->start('request_' . $request->id());
        $response = $next($request);
        $event = $stopwatch->stop('request_' . $request->id());
        \Log::debug('Request ' . $request->id() . ' took ' . $event->getDuration() . 'ms');
        return $response;
    });
    
  3. Event Listeners:

    public function handle(Event $event, Stopwatch $stopwatch)
    {
        $stopwatch->start('event_' . get_class($event));
        // Handle event
        $stopwatch->stop('event_' . get_class($event));
    }
    

Advanced Patterns

  1. Contextual Data:

    $event = $stopwatch->stop('event_name');
    $event->setData(['user_id' => auth()->id(), 'query' => $query]);
    
  2. Section-Based Profiling:

    $stopwatch->openSection('database');
    $stopwatch->start('query_1');
    // ...
    $stopwatch->stop('query_1');
    $stopwatch->start('query_2');
    // ...
    $stopwatch->stop('query_2');
    $stopwatch->stopSection('database');
    
  3. Custom Event Formatting:

    $event = $stopwatch->stop('event_name');
    $formatted = sprintf(
        'Event: %s | Duration: %dms | Memory: %dKB',
        $event->getName(),
        $event->getDuration(),
        $event->getMemory() / 1024
    );
    

Gotchas and Tips

Pitfalls

  1. Memory Leaks:

    • Stopwatch events store memory usage data. For long-running processes (e.g., CLI scripts), manually clear events:
      $stopwatch->stop('event_name'); // Explicitly stop to free memory
      
  2. Nested Sections:

    • Avoid deeply nested sections (openSection()) as it can complicate event hierarchy and increase overhead.
  3. Event Naming Collisions:

    • Ensure unique event names when profiling multiple similar operations (e.g., query_user_1, query_user_2).
  4. Lap Timing Quirks:

    • Laps (lap()) measure time since the last lap or start, not the event start. Reset with start() if needed.
  5. PHP 8.1+ Requirement:

    • Stopwatch v8.x requires PHP 8.1+. Use v7.x for older versions:
      composer require symfony/stopwatch:^7.4
      
  6. Stopwatch Overhead:

    • Stopwatch adds ~1–5% latency per event. Disable in production or use sparingly.

Debugging Tips

  1. Inspect Events:

    $event = $stopwatch->stop('event_name');
    dump($event->getDuration(), $event->getMemory(), $event->getData());
    
  2. Check for Active Events:

    • Ensure stop() matches start() calls. Use:
      $stopwatch->getEvents(); // List all active events
      
  3. Memory Profiling:

    • Memory values (getMemory()) are approximate. For precise memory profiling, use Xdebug.
  4. Section Validation:

    • Verify sections are properly closed:
      $stopwatch->stopSection('section_name'); // Must match openSection()
      

Extension Points

  1. Custom Event Classes: Extend Symfony\Component\Stopwatch\StopwatchEvent to add metadata:

    class CustomEvent extends StopwatchEvent
    {
        public function setCustomData(array $data): self
        {
            $this->data['custom'] = $data;
            return $this;
        }
    }
    
  2. Stopwatch Decorator: Wrap Stopwatch to add logic (e.g., auto-logging):

    class LoggingStopwatch implements StopwatchInterface
    {
        private $decorated;
    
        public function __construct(Stopwatch $stopwatch)
        {
            $this->decorated = $stopwatch;
        }
    
        public function start($name, array $data = [])
        {
            $this->decorated->start($name, $data);
            \Log::debug("Started profiling: {$name}");
        }
    
        // Delegate other methods...
    }
    
  3. Laravel Service Provider Integration:

    public function boot()
    {
        $this->app->resolving(Stopwatch::class, function ($stopwatch) {
            $stopwatch->register('laravel', function () {
                return new LaravelStopwatchEvent();
            });
        });
    }
    

Configuration Quirks

  1. Time Precision:

    • Stopwatch uses microtime(true) for timing. For higher precision, consider custom implementations.
  2. Memory Measurement:

    • Memory values are based on memory_get_usage(). For accurate deltas, measure before/after:
      $startMemory = memory_get_usage();
      // ... code ...
      $endMemory = memory_get_usage();
      $memoryUsed = $endMemory - $startMemory;
      
  3. Event Lifecycle:

    • Events are immutable after creation. Modify data via setData() before stopping.
  4. Thread Safety:

    • Stopwatch is not thread-safe. Avoid sharing instances across threads/processes.

Performance Optimization Tips

  1. Disable in Production:

    if (app()->environment('production')) {
        $stopwatch = new Stopwatch(false); // Disable
    }
    
  2. Batch Events: For high-frequency events (e

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.
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
anil/file-picker
broqit/fields-ai