Weave 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

Performance Laravel Package

bvanhoekelen/performance

A PHP/Laravel performance measurement package that profiles execution time, memory usage, and database queries, then presents a clear report to help you spot bottlenecks and optimize your application.

Deep Wiki
Context7

Getting Started

Install

composer require bvanhoekelen/performance

Laravel 5.5+ picks it up via package auto-discovery (PerformanceServiceProvider + Performance facade alias). On older Laravel or when auto-discovery is disabled, register manually in config/app.php:

'providers' => [
    Bvanhoekelen\Performance\PerformanceServiceProvider::class,
],
'aliases' => [
    'Performance' => Bvanhoekelen\Performance\Facades\Performance::class,
],

For plain Composer projects, just require 'vendor/autoload.php' and use the class directly.

Where to look first

  • The package README for the exact start() / stop() / output() surface — the API is small, so five minutes there is enough.
  • vendor/bvanhoekelen/performance/src — the facade and the Performance class are the whole story; there is no large config surface to learn.
  • Your framework's query log, because that is what feeds the DB-query metric.

First use case

Wrap a slow controller action or Artisan command and see time, peak memory, and query count in one table:

use Bvanhoekelen\Performance\Facades\Performance;

Performance::start();
// ... the code you suspect is slow
Performance::stop()->output();

In a browser you get an HTML table; on the CLI (Artisan, queue worker) you get a text table. That single call is usually enough to answer "is this slow because of queries, memory, or just CPU?"

Implementation Patterns

Block measurement around arbitrary code

The core pattern is start/stop around any region — a controller method, a service call, an Artisan command body, a loop iteration:

Performance::start();
$report = $this->reportBuilder->build($params);
Performance::stop()->output();

Named measurements for multi-segment requests

Pass a label to both calls to time several phases independently, then render them together:

Performance::start('validate');
$request->validate($rules);
Performance::stop('validate');

Performance::start('query');
$orders = Order::with('items')->where(...)->get();
Performance::stop('query');

Performance::start('render');
return view('orders.index', compact('orders'));
Performance::stop('render')->output();

This is the pattern worth standardizing on: it tells you immediately whether a regression is in validation, the ORM, or the view layer.

Closure form

For one-off probes, wrap the work instead of scattering start/stop calls:

Performance::measure(function () use ($payload) {
    $this->importer->run($payload);
})->output();

Local-only middleware

The most useful day-to-day integration is a middleware that is registered only in local/staging. Start in handle(), stop and emit after the response is built (in terminate() or after the response object is returned), and gate it behind an env flag:

if (app()->environment('local') && config('app.performance_overlay')) {
    Performance::start('request');
}

Console and queues

In Artisan commands and jobs, output() goes to stdout/log-friendly text, which makes it a cheap ad-hoc profiler for nightly imports and queue workloads. For queue workers, prefer emitting after the job rather than mid-job so timings reflect the whole unit of work.

Enable query logging when you need query detail

Query counts come from Laravel's query log, so confirm it is enabled for the code path you are measuring (DB::enableQueryLog() on the connection, or the equivalent config toggle). Without it, query numbers will read as zero and you will chase the wrong bottleneck.

Keep it out of production paths

Wire it behind APP_DEBUG / environment checks, or a config flag that defaults to false. Treat it as a development probe, not instrumentation.

Gotchas and Tips

  • output() echoes markup. In a JSON endpoint or behind a return response()->json(...) this corrupts the payload. Capture or restrict to local HTML responses, or route the table into a log entry instead.
  • Query log is itself expensive. Laravel's query log retains every query object in memory, which inflates the very memory number you are trying to read on large requests. Enable it for the measurement window only.
  • Peak memory is monotonic. memory_get_peak_usage() only ever rises, so a "start vs stop" memory delta reflects the high-water mark, not what is live at stop time. Do not interpret a drop in memory as freed memory; compare separate requests instead.
  • Labels must be unique per measurement. Reusing a label across overlapping segments (or nested calls) will overwrite or confuse the report. Namespace labels when measuring inside loops.
  • Header/output-buffer issues. Printing a table mid-response, after output has started, produces headers-already-sent warnings or a table rendered in the wrong place. Emit at the end of the request lifecycle.
  • Auto-discovery failures. Packages inside a non-standard skeleton, or projects with dont-discover, produce a "class not found" facade error. That is a registration problem, not a package bug.
  • Long-running processes (Octane, queue daemons). Static measurement state can leak across requests/jobs. Reset explicitly between units of work rather than relying on per-request assumptions.
  • Time is wall-clock, not CPU. I/O waits dominate. Run the measurement several times, with OPcache warm and Xdebug off, before concluding anything — especially in Docker where filesystem I/O can swamp the signal.
  • It is not a profiler. It answers "how long / how much memory / how many queries," not "which function." When you need a call-graph, reach for Xdebug, Tideways, or Blackfire and use this package to bracket the suspect region for them.
  • Extension point is the facade. The measurement surface is thin and static, so the practical customization is a tiny project-level helper (e.g. perf_probe('label', $callback)) that adds the environment gate, logging destination, and label conventions your team uses — keep that wrapper as the only import in application code so you can swap the backend later without touching call sites.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core