Profiling Your WordPress Site Performance

When dealing with speed and performance issues on your WordPress site, you’ll want to know what exactly is causing your application to be slow, and this is where profiling helps.

What is Profiling

Profiling measures the time and memory it took to execute your requests, the results will help narrow down all performance bottlenecks in a web application.

There are many tools available for profiling PHP (and thus WordPress) applications, including Xdebug, memprof, xhprof and others. Here at Pressjitsu we’ve built a custom integration with the Tideways extension (a lightweight profiler for PHP) which is pre-installed and available on all of our servers.

Creating a New Profile

To run a new profile you’ll need to perform an HTTP request to your site, with a special header called X-Pj-Profile. The value of the header must be set to your Pressjitsu API key, which you can find in your Account Settings or the Profiling section in your control panel.

If you’re comfortable working with tools such as cURL from the command line, you can add the X-Pj-Profile header to a request using the --header option, for example:

curl --header "X-Pj-Profile: YOUR_API_KEY" https://example.org -v -o /dev/null

If the profile was successful, you’ll see an additional response header indicating that profiling was enabled during the request:

< HTTP/1.1 200 OK
< X-Pj-Profile: enabled
...

If you’re not very comfortable working in the command line, you can grab a browser extension which will help you modify request headers, such as ModHeaders for Chrome, which will allow you to add the X-Pj-Profile header via a GUI.

Interpreting the Profiling Results

All successful profiles are saved to your Pressjitsu dashboard in the Profiling section, where each “run” is a separate profile. Note that old runs will automatically be deleted, so make sure to export your raw profiling data if you need to.

WordPress Profiling UI
WordPress Profiling UI

When viewing a specific profile you’ll be able to further dig into the function calls, database queries and remote HTTP requests performed during the run.

Functions

This section contains all function calls performed during a run, as well as some metrics around them, such as wall time, number of calls and memory usage. If you’d like to further dig into a specific function, click on its name. This will reveal the child and parent functions with their inclusive metrics.

Functions Profiling Metrics
Functions Profiling Metrics

Browsing through these function parents and children may be tedious and time-consuming, but it is absolutely necessary to be able to figure out which WordPress plugin or theme is to blame for poor performance.

Note that profiling requests tend to be a fair bit slower than regular requests, so don’t put too much emphasis on absolute time values. However, relative time metrics, as well as memory consumption, are both quite accurate.

Queries

This section lists your slowest database queries and contains a stacktrace for each query. The stacktrace will help you figure out where exactly the query is coming from, and the full SQL statement will help you run an EXPLAIN query, to perhaps optimize your database schema.

Profiling MySQL Queries in WordPress
Profiling MySQL Queries in WordPress

HTTP Requests

The HTTP section will show all remote requests performed during the run. This will often help spot plugins and themes that work with external services such as Twitter, Facebook, etc. The stacktrace will help figure out the origin of the remote request.

Profiling Admin & Logged In Requests

Logged in and admin requests in WordPress contain authentication cookies, so you’ll need to make sure to include those in your profiling cURL request. The easiest way to do this is to perform a regular logged in request with your browser, and copy all the cookies over to your cURL call.

Note: Never share these cookies with third parties as they may allow them to access your WordPress dashboard.

Copy as cURL in Chrome
Copy as cURL in Chrome

The request cookies can be found in the Network tab in your Chrome developer tools, which also contains a very useful feature called “Copy as cURL”, and that gives you a ready-to-use cURL command – you’ll only need to append your X-Pj-Profile header:

curl 'https://example.org/wp-admin/network/users.php' -H 'Cookie: wordpress_sec_...=; wordpress_logged_in_...=' --header "X-Pj-Profile: YOUR_API_KEY'

Similarly, you can profile AJAX requests and POST requests in the WordPress admin. Such requests often become performance bottlenecks, since many WordPress plugins (automatic sharing to social media, related posts cache priming, etc.) like to bind lots of operations to actions such as save_post. This is also useful for profiling performance problems with the WordPress Heartbeat routines.

Advanced Profiling

All the techniques described above are triggered by a user action supplying the X-Pj-Profile header in an HTTP request. But sometimes we run code that isn’t triggered by a user or by an HTTP request at all.

WordPress Cron jobs is a good example, on Pressjitsu these run in an entirely separate CLI process. Other examples are WP-CLI commands, and timed import-export jobs. To handle these situations, we’ve exposed part of our profiling API in two simple functions to start and stop the profiler:

Pj_Profile::start();
// Do something
Pj_Profile::stop();

The start() method initializes the profiler and starts collecting data. The stop() method stops the profiler and sends all the collected data to your Pressjitsu dashboard.

DO NOT use these functions in high-frequency, public facing requests, as it may easily lead to site disruption — profiling requests are slower than regular requests, and take up more server resources.

For example, if you’d like to run a profile on a custom WordPress Cron action, you can use the profiling functions as follows:

wp_schedule_event( time(), 'hourly', 'my_action' );
add_action( 'my_action', 'my_event_callback' );
function my_event_callback() {
    Pj_Profile::start();

    // Run your database queries, remote requests and
    // other things that may or may not be slow.

    Pj_Profile::stop();
}

Make sure that you remove or comment out these profiling functions from your production code as soon as you’ve collected enough data to work with.

Working with Raw Data

The Profiling section in your Pressjitsu dashboard allows you to export raw data for each view, including the .xhprof file for your functions metrics. This is useful if you’d like to use external tools to work with the full dataset.

Download Raw Profiling Data
Download Raw Profiling Data

If you run into any problems while working with our profiling tools and APIs, or if you have any questions about profiling or performance, please feel free to open a support request or reach out to us via e-mail.