RootsLabs

More than a tool ! GitHub Google+ LinkedIn RSS

Blackfire ou comment profiler votre application PHP ?

Progi1984 - Commentaires (0)

Blackfire est un outil fourni par SensioLabs afin de profiler du code PHP, et ainsi trouver les goulots d’engorgement du code, les endroits où l’on pourrait mettre du cache, etc…
Dans cet article, nous allons voir comment l’installer via Docker, l’utiliser et un cas d’utilisation avec PHPPresentation.

Blackfire : Logo

Pré-requis

Sur la page Credentials de Blackfire, quatre clés seront disponibles :

  • Client ID ;
  • Client Token ;
  • Server ID ;
  • Server Token.

Installation de Blackfire avec Docker

Pour le fichier docker-compose.yml, j’ai modifié le container php, je lui ai ajouté les variables d’environnement utiles pour Blackfire.

## PHP
php:
  build: .docker/php
  restart: always
  ports:
    - "9000:9000"
  volumes:
    - ./:/var/www/local.dev
    - ./.docker/php/ini/php.ini:/usr/local/etc/php/php.ini
  environment:
    BLACKFIRE_LOG_LEVEL: 4
    BLACKFIRE_SERVER_ID: XXXXXXXXXXXXXXXXXXXXXXXX
    BLACKFIRE_SERVER_TOKEN: XXXXXXXXXXXXXXXXXXXXXXXX
  links:
    - db:db

J’ai aussi modifié le fichier Dockerfile, qui va générer le container php, en lui ajoutant les ligne en surligné pour Blackfire :

FROM php:5.6-fpm

RUN apt-get update && apt-get install -y \
        libfreetype6-dev \
        libjpeg62-turbo-dev \
        libmcrypt-dev \
        libpng12-dev \
        libsqlite3-dev \
        libssl-dev \
        libcurl3-dev \
        libxml2-dev \
        libzzip-dev \
    && docker-php-ext-install iconv json mcrypt mbstring mysql mysqli pdo_mysql pdo_sqlite phar curl ftp hash session simplexml tokenizer xml xmlrpc zip \
    && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
    && docker-php-ext-install gd

RUN pecl install xdebug \
    && touch $PHP_INI_DIR/conf.d/xdebug.ini \
    && echo 'zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20131226/xdebug.so' >> $PHP_INI_DIR/conf.d/xdebug.ini \
    && echo 'xdebug.remote_enable=1' >> $PHP_INI_DIR/conf.d/xdebug.ini \
    && echo 'xdebug.remote_connect_back=1' >> $PHP_INI_DIR/conf.d/xdebug.ini \
    && echo 'xdebug.var_display_max_depth=10' >> $PHP_INI_DIR/conf.d/xdebug.ini \
    && echo 'xdebug.cli_color=1' >> $PHP_INI_DIR/conf.d/xdebug.ini \
    && echo 'xdebug.show_local_vars=1' >> $PHP_INI_DIR/conf.d/xdebug.ini
	
RUN export VERSION=`php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;"` \
    && curl -A "Docker" -o /tmp/blackfire-probe.tar.gz -D - -L -s https://blackfire.io/api/v1/releases/probe/php/linux/amd64/${VERSION} \
    && tar zxpf /tmp/blackfire-probe.tar.gz -C /tmp \
    && mv /tmp/blackfire-*.so `php -r "echo ini_get('extension_dir');"`/blackfire.so \
    && echo "extension=blackfire.so\nblackfire.agent_socket=\${BLACKFIRE_PORT}" > $PHP_INI_DIR/conf.d/blackfire.ini
	
RUN curl -s https://packagecloud.io/gpg.key | apt-key add - \
    && echo "deb http://packages.blackfire.io/debian any main" | tee /etc/apt/sources.list.d/blackfire.list \
    && apt-get update \
    && apt-get install blackfire-agent
	
WORKDIR /var/www

CMD ["php-fpm"]

Après ces modifications, vous devez regénérer le container php :

docker-compose build php

Et lancer tous les containers :

docker-compose up

Utilisation de Blackfire sur un fichier

Malgré une ligne de commande assez complexe, l’utilisation reste assez simple.

Il faut tout d’abord récupérer l’ID du container PHP via un docker ps.

Après cela, on lance la commande pour analyser un fichier PHP en ligne de commande :

docker exec -i CONTAINER_ID blackfire --client-id="XXXXX" --client-token="XXXXX" run php CHEMIN_DU_FICHIER

Pour cela, on a besoin de l’ID du container, des clés récupérés dans les pré-requis et le chemin du fichier à exécuter.

Cas d’utilisation : PHPPresentation

Pour tester Blackfire, je voulais un véritable cas d’exemple et j’ai pensé à un de mes projets open source : PHPPresentation.

Je suis parti d’un exemple (Sample_01_Complex.php) que j’ai profilé. Un point m’a choqué : la méthode writeAttribute faisait un nombre important d’appels à une méthode magique.
Blackfire : Avant l'optimisation

En poussant un peu plus loin, je me suis aperçu que la classe XMLWriter de PhpOffice\Common stockait dans un attribut une instance de XMLWriter et faisait des appels via la méthode magique __call. J’ai modifié le code pour que XMLWriter hérite directement de la classe native XMLWriter.

Lien du commit : https://github.com/PHPOffice/Common/commit/cfeb9d71c09e38441d5ec06f21855733d0c71077

Et voilà, comment optimiser son code pour éviter des appels inutiles : cela a permis de gagner 29ms au niveau de la méthode writeSlide().
L’image ci-dessous est un comparatif entre le profilage avant la modification et le profilage après la modification. On y voit rapidement les gains en temps processeur au niveau des méthodes.

Blackfire : Gain avant / après

Conclusion

Blackfire est un outil qui va permettre d’optimiser certains processus.
A mon niveau, ses avantages sont :

A mon niveau, ses inconvénients sont :

  • le plan Hack qui ne permet pas de garder plus d’une journée son profilage ;
  • aucun plan pour des projets Open Source ;
  • la possibilité de ne pas définir via le Dockerfile le CLIENT_ID et le CLIENT_SECRET afin de faciliter la ligne de commande.

Je dirais que Blackfire est un bon outil à mettre dans les mails des entreprises mais pour les fans d’open source qui souhaiteraient faire du profilage, il faut regarder les solutions alternatives : XHProf ou XDebug.

Merci à Christophe Dujarric pour les logos.

Ajouter un commentaire

Commentaire :