Skip to content

Recipes

Muhammet Şafak edited this page May 25, 2026 · 1 revision

Recipes

Real-world patterns for using PerformanceMeter. Each recipe is self-contained and copy-pasteable into a fresh script.

Index

Recipe What it shows
CLI Benchmark Script A bench.php that prints elapsed / memory / peak in one summary line.
Cron Job Timing Log Append one line per scheduled run to a log file for low-fi trend analysis.
A/B Comparison of Two Implementations Reset-between-runs pattern for comparing candidate implementations.
Peak Memory Tracking Tracking the high-water mark through distinct phases of a script.

Each recipe page calls out the relevant caveats — microbenchmark noise, formatter caveats, why reset() is necessary, etc.

Cross-cutting tips

A few patterns that come up in more than one recipe.

Namespace your checkpoint names

The registry is global. If your code might run alongside another library that uses PerformanceMeter, prefix your names with a stable token so you do not collide:

PerformanceMeter::setPointer('mylib:request:start');
PerformanceMeter::setPointer('mylib:request:end');

A two- or three-part dotted/colon-separated name is enough — there is no built-in namespacing, this is a convention.

Use register_shutdown_function() for "run-to-end" totals

If you want a single "total time" / "peak memory" line at the very end of a script, regardless of how many exit / die paths exist:

PerformanceMeter::setPointer('boot');

register_shutdown_function(static function (): void {
    fwrite(STDERR, sprintf(
        "elapsed=%ss peak=%s\n",
        PerformanceMeter::elapsedTime('boot'),
        PerformanceMeter::peakMemoryUsage(),
    ));
});

The shutdown function runs after every code path, including fatal errors, so the measurement always lands.

Defeat opcode-cache caching when benchmarking small snippets

If you are comparing two implementations and PHP's opcode cache (or your IDE's auto-formatter) reorders cold load behaviour, your first iteration of each will look slower than subsequent ones. The common fix is a warm-up loop you discard:

// warm-up — measurements thrown away
for ($i = 0; $i < 3; $i++) {
    $fn();
}

// measured loop
PerformanceMeter::setPointer('s');
for ($i = 0; $i < 1_000; $i++) {
    $fn();
}
PerformanceMeter::setPointer('e');

For anything serious, use phpbench/phpbench — it handles warm-up, outlier rejection, and statistical confidence properly.

Combine with try/finally for guaranteed measurement around exceptions

PerformanceMeter::setPointer('handler:start');

try {
    $handler->run();
} finally {
    PerformanceMeter::setPointer('handler:end');
    log_metric(PerformanceMeter::elapsedTime('handler:start', 'handler:end'));
}

The measurement records and the metric is logged even if $handler->run() throws.

Clone this wiki locally