-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
How to use xhprof
Note
Last tested on: 28/03/2025
Warning
You must have a volume mounted to be able to get the profiles on your host file system
And depending on how the container runs you might also need to run: chmod 777 build/profiles/
Enter the container: docker exec -u root -it containerName bash
# See (below): Install the `xhprof` extension using pecl
# Setup the built extension
echo 'extension=xhprof.so' > /usr/local/etc/php/conf.d/docker-php-ext-xhprof.ini
# Install nano (or any other editor)
apt update && apt install nano -y
# Edit the index file
nano index.php
# Apply (below): Patch your `index.php` file
# Install graphviz (if you host xhprof web UI in the container build folder)
# apt update && apt install graphviz -y
exit- The restart the container:
docker restart containerName - Browse and test phpMyAdmin, each request should build a profile
pecl update-channels
pecl install xhprof(You may need to add the DEB sury repo: https://gist.github.com/janus57/37b079a383dd0507149bd94fd35053d1)
apt install php-xhprof
# More specific
apt install php8.0-xhprofRun php --ini and it will say Scan for additional .ini files in
Example:
php --ini
Configuration File (php.ini) Path: /etc/php/8.4/cli
Loaded Configuration File: /etc/php/8.4/cli/php.ini
Scan for additional .ini files in: /etc/php/8.4/cli/conf.dRun echo 'extension=xhprof.so' > /etc/php/7.4/cli/conf.d/docker-php-ext-xhprof.ini to activate the extension.
Note: /etc/php/7.4/cli/conf.d is a path given by php --ini
Run echo 'extension=xhprof.so' > /etc/php/7.4/fpm/conf.d/docker-php-ext-xhprof.ini to activate the extension.
Note: /etc/php/7.4/fpm/conf.d is a path given by phpinfo(); on a web page in the "Scan this dir for additional .ini files" line
No phpMyAdmin is not an app that "runs". That said you need to restart your php-fpm worker pool or your apache2 webserver. It will read the new extension file config and load it.
Examples:
service apache2 restart-
docker restart phpfpm74(wherephpfpm74is the container name) service php7.2-fpm restart/etc/init.d/php7.2-fpm restart
class XhProfProfiling
{
/** @var string */
private $requestUuid;
public function __construct()
{
$this->requestUuid = uniqid() . '.' . str_replace('+', '-', date('c'));
if (! extension_loaded('xhprof')) {
$this->log('The xhprof extension is not enabled');
return;
}
xhprof_enable(XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY);
$this->log('Loaded xhprof');
}
public function log(string $msg): void
{
// Enable this to print logs to error logs
// error_log('[' . $this->requestUuid . '] ' . $msg);
}
public function __destruct()
{
global $route;
if (! extension_loaded('xhprof')) {
return;
}
$buildXhprofs = __DIR__ . '/build/profiles/';
if (! is_dir($buildXhprofs)) {
mkdir($buildXhprofs, 0777, true);
}
$xhprofData = xhprof_disable();
$xhprofData = serialize($xhprofData);
$this->requestUuid .= str_replace('/', '--', $route);
$profilePath = $buildXhprofs . $this->requestUuid . '_capture.xhprof';
$wrote = file_put_contents($profilePath, $xhprofData);
$this->log('Wrote xhprof profile to "' . $profilePath . '": ' . ($wrote === false ? 'no' : 'yes'));
$metaPath = $buildXhprofs . $this->requestUuid . '_metadata.json';
$metadata = [
'route' => $route,
'method' => $_SERVER['REQUEST_METHOD'] ?? 'php ini bug',
'params' => [
'GET' => $_GET,
'POST' => $_POST,
'COOKIES' => $_COOKIE,
],
];
// Replace tokens with "*"
$ssoValue = $GLOBALS['cfg']['Server']['SignonSession'] ?? 'n/a';
foreach (['phpMyAdmin', 'phpMyAdmin_https', $ssoValue] as $key) {
if (! isset($metadata['params']['COOKIES'][$key])) {
continue;
}
$metadata['params']['COOKIES'][$key] = str_repeat('*', strlen($metadata['params']['COOKIES'][$key]));
}
foreach (array_keys($metadata['params']) as $key) {
if (! isset($metadata['params'][$key]['token'])) {
continue;
}
$metadata['params'][$key]['token'] = str_repeat('*', strlen($metadata['params'][$key]['token']));
}
$metadata = (string) json_encode($metadata, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$wrote = file_put_contents($metaPath, $metadata);
$this->log('Wrote metadata to "' . $metaPath . '": ' . ($wrote === false ? 'no' : 'yes'));
}
}
$keepMeInMemory = new XhProfProfiling();Please check that the metadata files have nothing private
They normally contain no private data (only the queries could be in the files)
They are in {phpMyAdmin}/build/profiles/
- From: https://github.com/longxinH/xhprof/releases
- Download the last release (See: Assets)
- Extract it in your webserver root
Note
Last tested version of xhprof UI: 2.3.10
Only the folder xhprof_lib and xhprof_html are needed
xhprof_html/docs can be deleted to save disk space
You need to edit xhprof_html/index.php, xhprof_html/typeahead.php, xhprof_html/callgraph.php to change the profiles path.
Or set XHPROF_OUTPUT_DIR as an ENV variable of the webserver/docker container. Or set the ini value xhprof.output_dir.
- $xhprof_runs_impl = new XHProfRuns_Default();
+ $xhprof_runs_impl = new XHProfRuns_Default('/var/www/html/build/profiles');Open your webserver URL, for example: xhprof-2.3.10/xhprof_html/index.php
Xhprof graphs need graphviz to display.
# Install graphviz
apt update && apt install graphviz -yPopular destinations:
- Team meetings
- GSoC home
- Developer guidelines
- How to install on Debian and Ubuntu
- Issue and pull-request management
User resources: