Blackfire ou comment profiler votre application PHP ?
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.
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.
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.
Conclusion
Blackfire est un outil qui va permettre d’optimiser certains processus.
A mon niveau, ses avantages sont :
- fourni par SensioLabs, marque de qualité dans le monde du développement logiciel PHP ;
- simple à mettre en place ;
- rendu web du profilage très propre ;
- des nouveautés avec le support de nouvelles intégrations, ou de l’utilisation de Blackfire dans les tests unitaires.
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