Blackfire.io — profiling PHP apps in production
Intermediate5 min read·php-15-003
performance
Concept
Xdebug is the primary debugging and profiling extension for PHP. Its profiling mode generates Cachegrind-format output files that can be analyzed with tools like KCachegrind (Linux), Qcachegrind (Mac), or Webgrind (web-based).
Xdebug modes (Xdebug 3+): Set xdebug.mode in php.ini:
off: Disabled (use in production — overhead is otherwise too high).develop:var_dump()improvements, stack traces.coverage: Code coverage for PHPUnit.profile: Generate profiling output files.trace: Function call tracing.debug: Step debugging (used with VS Code / PHPStorm).
Profiling flow:
- Set
xdebug.mode = profileandxdebug.output_dir = /tmp/xdebugin php.ini. - Trigger profiling with
XDEBUG_PROFILE=1query parameter or cookie, or enable for all requests withxdebug.start_with_request = yes. - Run the request/script.
- Open the generated
cachegrind.out.*file in KCachegrind.
Xdebug's output: A Cachegrind file with: per-function timing, call count, inclusive time (self + children), exclusive time (just this function). This reveals which functions are hot spots.
Important: Xdebug adds 10-20% overhead even when not actively profiling. NEVER enable Xdebug in production. Use xdebug.mode = off in production and only enable in development/staging environments.
Code Example
ini
; php.ini — development settings for profiling
[xdebug]
zend_extension = xdebug.so
xdebug.mode = profile
xdebug.output_dir = /tmp/xdebug
xdebug.profiler_output_name = cachegrind.out.%t.%H_%R
; Profile only when triggered (recommended — not every request)
xdebug.start_with_request = trigger
; Or profile all requests (noisy but useful for CLI):
; xdebug.start_with_request = yesbash
# Trigger profiling for a specific request
curl "https://app.local/api/orders?XDEBUG_PROFILE=1"
# Or via browser — add XDEBUG_PROFILE cookie
# Run a CLI script with profiling
XDEBUG_CONFIG="mode=profile" php artisan queue:work --once
# Open in KCachegrind (Linux)
kcachegrind /tmp/xdebug/cachegrind.out.1234
# Open with qcachegrind (macOS via homebrew)
brew install qcachegrind
qcachegrind /tmp/xdebug/cachegrind.out.1234
# Webgrind (web-based — Docker-friendly)
# docker run -p 8080:80 --volume=/tmp/xdebug:/tmp jokkedk/webgrindphp
<?php
// Check if Xdebug is active
if (function_exists('xdebug_info')) {
xdebug_info(); // displays Xdebug configuration
}
// Manually start/stop profiling in code
if (function_exists('xdebug_start_profiling')) {
xdebug_start_profiling();
// ... code to profile ...
xdebug_stop_profiling();
// dump written to xdebug.output_dir
}
// xdebug_var_dump — enhanced var_dump (respects xdebug.develop mode)
xdebug_var_dump(['nested' => ['data' => 42]]);