Looking at Drupal Performance with XProf and XHGui

Perhaps, your Drupal site is so slow that you cannot ignore it any longer and you have decided to look into the affects of the poor performance. In general, the affects of performance may be categorized into three categories each addressing different aspects of application such as Drupal:

  • Code execution looks at the time code executes.
  • Querying database looks at how much time it takes to query database.
  • Load balancing looks at how your site performs based on number of visitors on your site at the same time.

In this post, we cover how to use XProf and XHGUI to look into code execution aspect of the performance. It also helps determine if code execution related to DB querying is significant enough contributor to slow performance that you have to address it as well

Before starting troubleshooting performance, restart the mysql because mysql keeps cache and some bad queries in the cache may have an unwanted effects on your performance analyses

Profile PHP Executions

To to profile php executions, we will use XHprof. There is XHprof part of Drupal Devel module,however. It’s outdated and it was difficult to make it work with Ubuntu 14/Apache 2.4. Instead we will grab the newest XHprof that comes with nice GUI for reports and run it as stand alone solution

But before installing XHprof, lets install MongoDB because the newest of XHprof requires MongoDB to run.

sudo pecl install --nocompress mongo
echo 'extension=mongo.so' > /etc/php5/mods-available/mongo.ini
sudo php5enmod mongo
sudo service apache2 restart

This installs MongoDB, configures the php driver to be loaded and starts the mongo DB

Installing XHprof and XHGui

Next, lets install the XHprof.:

sudo pecl install --nocompress xhprof-beta
echo 'extension=xhprof.so' > /etc/php5/mods-available/xhprof.ini
service apache2 restart
php -m | grep xhprof

Here, we first install xhprof module. Next we enable it and then restart it to load the module. At last, we verify if the module is loaded by retrieving all php modules loaded and filtering for xhprof module only. If you see the ‘xhprof’ listed, then you have installed XHprof correctly

Lets install the Gui for xhprof(XHGui) as following:

sudo git clone https://github.com/perftools/xhgui.git xhgui
sudo chmod -R 777 xhgui
cd xhgui
sudo composer install
sudo php install.php

Access XHGui Reports

To see the reports, we will configure virtual host that services dir located at /path/to/xhgui/webroot as following:

<VirtualHost *:80>
	DocumentRoot /home/margots/tools/xhgui/webroot
	ServerName xhgui
	<Directory "/home/margots/tools/xhgui/webroot">
		Options Indexes MultiViews FollowSymLinks
		AllowOverride All
	#	Order allow,deny
	#	Allow from all
		Require all granted

After putting the above virtual host at /path/to/apache2/sites-available/xhgui.conf, we enable and load:

sudo a2ensite xhgui
services apache2 restart

At last, lets point the url – xhgui to our local machine in the local DNS table /etc/hosts:     xhgui

Now, if you go to ‘http://xhgui’, you should see the the reports of xhprof. You should see something like “Looks like you haven’t done any profiling” if for the first time. This is because, we haven’t enabled profiling to any o our sites.

Enabling XHProf Profiling for Drupal Site

One way to enable profiling is to do it in php.ini that is going to profile all sites. If you like to profile individual site, then another way to enable profiling is via virtual host for the particular site. To do so, update the virtual host by adding following line:

<VirtualHost *:80>
   php_admin_value auto_prepend_file /path/to/xhgui/external/header.php
<Directory path/to/root>

After restarting apache, your site will be profiled. Make view requests and open reports at http://xhgui

Configure XProf Profiler

  1. Profiler Every Request

    By default, XHprof will only profile 1% of all requests because it is intended light weight to be used in production. Since we are at development and like to improve performance, we enable to profile all requests by updating /path/to/xhprof/config/config.default.php:

    'profiler.enable' => function() {
    #        return rand(0, 100) === 42;
    	return true;

    Here, we uncommented the ‘rand(0,100)===42’ line and added ‘return true;’ to profile all requests

  2. Clear HXProf or XHGUI

    To clear XHProf with XHGui, log into mongo db and clear the collection – results as following:

    use results

    The first line log into mongo db console. Next we switch the the database. At last command, it drops database – results that is is going to be recreated by the XHGui on the next request that is profiled

    Some other useful commands:

    show dbs //shows all databases
    use results //switch to this database
    db.results.help() //to find out all commands available for collection results
  3. Delete After 5 Days

    To limit disk usage, perhaps, you like to set certain time after which the logs are deleted

    $ mongo
      > use xhprof
      > db.results.ensureIndex( { "meta.request_ts" : 1 }, { expireAfterSeconds : 432000 } )

    This will set logs to be deleted after 5 days.

Enable Profiling for Command Line Executions

Drush is common tool for handling Drupal and you may want to profile it as well.
To profile scripts run from command line, all you have to do is import the header.php as following:

require '/path/to/xhgui/external/header.php';
// Rest of script.

Or use the -d flag:

php -d auto_prepend_file=/path/to/xhgui/external/header.php do_work.php

This will start profiling the particular script run from command line


1. could not extract the package.xml file from “/build/buildd/php5-5.5.9+dfsg/pear-build-download/mongo-1.5.5.tgz”

This happened when installing php mongo driver. The solution was installing uncompressed as following:

pecl install --nocompress mongo
2. Fatal error: Class ‘Xhgui_Config’ not found in [path]/xhgui/src/bootstrap.php

This error appears,when you forget to run ‘composer install’ before ‘php install.php’ in the xhgui directory. Basically, the autoloader.php is missing because composer hasn’t created it and you need autoloader to load Xhgui_Config class

3. xhgui – Failed to connect to: Connection refused

This error indicates that the mongodb cannot start. After looking into mongodb logs(/var/log/mongodb/), it was telling that we are out memory. By increasing memory, the mongodb was able to start and the error was gone


Sharing via Samba Instead VirtualBox Shares

The performance was so largely effected by using the VirtualBox shares on Apache server that I had to find a better solution to share directories between my VirtualBox Dev environment with Web server,database,etc and my machine Mac with the editor software. I turn to Samba Service as solution since it is one of the well known file sharing services available

Step 1 – Make Your Mac Sharing

By default, the file sharing is not enabled in the Mac, so the first step is to do just that

  1. On Mac, go to “System Preferences”->”Sharing” and check “File Sharing”
  2. And add the users and set permissions to “read & write” in the “Sharing” section
  3. On VBox Guest, add the ‘shares’ – directories that going to be shared in the “Sharing” section under Settings of your VirtualBox guest machine

Step 2 – Install Samba

While Mac comes with the Samba support, our guest Os is xUbuntu and it didn’t have Samba installed/enanbled which I did as following:

 sudo apt-get install samba sudo start smbd sudo start nmbd 

This installs and starts the Samba server on my guest Ubuntu

Mount Shares

Once the Samba installed and started, then we mount the share directory. The mounting was done from the Samba server( in our case guest OS) into the host – Mac OS as following: To mount a share from guest to host:

 sudo mount -t cifs //HOST-IP/SHARE-As-Declared-Step-1 /path/At/Guest/machine -o uid=1000,iocharset=utf8,rw,username="USER-HOST",password=USER-HOST-PASSWORD,nounix --verbose 

See “man mount.cifs” for more info on options(i.e. outlet iphone 8 case “-o”) To check what’s mounted so far on Ubuntu:


This should display all mounted points including the shares To mount automatically on reboot:

  1. Create Permanent IP for Host Machine

    Before configuring to auto mount the shares, it is important to have the permanent IP for the host. Otherwise, you will have to manually change the IP every time your Host WiFi IP changes. To have the permanent IP for the Host machine, you have to create “Host Only Network” as described in section 6.1 of post Virtualbox Gotchas

  2. Configure Auto Mount Shares

    To mount the shares at the start up, we edit /etc/rc.local at our Guest Ubuntu OS and added the following:

     mount.cifs //HOST-IP/SHARE-As-Declared-Step-1 /path/to/shared/dir -o uid=1000,iocharset=utf8,rw,username=HOST-USER,password=HOST-USER-PASSWORD,nounix 

    So by adding the line in the rc.local file, it is executes the mount at the boot process. Do the same for each share you like to mount. iphone 7 case

Sharing via AFP

Disclaimer: The AFP is very buggy and should be avoided. Its possible to use AFP instead of SAMBA. I had to install afp modules on the guest Ubuntu:

 sudo apt-get install afpfs-ng 

Afterwards, we mounted the the directory as following:

 sudo mount_afp afp://host_user:host_user_password@hostIp/share /srv/afp/share 


Do Manual Mount

To better see the issue, mount the shared dir manually via “mount” command. It seems to display better error messages. Here is sample command taken out from rc.local with extra flags

 sudo mount -t cifs // /home/margots/workspace -o uid=1000,iocharset=utf8,rw,username=margots,password=PASSWORD,nounix 
Check What is mounted?

First, look at what is mounted by issuing command:


It will display a list of all the mounted directories

1. Check Logs

Log files location is declared smb.conf file in “/etc/samba/” dir. The default location “/var/log/samba”

2. See Samba Settings

There is nice way to see the Samba settings:

 smbclient -L smb -N 
3. Check if Samba Running

Check if Samba is running:

 ps -ef | grep smbd 
4. Follow Kernel Logs Fix Mount Problem

Look at the logs to fix any mount problem:

 tail -f /var/log/kern.log 

This will be output logs as they come in

5. mount_smbfs: mount error: /srv/samba/share: Unknown error: -1073741275

I haven’t found solution to this. It is happening when trying to mount share from host to the guest instead way around as described above. iphone 8 case outlet uk I guess my solution was just to mount the share from guest to host that accomplishes the task at hand.

6. outlet iphone xs case Package smbfs is not available

According to this page https://wiki.ubuntu.com/MountWindowsSharesPermanently, it seems smbfs is deprecated and you should use cifs instead. try:

 sudo apt-get install cifs-utils 
7. mount error(22): Invalid argument.Refer to the mount.cifs(8) manual page (e.g. iphone xr case outlet uk man mount.cifs)

This happened when trying to mount share into host mac

 sudo mount -t cifs // /srv/samba/share -o uid=1000,iocharset=utf8,username="margots",password=38394815 

To solve problem, we needed to disable the CIFS Unix Extensions for this mount that was done by adding option “nounix”

 sudo mount -t cifs // /srv/samba/share -o uid=1000,iocharset=utf8,username=USERNAME,password=PASSWORD,nounix 
8. Permission Denied For Apache When Writing On Samba Share

There was permission denied when Apache server tried to write in Samba Share. The solutions was to update apache user and group to one with Samba write permissions. cheap iphone xs case To do so, I had to update Apache Environment variables – APACHE_RUN_USER, APACHE_RUN_GROUP in the /etc/apache2/envvars file as following:

 export APACHE_RUN_USER=SAMBA_USER=samba_user export APACHE_RUN_GROUP=share_dir_user_group 

The Samba User with group of the share allowed Apache to make writes on Samba shares

9. mount error(13): Permission denied

I got this error when incorrectly enabled file sharing at host machine of Mac. You may need to have the 3 settings present in “System Preferences”->”Sharing”:

    Check “File Sharing”
  • Under “File Sharing”, click “Options” and add the user that will be used for remote sharing
  • Check “Remote Login”
  • Under “Remote Login”, add the user that will be used for remote sharing

This solved the error for me

10. /etc/rc.local Doesn’t Run at Startup

The /etc/rc.local contains our mount functions to run at startup, however. If it doesn’t run, try troubleshooting by running the following commands and looking for error messages for answers

 /etc/rc2.d/S99rc.local start /etc/init.d/rc.local start /etc/rc.local 

This is tracing through the sequence for scripts called before rc.local to find out where it fails

11. No Match Found in /etc/fstab

As I was tracing through the scripts to find out why the rc.local doesn’t seem to be executed at startup to mount my shared dir, i got the error “No Match xxx found in /etc/fstab” prusuant to 10 above. cheap iphone 7 case The solution was allow members of CDROM group to mount without prompting for root password by inserting the following line in /etc/sudoers:

 %cdrom ALL = NOPASSWD:NOEXEC: /bin/mount, /bin/umount, /sbin/mount.cifs, /sbin/mount.nfs 

Afterwards, i add “sudo mount” to mount command in rc.local script:

 sudo mount.cifs ...