Generating PHP Flame Diagram Based on Xdebug

In 2012, you just started learning PHP. At that time, the application of PHP was very simple, there were not too many complex design modes, such as dependent injection, factory mode, which were few. Reflection API was just coming out at that time. A PHP application was some script files that packed the front-end code. Just because PHP was simple and reliable, the learning cost was very low, PHP became very popular in those years. You can quickly read PHP codes written by others, no matter how bad they are. I had just graduated at that time with my proficiency in PHP, I could easily get 7,800 salaries in the top 34 cities, plus thorough research into the source code of the major frameworks (Tp, Ci, Yii, Cphalcon) at that time, and thought I had touched the ceiling of PHP. Later, PHP was written less and less in cities, using a set of framework written by Swoole.

However, PHP now accounts for 90% of the company's share and is basically Laravel/Lumen apps, which makes it difficult for me to keep optimizing performance. Laravel uses a large number of design patterns, dynamic injection, many times only at runtime can we know the specific object instances, it is difficult to determine the running state of the service only by looking at the source code. Therefore, flame graphs and visual call stacks are important for performance analysis, and they can be very intuitive and accurate to see the various time-consuming.

In PHP, we can focus on two levels of flame graphs: the PHP core and the PHP Zend call stack. The former is a time consuming flame graph capturing system calls, and the latter is a time consuming flame graph of Zend VM. The two flame graphs are shared below.

Running Environment

Operating System (Arch Linux)

# neofech
                   -`                    russell@T14 
                  .o+`                   ----------- 
                 `ooo/                   OS: Arch Linux x86_64 
                `+oooo:                  Host: NBLK-WAX9X M1040 
               `+oooooo:                 Kernel: 5.14.14-arch1-1 
               -+oooooo+:                Uptime: 1 hour, 15 mins 
             `/:-:++oooo+:               Packages: 852 (pacman) 
            `/++++/+++++++:              Shell: zsh 5.8 
           `/++++++++++++++:             Resolution: 1920x1080 
          `/+++ooooooooooooo/`           DE: Plasma 5.23.2 
         ./ooosssso++osssssso+`          WM: KWin 
        .oossssso-````/ossssss+`         WM Theme: Breeze 
       -osssssso.      :ssssssso.        Theme: Breeze Light [Plasma], Breeze [GTK2/3] 
      :osssssss/        osssso+++.       Icons: Uos-fulldistro-icons [Plasma], Uos-fulldi 
     /ossssssss/        +ssssooo/-       Terminal: konsole 
   `/ossssso+/:-        -:/+osssso+-     Terminal Font: Hack 10 
  `+sso+:-`                 `.-/+oso:    CPU: AMD Ryzen 5 3500U with Radeon Vega Mobile G 
 `++:.                           `-/+/   GPU: AMD ATI 03:00.0 Picasso 
 .`                                 `/   Memory: 1928MiB / 6880MiB

PHP Version

# php -v
PHP 7.4.23 (cli) (built: Sep 19 2021 12:07:04) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Xdebug v3.1.1, Copyright (c) 2002-2021, by Derick Rethans

There's nothing to ask for, as long as it's not under version 5.6.

Laravel version

# php artisan -V
Laravel Framework 8.61.0

perf version

# perf -v
perf version 5.14.g7d2a07b76933

Download flamegraph

git clone https://github.com/brendangregg/FlameGraph.git
cd FlameGraph
# This step is to inject FlameGraph into the path of the executable file system so that the tools inside can be executed directly below.
export PATH=`pwd`:$PATH

This tool is critical to capture the time-consuming system calls through perf and generate a flame graph.

Grab PHP Kernel Flame Graph

Find the PHP process ID first, then grab it with the following command

# Grab PID for 7959 process for 60 seconds
perf record -F 99 -p 7959 -g -- sleep 30

Export Stack

perf script > out.perf

Generate Fold stacks file

stackcollapse-perf.pl out.perf > out.folded

Generate Flame Graph

flamegraph.pl out.folded > php-zend-flame-graph.svg

To see the effect, the svg format picture can be filtered by clicking on the flame bar (open a new tab):

Grab Zend VM Time-consuming Flame Graph

This flame graph generation relies on xdebug and different xdebug versions use different configurations. Configuration instructions can be viewed directly from the xdebug package configuration file or above Github Look.

Xdebug3 configuration:

zend_extension=xdebug
xdebug.mode=trace
xdebug.start_with_request=trigger
xdebug.trigger_value=StartProfileForMe
xdebug.trace_output_name = xdebug.trace.%t.%s
xdebug.output_dir = /tmp
xdebug.trace_format=1

Xdebug2 configuration:

xdebug.trace_output_name = xdebug.trace.%t.%s
xdebug.trace_enable_trigger = 1
xdebug.trace_output_dir = /tmp
xdebug.trace_enable_trigger_value = "<secret key>"
xdebug.trace_format=1

Request interface url to get php stack data curl http://youdomain.com?XDEBUG_ TRACE=<secret key>. The trace file starts with xdebug.tarce in the / tmp directory.

Convert stack data (if stackcollapse-xdebug.php does not exist, note the download flamegraph description above):

stackcollapse-xdebug.php /tmp/xdebug.trace.1635786267._data_workspaces_study_laravel-framework_laravel_server_php.xt

If the xdebug trace file is in gz format, convert it:

# The parameter `-dk'means to unzip and preserve the source file.
gzip -dk /tmp/xdebug.trace.1635786267._data_workspaces_study_laravel-framework_laravel_server_php.xt.gz

Convert stack data

stackcollapse-xdebug.php xdebug.trace.1635786267._data_workspaces_study_laravel-framework_laravel_server_php.xt > out.folded

Generate Flame Graph

flamegraph.pl out.folded > laravel-flame-graph.svg

To see the effect, the svg format picture can be filtered by clicking on the flame bar (open a new tab):

Tags: PHP

Posted on Mon, 01 Nov 2021 13:24:45 -0400 by andr923