One of my favorite development tasks is performance engineering. I love taking an application and analyzing it to increase performance. Application performance monitoring (APM) tools like New Relic and Blackfire.io are tools every developer should have in their toolkit. New Relic is for passive performance monitoring of your application in production. Blackfire is for active performance monitoring and profiling in any environment. I like to think of it as New Relic helps you see the smoke, and Blackfire finds the fire. If you don't have Blackfire, you can use Xhprof for profiling.
If you use DDEV for your local development environment, Blackfire and Xhprof can be used out of the box!
One area that can be tricky to profile is AJAX requests in your application. Drupal provides an AJAX API that allows you to build dynamic user interactions many times without writing any JavaScript.
Profiling AJAX requests with Blackfire.
There are two ways to profile AJAX requests with Blackfire. The browser extension allows you to profile specific requests and has a "Profile all requests" option. Any request that occurs while recording will be profiled, perfect for capturing Drupal's AJAX calls for profiling. When recording, a transparent window appears that displays all of the recorded requests, including a "Stop" button to stop recording.
I wanted to do some profiling of the Media Library. I used the "Profile all requests" option to do performance profiling of the AJAX views operation that powers the media library. Instead of having to profile individual AJAX requests for filtering or pagination manually, I could capture them all and then go back and review them individually.
Once you hit "Stop," your Blackfire dashboard will open, allowing you to review the profiled requests.
You can also profile individual requests by using the built-in "Copy as CURL" command from the Network tab in your developer console. This allows you to profile the request using the Blackfire CLI.
Here is an example from the copied command with a truncated URL, as the media library has a lot of stateful items in the query parameters:
blackfire curl 'https://drupal-core-dev.ddev.site/en/views/ajax?media_library_opener_id=media_library.opener.field_widget&media_library_allowed_types%5Bimage%5D=image&media_library_selected_type=image&media_library_remaining=1&media_library_opener_parameters%5Bfield_widget_id%5D=field_media_image&media_library_opener_parameters%5Bentity_type_id%5D=node&media_library_opener_parameters%' \
-H 'authority: drupal-core-dev.ddev.site' \
-H 'accept: application/json, text/javascript, */*; q=0.01' \
-H 'accept-language: en-US,en;q=0.6' \
-H 'cookie: SSESS6784e72b328053d94d40c68849404ec4=wt3HkXmNlpcGu6O9nEV6mW%2CuJTOlcWHoXNUWSYlkxpBpxP%2Cu' \
-H 'referer: https://drupal-core-dev.ddev.site/en/node/add/article' \
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' \
-H 'x-requested-with: XMLHttpRequest' \
--compressed
You can then re-profile an AJAX request without recording all the requests on a page. Note: this does not always work if the route is protected by CSRF tokens that have a timestamp as part of the token.
Profiling AJAX requests with Xhprof.
It has been seven or eight years since I last used Xhprof, so this section is heavily based on DDEV's setup, making using Xhprof a breeze.
When using Xhprof, all requests are profiled. The only downside is that the resulting reports make it hard to identify the URL that created the request. This can make it difficult if a page has multiple AJAX requests. When I have had to use Xhprof I would use the "Copy as cURL" approach and then turn on Xhprof profiling.
Xhprof profiles are harder to read. It has been a while since I tried this, but the msonnabaum/xhprof-flamegraphs repository used brendangregg/FlameGraph to create flamegraphs from Xhprof reports. I had a script that embedded this into my Docker image. There is a DDEV addon to add XhGui for easier Xhprof profiler viewing.
Want more? Sign up for my weekly newsletter