PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

Blackfire – DDEV setup, HTTP and CLI profiling, CI/CD assertions

by Henryk Tews / Monday, 03 June 2024 / Published in PHP, Środowiska

Blackfire is a PHP profiler that shows not just what is slow, but why – with call graphs, timeline, and SQL query analysis. Unlike Xdebug which shows you line-level execution, Blackfire aggregates and visualises the performance bottlenecks in a way that makes them immediately actionable. I show installation in DDEV, profiling HTTP requests and CLI commands, and writing performance assertions for CI/CD.

Blackfire vs Xdebug – different tools for different jobs

Aspect Xdebug Blackfire
Use case Stepping through code, debugging logic Performance profiling, finding bottlenecks
Overhead Very high (2-10x slower) Low (uses sampling)
Output Breakpoint inspection, var dump Call graph, timeline, SQL analysis
CI/CD integration Not practical Yes – performance assertions
Production use No Yes (on-demand profiling)

Installation in DDEV

# Add Blackfire to DDEV project
ddev get ddev/ddev-blackfire

# Set your credentials in .ddev/.env (gitignored)
BLACKFIRE_SERVER_ID=your-server-id
BLACKFIRE_SERVER_TOKEN=your-server-token
BLACKFIRE_CLIENT_ID=your-client-id
BLACKFIRE_CLIENT_TOKEN=your-client-token

# Restart to apply
ddev restart

# Verify Blackfire probe is loaded
ddev exec php -m | grep blackfire
# Output: blackfire

# Check agent is running
ddev exec blackfire agent:config

Profiling an HTTP request

# Profile a product page
blackfire curl https://magento2-dev.ddev.site/catalog/product/view/id/42

# Profile with custom options
blackfire --samples=10 curl https://magento2-dev.ddev.site/

# Profile with authentication header
blackfire curl https://magento2-dev.ddev.site/rest/V1/products/MG-001 \
  -H 'Authorization: Bearer YOUR_TOKEN'

# The command outputs a URL to the Blackfire dashboard
# where you see the full call graph and SQL queries

Profiling a CLI command

# Profile a Magento reindex
ddev exec blackfire run php bin/magento indexer:reindex catalog_product_price

# Profile a custom import command
ddev exec blackfire run php bin/magento vendor:import:products --limit=100

# Profile with more samples for better accuracy
ddev exec blackfire --samples=5 run php bin/magento catalog:product:attributes:cleanup

Understanding the Blackfire output

# Key metrics in the Blackfire dashboard:

Wall Time:     Total execution time including I/O waits
CPU Time:      Time actually using the CPU
Memory:        Peak memory usage
SQL Queries:   Count and total time of database queries
HTTP Requests: Count of external HTTP calls

# Call Graph interpretation:
# - Width of a node = % of total time spent in that function
# - Red nodes = hot paths (most time spent here)
# - Click a node = see callers and callees

# Common findings in Magento 2:
# 1. Catalog\Model\ResourceModel\Product\Collection::load() - very wide = too many products
# 2. config::get() called 500+ times - missing caching
# 3. Identical SQL queries repeated N times = N+1 problem
# 4. serialize()/unserialize() with large objects = expensive serialization

Performance assertions in CI/CD

# .blackfire.yaml - define performance expectations
tests:
    "Product page loads fast":
        path: /catalog/product/view/id/42
        assertions:
            - main.wall_time < 500ms
            - main.peak_memory < 64mb
            - metrics.sql.queries.count < 50
            - metrics.http.requests.count == 0  # no external HTTP calls

    "Category page":
        path: /shoes
        assertions:
            - main.wall_time < 800ms
            - metrics.sql.queries.count < 80

    "Homepage":
        path: /
        assertions:
            - main.wall_time < 300ms
            - main.peak_memory < 32mb
# .github/workflows/performance.yml
name: Performance Tests

on:
  pull_request:
    branches: [main]

jobs:
  blackfire:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Blackfire tests
        uses: blackfireio/github-action@v1
        with:
          client-id:     ${{ secrets.BLACKFIRE_CLIENT_ID }}
          client-token:  ${{ secrets.BLACKFIRE_CLIENT_TOKEN }}
          server-id:     ${{ secrets.BLACKFIRE_SERVER_ID }}
          server-token:  ${{ secrets.BLACKFIRE_SERVER_TOKEN }}
          config:        .blackfire.yaml
          endpoint:      https://staging.shop.example.com

Profiling programmatically in PHP

<?php

// Auto-instrumentation: add custom spans to see your code in the timeline
// Useful when you want to see exactly where within a request your code runs

use Blackfire\Client;
use Blackfire\Profile\Configuration;

class ProductImporter
{
    public function import(array $products): void
    {
        // Instrument a specific method
        $probe = \BlackfireProbe::getMainInstance();
        $probe->enable();

        foreach ($products as $product) {
            $this->importSingle($product);
        }

        $probe->disable();
    }

    private function importSingle(array $data): void
    {
        // Add a custom marker visible in the Blackfire timeline
        \BlackfireProbe::micro(__METHOD__ . ':start');
        $this->saveToMagento($data);
        \BlackfireProbe::micro(__METHOD__ . ':end');
    }
}

Summary

Blackfire is the professional PHP profiling tool - it gives you actionable data where Xdebug gives you inspection capability. In DDEV the setup takes about 10 minutes. The call graph immediately shows the widest nodes (most time) and SQL query count per request. Performance assertions in CI/CD prevent performance regressions from reaching production - a product page that was 300ms should not silently become 800ms after a feature change.

About Henryk Tews

What you can read next

DDEV advanced – mutagen, custom services, hooks, shared team configuration
GitHub Actions – PHP pipeline, test matrix, staging deploy via SSH
Production to dev migration – mydumper, GDPR anonymisation, DDEV automation hooks

© 2026 Created by

TOP
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Always active
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
Zobacz preferencje
  • {title}
  • {title}
  • {title}