Unprofitable profiles php. Profiling and debugging PHP applications using xhprof & FirePHP. Code optimization based on profiling data

An extension to PHP called Xdebug is available to assist in profiling PHP applications, as well as runtime debugging. When running the profiler, the output is written to a file in a binary format called "cachegrind". Applications are available on each platform to analyze these files. No application code changes are necessary to perform this profiling.

To enable profiling, install the extension and adjust php.ini settings. Some Linux distributions come with standard packages (e.g. Ubuntu's php-xdebug package). In our example we will run the profile optionally based on a request parameter. This allows us to keep settings static and turn on the profiler only as needed.

# php.ini settings # Set to 1 to turn it on for every request xdebug.profiler_enable = 0 # Let's use a GET/POST parameter to turn on the profiler xdebug.profiler_enable_trigger = 1 # The GET/POST value we will pass ; empty for any value xdebug.profiler_enable_trigger_value = "" # Output cachegrind files to /tmp so our system cleans them up later xdebug.profiler_output_dir = "/tmp" xdebug.profiler_output_name = "cachegrind.out.%p"

Next use a web client to make a request to your application"s URL you wish to profile, e.g.

Http://example.com/article/1?XDEBUG_PROFILE=1

As the page processes it will write to a file with a name similar to

/tmp/cachegrind.out.12345

By default the number in the filename is the process id which wrote it. This is configurable with the xdebug.profiler_output_name setting.

Note that it will write one file for each PHP request / process that is executed. So, for example, if you wish to analyze a form post, one profile will be written for the GET request to display the HTML form. The XDEBUG_PROFILE parameter will need to be passed into the subsequent POST request to analyze the second request which processes the form. Therefore when profiling it is sometimes easier to run curl to POST a form directly.

Analyzing the Output

Once written the profile cache can be read by an application such as or Webgrind. PHPStorm, a popular PHP IDE, can also display this profiling data .

KCachegrind, for example, will display information including:

  • Functions executed
  • Call time, both itself and inclusive of subsequent function calls
  • Number of times each function is called
  • Call graphs
  • Links to source code

What to Look For

Obviously performance tuning is very specific to each application"s use cases. In general it"s good to look for:

  • Repeated calls to the same function you wouldn't expect to see. For functions that process and query data these could be prime opportunities for your application to cache.
  • Slow-running functions. Where is the application spending most of its time? the best payoff in performance tuning is focusing on those parts of the application which consume the most time.

Note: Xdebug, and in particular its profiling features, are very resource intensive and slow down PHP execution. It is recommended to not run these in a production server environment.

Using profiling systems, you can collect information about which functions in PHP code consume more CPU time and RAM, that is, identify the slowest and most memory-demanding places in a PHP program.

xhprof

XHProf - PHP profiler developed by Facebook.

Installation:

Aptitude install php-pear pecl install xhprof-0.9.4 echo "extension=xhprof.so" > /etc/php5/mods-available/xhprof.ini ln -s /etc/php5/mods-available/xhprof.ini /etc /php5/conf.d/xhprof.ini apachectl restart

The files necessary for work are located in the directory /usr/share/php. However, not everything, but only with PHP code. For normal display of reports, jquery and css are required. They can be obtained from the github repository:

Git clone https://github.com/facebook/xhprof.git

After this, add the line to the PHP script code in the place where data collection should begin:

Xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);

Parameters for data collection are indicated in parentheses. In this case, data will be collected on processor load and RAM usage. One more option is possible XHPROF_FLAGS_NO_BUILTINS when used, data on built-in functions is not collected.

$xhprof_data = xhprof_disable(); include_once "xhprof_lib/utils/xhprof_lib.php"; include_once "xhprof_lib/utils/xhprof_runs.php"; $xhprof_runs = new XHProfRuns_Default(); $run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_test"); echo "Report: http://domain.tld/xhprof_html/index.php?run=$run_id&source=xhprof_test"; echo "\n";

In line $run_id The quotation marks indicate the name of the profile, which can be set arbitrarily.

The processed result looks like this:

If you specify the parameter XHPROF_FLAGS_NO_BUILTINS, it is clear that the number of function calls is significantly reduced:

The table provides the following information:

Calls- number of function calls,
Wall Time- the total operating time of the function, including the time spent waiting for a response from external resources,
CPU- how much time was spent processing functions,
MemUse- how much RAM was used,
PeakMemUse- peak memory consumption.

The modifiers are:

Incl- inclusive - taking into account calls to other functions from this function,
Excl.- exclusive - excluding function calls.

In addition, above the table there is information about the total processing time, memory used and the number of function calls.

Also XHProf allows you to build differential reports between two runs, which are indicated by red and green colors. With these reports, you can get a clear picture of improvements after each code change.

To obtain such a report, you need to use a link like this:

http://domain.tld/xhprof_html/index.php?run1=run_id1&run2=run_id2&source=xhprof_test

Where run_id1 And run_id2- launch identifiers.

If you install Graphviz:

Aptitude install graphviz

There are also third-party web interfaces for php profiler xhprof that use databases:

xDebug

xDebug- PHP code debugger with profiling capability, written by Derick Rethans.

Installation:

Yum install php5-xdebug

Then we edit the config:

Nano /etc/php5/mods-available/xdebug.ini

adding the lines to it:

Xdebug.profiler_enable = 1 xdebug.profiler_aggregate = On xdebug.profiler_output_dir = /tmp

Here we enable the PHP profiler and specify the directory in which to store the profiles. Profiles are created with names like cachegrind.out.*

There is a webgrind web client: https://github.com/jokkedk/webgrind. It doesn't work very fast, but it allows you to quickly view small profiles. In fact, this is the PHP code that needs to be cloned from github:

Git clone https://github.com/jokkedk/webgrind.git

a directory will be created webgrind, which you need to copy to the directory of any website and access it from the browser. Next, to make plotting in the configuration file work in Debian config.php you need to correct the path to the executable file graphviz. It should look like this:

Static $dotExecutable = "/usr/bin/dot";

In addition, you can adjust the time zone:

Static $defaultTimezone = "Europe/Moscow";

In the header, you can select a profile and check the box to take into account built-in functions. The table itself shows the functions, the number of calls, the operating time of the function itself and the time including waiting. To go deeper into the functions, just click on the triangular arrow. In my case, with fairly large profiles (from several megabytes), the wait for the result was unnecessarily high. It is probably better to use local viewing programs for fairly large profiles.

The graph might look like this:

note that webgrind should not be used on production servers, since no authorization is provided, but there is access to the php file code. If necessary, use at least basic Apache authorization.

There are also programs for analyzing profiles for Linux:

About profiling

Profile data can help you improve your application, that is, achieve certain goals, for example, reduce memory consumption, reduce page generation time, and so on.

The information in the profile is the starting point for optimization: it tells how long it takes to generate the result, how much memory is used and how many function calls are made. With more detailed data, you can improve these metrics.

For example, if you are using a framework, then using some functions of the framework may lead to calls to several basic functions. If you are reading some data multiple times, it may be worth storing the result in a variable.

The profiler can also help you understand where to use PHP code caching, for example, using APCu or memcached.

First of all, it is worth optimizing the functions that require the most execution time. Once everything is optimized and it seems that there is nothing left to improve, it is worth sorting functions by the number of calls and working on reducing it. Even if PHP is fast, it's worth considering whether you need to call functions that often?

If you encounter the following situations, you should consider caching:

  • Immutable functions are called inside a loop,
  • Some content is generated twice,
  • Content that does not change is generated every time,
  • Content is generated even if not used.

You shouldn't cache everything, since memory is also a valuable resource. Cache the data you access constantly. Also, caching makes little sense if caching wastes more resources than it saves.

In addition to caching in the code, do not forget about caching using the web server (), as well as on the client side. If you use the right headers, many requests can be resolved before they even reach the server.

FirePHP is an extension for firebug, which, in conjunction with its small php class, allows you to broadcast data from php, for example, all sorts of var_dump and other debugging information, to the firebug console. The main advantage of this extension is that all debugging information is broadcast through headers and does not litter the pages and does not break the logic of the application in any way. Official website: http://firephp.org/.

Main idea.

The general profiling algorithm is as follows:
  1. At the beginning of the page we enable profiling using xhprof_enable()
  2. At the end of the page, turn off profiling using xhprof_disable() and save the collected data using save_run()
  3. Next, using the firephp php class, we pass a link to the profiling data to the client part
  4. In the firebug console we open the information we need
  5. We rejoice :)
I would also like to say that, of course, manually adding these functions to your PHP scripts is great. But I want this information to always be at hand during development, and not end up on the production servers. We solve this problem as follows:

In our projects, in almost all scripts, a working file with a class loader, connecting functions and other necessary things is connected at the beginning. Therefore, we included the inclusion of profiling in this file. And in order to be able to turn on/off the debugging mode at will, we added a check for the configuration constant, plus we wrapped these checks in some meta tags that are automatically removed when the project is built. The same applies to turning off profiling and writing information to headers using firephp - these tasks are solved by one function, which is called at the end of each PHP script and is also wrapped in meta tags. It looks something like this:

// The following constants are written in the application config file

/** Mode of operation of the environment * */
define("APPLICATION_ENV" , "dev" ); // dev - debugging | pro - production
/** Path to profiler */
define("XHPROF_ROOT" , __DIR__ . "/ExtProcs/debug/xhprof-0.9.2");

/***************************************************************************************
* Next, in the file that is loaded at the beginning of each script, we launch profiling
* DEV_START and DEV_END are our meta tags, everything between them is cut out during assembly
***************************************************************************************/

//-- DEV_START
//-- in debug mode we connect debug libraries

// Load firephp
require_once(__DIR__ . "/includes/ExtProcs/debug/firephp/FirePHP.class.php");
//-- load the profiler
"/xhprof_lib/utils/xhprof_lib.php");
require_once(XHPROF_ROOT. "/xhprof_lib/utils/xhprof_runs.php");
// Initialize profiling with the necessary flags. Detailed description of flags
// can be found at php.net/manual/ru/xhprof.constants.php
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
}
//-- DEV_END

// Well, this function is called at the end of each script
// Its call is also wrapped in DEV_START and DEV_END

/**
* Create a link to the profiling result and display it in the console
*/
function dev_boot_Down() (
if (APPLICATION_ENV === "dev" ) (
// Initialize the firephp instance
$firephp = FirePHP::getInstance(true);
// Turn off profiling and save data
$xhprof_data = xhprof_disable();
$xhprof_runs = new XHProfRuns_Default();
$run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_testing" );
// Create a link to the profiling data and write it to the console
$link = "http://" . $_SERVER["HTTP_HOST" ] . "/includes/ExtProcs/debug/xhprof-0.9.2/xhprof_html/index.php?run=($run_id)&source=xhprof_testing\n";
$firephp->info($link, "profiling data" );
}
}


* This source code was highlighted with Source Code Highlighter.

I won’t go into details about installing these extensions, because everything is simple here. I will only say about some aspects of the setup. xhproof has only one configuration variable - xhprof.output_dir, which points to the folder where profiling data will be saved. Therefore, make sure that the user under whom the PHP scripts are executed has write rights to the specified directory. So write something like this in your php.ini:


extension=xhprof.so
xhprof.output_dir="/var/tmp/xhprof"

It’s also a good idea to install something like dot or Graphviz to draw call graphs. I have Graphviz on MacOS X.

Having completed the procedures described above, we were able to open and look at the profiling of any of our scripts directly in the browser at any time.

Installing xhprof for php:

Sudo apt-get install php5-xhprof

Restart Apache:

Sudo service apache2 restart

Print phpinfo(); and check whether the module is connected or not?

We check /etc/php5/apache2/conf.d to see if a link to the xhprof.ini config appears there.

If not, then create the link yourself and restart Apache.

Sudo ln -s /etc/php5/mods-available/xhprof.ini /etc/php5/apache2/conf.d/20-xhprof.ini sudo service apache2 restart

We check the xhprof connection, check whether 20-xhprof.ini is connected:

The screenshot shows version 0.9.2, although during installation version 0.9.4 was displayed, but this is not a hindrance to us.

Now we can profile our code.

  1. At the beginning of the page, enable profiling using xhprof_enable();
  2. At the end of the page, turn off profiling using xhprof_disable() and save the collected data using save_run();
  3. Next we analyze.

Function xhprof_enable() takes flags as arguments:

XHPROF_FLAGS_CPU for recording processor statistics,

XHPROF_FLAGS_MEMORY - for memory,

XHPROF_FLAGS_NO_BUILTINS - to ignore built-in functions.

To save and further debrief, we need to install a profile analysis tool.

Download the archive with the analysis tool from the xhprof: page, take version 0.9.4.

On the server or local PC, create a folder accessible via localhost or a separate domain into which we unzip the downloaded archive:

Now we can save the profile.

https://xn--d1acnqm.xn--j1amh/altadmin/posts/edit/188

The tracking code looks something like this:

// Initialize the profiler - we will count both processor time and memory consumption xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
// Profiled code # Stop the profiler $xhprof_data = xhprof_disable(); # Save the report and generate a link to view it include_once "/var/www/html/xhprof-0.9.4/xhprof_lib/utils/xhprof_lib.php"; include_once "/var/www/html/xhprof-0.9.4/xhprof_lib/utils/xhprof_runs.php"; $xhprof_runs = new XHProfRuns_Default(); $run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_test"); echo "Report: http://localhost/xhprof-0.9.4/xhprof_html/index.php?run=$run_id&source=xhprof_test"; echo "\n";

/var/www/html/xhprof-0.9.4 - the path to the folder where we unzipped the libraries we need.

Report: http://localhost/xhprof-0.9.4/xhprof_html/index.php?run=57c32f3095d21&source=xhprof_test

This is what a profile analysis looks like. This table displays all function calls that are profiled.

We can sort the functions by clicking on the table headings.

When we see that some function is executed either many times or for a very long time, we can click on this function and a similar table will open but with internal calls inside the function in question and the parent environment where the function was called.

Indicators:
Total Inc. Wall Time (time spent on executing functions, taking into account waiting for responses from sockets, file system and other resources)
Total Inc. CPU (time spent executing functions)
Total Inc. MemUse (memory usage)
Total Inc. PeakMemUse (peak memory usage)
Number of Function Calls

There is also the option of graphically displaying the report. But to do this, you need to make sure that you have the graphviz library installed:

Apt-get install graphviz

Then in your profile you need to click to display and voila:

Now you can analyze and improve the code.