0

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:

  1. Set xdebug.mode = profile and xdebug.output_dir = /tmp/xdebug in php.ini.
  2. Trigger profiling with XDEBUG_PROFILE=1 query parameter or cookie, or enable for all requests with xdebug.start_with_request = yes.
  3. Run the request/script.
  4. 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 = yes
bash
# 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/webgrind
php
<?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]]);