Posts

Launching Tideways with transparent and flexible pricing

We are excited to launch the first version of Tideways to the general public this week, along with a new pricing model.

The new pricing is not turning Tideways upside down. In fact, the old plans are a limited subset of the new model as you can see later.

Plans: To infinity … and beyond!

Starting today, you only pay exactly what you use in Tideways. You will always pay a basic fee of 40 € for the first million traces and then you will be charged for the usage in packages of one million traces each. This is the equivalent of having infinitely many plans where discounts for size apply automatically. For detailed information about the volume-based offers please visit the pricing page.

Your main advantages with the new pricing model:

  1. Transparency and Dependability: No rapid jumps in monthly prices if your application traffic grows beyond a plan.
  2. Volume-Based Plan: you will save money by paying only for the traces collected from your application.

One more thing on data retention

We wanted to improve flexibility even more. During beta, all traces were kept for 14 days, however, we realized that the requirements regarding data retention vary extremely among our customers.

Because the retention of traces has a direct impact on how much storage space and processing is needed, we factored this variable in the monthly fee.

If you don’t need traces for 14 days, but only for three or even just one day, we grant you a considerable discount for each million traces. Equally, if you want to store traces for much longer (30 or 90 days) then you will be charged accordingly.

Pricing Calculator

We built a pricing calculator so that you can easily experiment with the costs for different amounts of traces and retention.

You can start by checking that the startup and business plans from the beta didn’t change much in price. Using the 14 days retention, the startup plan with 3 million requests/month is now 100€ instead of 99€ (+1€) and the business plan with 15 million requests/month is now 195€ instead of 199€ (-4€).

How about long-term, fixed-scope contracts?

If you are planning with a fixed budget and with at least one year of usage in advance, then we can talk about a fixed scope contract. Please contact [email protected] to get in touch with us.

Thank You

Thanks to you – our beta testers, early-adopters, new and prospective customers – and your feedback we were able to make Tideways amazing and tailored to your needs.

As always, please let us know if you have any questions regarding Tideways, we are looking forward to hearing from you!

Three Fully Functional Demo Applications

Tideways stands for smart and efficient profiling. To offer first-time-users an easy access, we incorporated a lot of feedback to simplify the installation.

Among other things, we now provide three fully functional demo applications, to give you an impression of Tideways’ possibilities:

  • simple WordPress blog
  • Sylius eCommerce (based on Symfony2) with demo data
  • Shopware 5 with demo data

With no work required from your side, you can check out all the features of Tideways. All you need to do is sign up for a Tideways account to get direct access to the demo applications.

Don’t worry, exploring the demo applications does not count towards your available 30-day free trial, you can look around without any rush and decide to start a trial later.

All the available features are showcased and we are forcing error conditions and durations of slow performance into these applications to make them feel like an exciting roller coaster ride.

If you already created an account before and the demo applications are not visible in your dashboard, you can enable them in your settings.

Enjoy the demo applications and let us know how they work for you – as always we are looking forward to your feedback!

Trace Timelines Public Preview Available

We are happy to release a first public preview of Trace Timelines for Linux today that we unveiled two weeks ago. You can find the PHP Extension v2.0.3 on the downloads page. Please note that this a preview and there might still be bugs.

A small number of our customers have tested the new feature already and provided a lot of feedback, most of which we already incorporated into the current version.

Improvements were made mainly on the user interface, mostly adding much more information to each individual span. Each timeline contains a large number of individual timespans that are PHP calls, Events, SQL or HTTP calls:

TimelineTimeline

More information is available by hovering over each individual timespan.

Take this first example for the main PHP request span. It contains the total duration and additional information such as the number of included files and the PHP compile overhead that this request required.

Request PerformanceRequest Performance

In this case 29% of the request spent compiling php files points to a missing opcache extension.

Another example is this Doctrine ORM timespan which contains information about the time spent building the SQL query and the hydration overhead.

Doctrine PerformanceDoctrine Performance

With this information readily available a decision about writing this query manually or keep using the ORM can be quickly made.

We also hook into framework specific functions that are known to be performance hogs, for example the service lazy load in Symfony’s EventDispatcher can take a significant amount of time per request.

Symfony PerformanceSymfony Performance

We are adding custom descriptions to guide you towards identification and fixing issues so that you don’t have to dig deep into the internals of third party libraries and frameworks.

These examples show features of the instrumentation that the new Tideways extension detects automatically. But the new Tideways is not limited to automatic instrumentation: Any span can be enriched with custom information and you can create your own spans declaratively and programatically. See the documentation for the API on adding custom spans.

On top of a much better insight into your applications, we can collect this profiling information at a much lower overhead than with XHProf. So far it runs 50% faster and we still have room for additional improvements. Going forward we will be able to trace much more individual requests allowing to paint a much better picture of your applications.

Tideways Update: On Timelines

Tobias and I have been super busy the last weeks adding more features to Tideways. With new customers joining our awesome group of early adopters every month we can now invest more time in working on Tideways. Most of the current work is building new features from scratch which is why it takes so much time compared to previous iterations on the Profiler.

However, we are really excited about the next features and this blog post is about sharing some of that excitement with you.

One feature that we are working on right now is called “Timeline”. It implements profiling as initially proposed by Google with a system called Dapper.

The idea is to collect timespans of interesting events that happen during a request. Each timespan can contain contextual information such as SQL queries, URLs in HTTP calls or template names. All timespans are then displayed in a timeline. What got us hooked on this visual design was the possibility to show all the relevant information on a single screen, no endless clicking and zooming necessary anymore.

Have a look at a sneak preview of this feature showing a request of a Shopware 4 application with demo data:

Shopware4 TimelineShopware4 Timeline

You can see timespans collected for SQL Queries, Events, Templates and Controllers neatly aligned to show the requests sequence from left to right. Hovering over each timespan bubble will show additional context information. You can spot critical performance problems such as slow or N+1 queries within seconds and know exactly when they happened in the request.

Our PHP extension collects this data automatically for common PHP extensions, frameworks and libraries. Here is another example from a WordPress blog:

WordpressWordPress

We believe Timeline can provide much more valuable profiling data than XHProf in most cases. Our initial prototype built in January already proved successful when we worked with Shopware to improve the baseline performance of their new Shopware 5 release.

Signup for Tideways now to get early access when we release timelines in the next days. We will automatically set your trial to 30 days once the release is ready, so that you don’t have a disadvantage signing up now.

If you are worried about XHProf callgraphs being removed from Tideways now, don’t be. You can still send XHProf traces from your applications either automatically with a sample rate or explicitly triggering them.

Watch out for follow-up posts that explain our rationale for introducing Timeline and why we think it will benefit you when we put less focus on XHProf data. You can follow us on Twitter to keep up to date.

Qafoo Profiler is now Tideways

Today we are unveiling our new product name Tideways replacing the working title Qafoo Profiler.

You can now find us under our new domain tideways.io, on Twitter @tidewaysio and on our new dedicated Github organization. The old qafoolabs.com and profiler.qafoolabs.com domains will continue to work indefinitely.

As for the meaning of the name, tideways are water streams visible during ebb in the wadden/north sea. You can find more information on Wikipedia (German and English).

Concerning the migration of packages, we are starting with a soft migration today. The old Debian and Packagist packages are still available as before, but we have added new Tideways packages:

  • Composer package “tideways/profiler” replaces the “qafoolabs/profiler” package.

  • Debian package “tideways-daemon” replaces the “qprofd” package.

  • Debian package “tideways-php” replaces the “qafoo-profiler-php” package.

We were careful to provide a backwards compatible API for QafooLabsProfiler PHP class so that your code will not break during an upgrade. A detailed migration guide exists to help you in the transition.

The old packages will keep working, but we are starting to send out update notices to everyone who is still running on the old code. We have no immediate plans to remove the old packages, because the protocols are compatible to each other. We have also decided against forcing upgrades to the new packages.

However, be aware that only by changing to the new tideways packages, you will receive automatic updates for PHP library, extension and daemon.

The documentation was changed to refer to the Tideways packages and code only.

The beta period will come to an end in the next weeks, the final features in testing and development at the moment include:

  • MacOS support with Homebrew
  • Alerts and Notifications for performance regressions and errors
  • Better support to identify slow queries, http requests and requests between different applications.
  • A commandline tool complementary to the Chrome extension to trigger traces for PHP scripts and REST APIs.

Follow us on Twitter @tidewaysio for updates.

Heatmaps in Weekly Report

Changes to the weekly mail were already planned for a long time and now we are pushing them forward with heatmaps as an additional tool to find periods of slow response times. The heatmap will show the response time (95% percentile) of all your applications for each hour of the last seven days.

It is now part of the weekly application report that is sent every monday morning.

Heatmap in Weekly Report MailHeatmap in Weekly Report Mail

By clicking on the square for any hour you will be redirected to the Profiler, showing the graph of response times in the selected 60 minutes as well as the critically slow transactions and traces.

You will receive the first mail including heatmaps next Monday.

Using Tideways with HHVM

Note 2018 We have discontinued support for Tideways on HHVM because there wasn’t enough interest from customers. With all the new features since 2015 our HHVM support was not at the same level as our PHP support and with HHVMs teams decision to move away from PHP.

Facebooks PHP runtime HHVM bundles its own profiler compatible with the XHProf API. Because Tideways works with the XHProf output format as well, you can start to monitor and profile your HHVM based applications in production today.

To install the profiler with HHVM requires the tideways/profiler Composer package or download Tideways.php file directly into your application.

Add the Profiler initialization code to your project as described in the Profiler Setup documentation with the following snippet:

<?php

TidewaysProfiler::start($apiKey, 10); // 10% Sampling Rate 

For more insight into your app you should also capture the name of the called transaction using TidewaysProfiler::setTransactionName().

With a running daemon on the server these are all the necessary changes for monitoring HHVM application performance.

Detecting Bottlenecks: Blocking Session

PHP uses a file-based session store by default that conveniently works out-of-the-box. However, file-based sessions can introduce a serious bottleneck when used with parallel (AJAX-) requests. PHP locks each session file during session_start() until the request ends, preventing concurrent access to the same session at the same time. A blocked request waits at session_start() until previous requests release the lock.

This leads to linear AJAX-requests execution instead of in parallel.

We improved the bottleneck detection to scan for this problem automatically, as you can see in this screenshot that shows a transaction that is called via AJAX:

No changes are necessary to your Profiler setup, this can be extraced on our side already. If your application is suffering from this problem, you will see the warning label popup automatically with the next affected trace.

There are multiple different fixes to this problem:

  1. If you want to keep file based sessions or use any other backend with locking support such as Memcached: Call session_write_close() when you are sure that you are not writing to the session anymore later. This allows other requests to start reading the session until again session_write_close() is called or the requests end.
  2. You can switch to a custom session backend that don’t implement locks on the session. Careful though, you can theoretically suffer from lost updates when two parallel requests read and then write to the same session. The PHP manual describes how to create a custom session backend in detail.

See the Session reference in the PHP documentation for more information.

Histograms are back

Histograms are available again to all customers starting today. The stability of this feature has been tested by several customers in the last weeks.

We believe histograms are very important when monitoring response-times, so when we removed this feature temporarily in October we knew it would come back soon.

In statistics, the calculation of the average assumes a normal distribution of all the recorded values, an assumption that is not true for response times. The average response time is a largely misleading metric. Benchmarks calculating this value should not be trusted.

For this reason we use 95% percentile in our charts. The 95% percentile is calculated by sorting all response times in order and picking the highest value that is lower or equal to 95% of all requests. Picking the 95% percentile over 90% or 99% is rather arbitrary, we are working on better data structures that allow you to compare those values. Computing percentiles with a huge amount of data efficiently is not an easy task.

Where do histograms fit in this picture? Code usually has different execution paths depending on input, influencing the response times heavily. This could be due to caching, invalid user-input leading to early exit or many other causes.

Histograms take a different angle on data, removing the time dimension and counting the number of occurances that fall into a pre-defined interval such as 0-29ms, 30-59ms and so on.

The following histogram extracted from the Profiler is an example of how helpful histograms are:

Histogram with two PeaksHistogram with two Peaks

There are two peaks in this histogram, suggesting there are two execution paths in the code that handle this transaction.

Compare this to a more boring transaction that has only a single peak:

Histogram with one PeakHistogram with one Peak

Histograms complements charts with time and percentile values, allowing you to better understand how you need to optimize your code to achieve better performance for your users.

Filtering Callgraphs

After our holiday break in December we are happy to introduce the first new feature of 2015. We are starting small with the addition of filtering options for callgraphs.

To improve the experience when looking at callgraphs it is necessary to adjust them to the current data you are looking at. After all even XHPRof’s original UI allowed configuring some filters if you knew the magic GET variables to pass.

Before this change callgraphs were limited to a depth of 15 calls, unlimited children per call and a 1% threshold of total response time for calls to be included. Depending on the kind of project, these defaults either lead to very wide and deep graphs that are hard to navigate or to boring graphs that include even the most unimportant paths.

When you now visit the callgraph of a trace you will see three new dropdowns to filter the callgraph:

  • Depth controls the number of calls that are displayed starting from the main node.
  • Children/Node controls the maximum number of children displayed for every call.
  • Call Threshold controls the minimum duration of a call to appear in the result as a percentage of the total response time.

See this screenshot with a current trace of the Tideways Profiler itself:

Callgraph FilteringCallgraph Filtering

We have also changed the defaults of some options to improve the experience. Children/call now defaults to “2” instead of the previous “Unlimited” and the depth has been reduced from 15 to 10.

Environments Revisited

We have revisited the “Environments” feature of the Profiler and are stopping to collect performance data on non-production environments. With this change the user-experience becomes much better, because we can now always display the production data graphs. The environment switch dropdown was removed from the UI.

Our customers so far haven’t used performance data from other environments and we came to the conclusion that the additional complexity in the user-interface is only causing confusion.

Nothing has changed for regular profiling traces: They are still collected for every server and environment.

If you do need performance data, for example during load-tests of staging environment, you can just add a second application to your account and use that for testing.

New Extension Release: Auto-Start Profiler

We released an important milestone with the Tideways Profiler extension today. The new version allows you to start profiling and monitoring your applications without any code modifications. Documentation and setup guides will be adjusted to reflect this much simpler installation in the next days.

When you install the PECL extension in version 1.3.2 from the Debian/Ubuntu repository or the Tarball, the dependency to the PHP library is now bundled. During request startup the PHP library is loaded directly from the extension. The TidewaysProfiler class is available in every request as if it was a built in PHP class.

The API Key, sampling rate and transaction function can then be configured from the php.ini:

# php.ini tideways.api_key=abcdefg tideways.sample_rate=10 tideways.transaction_function=SymfonyBundleFrameworkBundleControllerControllerResolver::createController 

Or alternatively by setting the values as environment values, for example in PHP-FPM Pool

env[TIDEWAYS_APIKEY]=abcdefg env[TIDEWAYS_SAMPLERATE]=10 env[TIDEWAYS_TRANSACTION_NAME]=SymfonyBundleFrameworkBundleControllerControllerResolver::createController 

or Apache2 Configuration:

SetEnv TIDEWAYS_APIKEY abcdefg SetEnv TIDEWAYS_SAMPLERATE 10 SetEnv TIDEWAYS_TRANSACTION_NAME "SymfonyBundleFrameworkBundleControllerControllerResolver::createController" 

In combination with the daemon installation, which already requires zero interaction, it is now possible for operations to fully automate the installation of the Profiler using orchestration tools like Puppet, Chef or Ansible.

Please note that auto-starting the Profiler is entirely optional. If you prefer starting the Profiler explicitly from your application this is still possible.

You can control the auto-start behavior of the extension with two additional php.ini variables:

  • tideways.load_library=0 will disable loading Tideways.php entirely.
  • tideways.auto_start=0 will only disable the autostarting functionality and you have to call TidewaysProfiler::start() yourself. Autostarting only works when the API Key is provided in the INI as well.

With the introduction of the INI variables for api-key and sample-rate, passing them to the start() method becomes optional:

<?php

TidewaysProfiler::start(); 

This will force the generation of a trace for this console script invocation.

We have also updated the daemon to a new version 0.3.1, which contains improvements in error handling, error logging and data transfer encoding.

You can find pre-compiled binaries for the PECL extension and the Daemon on our downloads page.

Note: We found that loading PHP code from within an extension is not compatible with Xdebug yet. In case you use Xdebug, the auto-loading feature is automatically disabled and the TidewaysProfiler class will not be available to you. A fix for this problem is already merged to the current stable branch of Xdebug and should be part of the next Xdebug 2.2.7 release.

Chrome Extension to Start Tracing

We are releasing a Chrome extension for Tideways today. The extension allows you to force the collection of traces for all requests of your current browser session with the push of a button, instead of having to wait for a random trace to be sampled.

The Profiler already shipped with multiple triggers to generate traces directly from your application before but the feature left a lot to be desired. For example it was nearly impossible to test POST- or Ajax-requests before.

After installing the extension, start using it by clicking on the “Profiler” icon next to your URL location. You will see a list of all your applications like the one in the screenshot below.

Chrome ExtensionChrome Extension

Pick the application to profile and the tracing starts. This works by creating a cookie with a short lifetime of five minutes. Tideways will react to this cookie on the server side. If you picked the wrong application which is not connected to the site on the current URL, nothing will happen.

On the Profiler UI you can list all the traces that were generated in the tracing session. Click on “Traces” in the application overview to see them.

You can download the Chrome extension from the Google store to try this new feature.

Using the Chrome extension requires at least Tideways PHP library version 0.11 on the server.

A note on security: Triggering a trace is secured with HMAC based on your API-Key and a short expiration date. This prevents malicious users from generating traces on your production servers. The API key is never sent directly to the extension or your site, avoiding that anybody will accidentally get access to the key through logfiles, HTTP referers or by sending the cookie to the wrong site.

We open the Beta for everyone today!

Six months ago the first line of code was written. Now we are finally opening the beta registration to everyone. Read the press release on our company blog.

So far our closed beta testers have measured 500 million requests and the Profiler has analyzed 7 million traces. We hope to increase this numbers a lot by giving everyone access to the Profiler starting today.

Our journey started by building a platform based on XHProf and during the closed beta we have moved beyond the original Facebook PHP extension to provide many additional features and performance optimizations that are necessary for isolating and fixing bottlenecks.

You can take a look at all the Features that we already support right now and a Roadmap of what we are working on.

During beta a lot of people have asked us about our pricing model and for the start of the open beta we are lifting the curtain.

We are transitioning to a paid beta using a simple per request pricing model. That means no need for you to count servers, applications or users. Plans start at 99€/month with 100.000 requests a day. See our pricing page for details. Get in touch if you have any questions about the pricing.

Why still keep the beta label? We are still working to improve the installation, packaging and setup of the Profiler for as many platforms as possible. The Profiler will stay in beta until we feel the setup experience is close to perfect.

What is next? The roadmap already contains a list of larger features that we are working on for the Profiler. If you want to keep informed about features and news subscribe to our mailing list or follow us on Twitter.

Improving XHProf further

Almost a month passed since our last blog post on the XHProf extension and we are happy to announce more improvements today that were necessary to improve the experience and performance of the Profiler. We released all this as v0.9.7 of XHProf.

Skipping userland functions

XHProf ships with a flag called XHPROF_FLAGS_NOBUILTIN which ignores all built-in functions during profiling by not overwriting the Zend Engine hook. This is a very efficient mechanism to save a lot of performance, however the other way around is much more interesting, skipping userland functions.

We have introduced a new flag XHPROF_FLAGS_NOUSERLAND that does just that, ignoring all userland functions during profiling by not hooking into zend_execute.

New “layer” profiling mode

When using XHProf for permanent production profiling, a full trace for every request is just a waste of CPU cycles. To get an overview of the performance using the average response times of different layers such as I/O, database, cache and HTTP is just enough.

With support for XHPROF_FLAGS_NOUSERLAND and the function whitelist we have added a third feature called layers that is both available in normal xhprof_enable() as an option but also with a dedicated call xhprof_layers_enable():

<?php

xhprof_layers_enable(array("mysql_connect" => "db", "mysql_query" => "db"));

mysql_connect(); mysql_query("SELECT 'hello world'");

$data = xhprof_disable();

printf("%d calls with a total of %d ms", $data['db']['ct'], $data['db']['wt'] / 1000); 

Fatal error traces

For our error collecting feature we have missed traces for fatal errors from the beginning. Adding a new function xhprof_last_fatal_error() you are now able to access the trace inside a register shutdown handler.

The output is the same as error_get_last() with a new key "trace". It also formats uncaught exception error fatals a little differently by using the exception class as “type”.

This function only works when called after either xhprof_enable() or xhprof_layers_enable() and before xhprof_disable(), because it overwrites PHPs error callback only in this case.

Stopping a trace unified

In Facebooks xhprof you could call both xhprof_disable and xhprof_sample_disable to stop the profiling. Because internally xhprof uses a lot of global state, we had to unify this approach to work with a single function only, xhprof_disable, to avoid bugs when calling the wrong disable method.

Testing the changes

This time you can easily test everything as well, we have pre-compiled the extension for 64bit Linux for PHP 5.3, 5.4 and PHP 5.5. This is still considered beta and you should expect it to segfault in some cases. The code is provided AS IS with no warranty that it works on your machines, please don’t use it in production yet.

If you want to compile it yourself, see the Github repository. Make sure to copy ext/curl/php_curl.h from the php-src to your PHP’s include directory; otherwise it won’t compile.

Our first experiments with PHP 5.6.0 show that XHProf is not compatible out-of-the-box. We are working on fixing them as soon as possible.

Outlook

With this milestone we are working on stabilizing all our changes to XHProf and focussing on the Profiler UI again. The layer and argument functionality is already integrated, but there is still a lot of room for improvement.

After this round of changes we will also be looking at activating new beta testers. In the current closed beta, our users have already created 56 applications that transmit a total of 2.5 million requests a day which has already required us to dedicate some time to scaling, which is why we haven’t added a lot more beta testers yet.

Improving the XHProf Extension

Note: This post is outdated. Please find more information about our current improvements to the XHProf extension on its Github page.

We rely on the XHProf PHP extension to collect profiling data for your applications. XHProf was developed by Facebook during the times when they still used PHP. Since its release it remains largely unmaintained except the occasional bugfix to allow compilation with recent PHP versions. In the last month, the extension moved from the official Facebook repository to another organization and should be considered unmaintained by Facebook.

To allow a stable integration of XHProf with the Tideways in the future, we have started to maintain our own fork of the project. At the moment the fork includes bugfixes and several improvements.

We haven’t started an “offical” repository for the fork yet, instead you will find the code in several branches of our fork.

Our mid-term goal is to release all these changes under an open-source license as a new extension.

Compiling with PHP 5.5.8+

Starting with PHP 5.5.8 XHProf would segfault because of a change in how the Zend Engine represents a function execution. There was an unmerged Pull Request on the XHProf repository which we merged into our fork.

Function Whitelist

Our first new feature is a whitelist of functions to profile as an opposite to ignore_functions that was already implemented using a new option called functions.

With a whitelist of interesting functions such as PDOStatement::execute, curl_exec and file_get_contents you can already find the most critical performance bottlenecks that are I/O related without collecting data for all the other function calls. This improves the performance of XHProf massively allowing to collect data for non-PHP layers on every request.

We have already turned this into a feature in the Tideways where you can see the performance of those layers over time:

LayersLayers

You can activate this functionality by invoking XHProf with the following options:

xhprof_enable(0, array('functions' => array('PDOStatement::execute', 'PDO::commit', 'curl_exec'))); 

Argument Summary

One drawback of the current XHProf is its one-level hierarchy of tracing data, especially with respect to SQL queries or expensive HTTP/Filesystem calls.

The information that PDOStatement::execute was called 100 times and took 2 seconds is interesting but not nearly as interesting as the information which of the 100 queries was actually slow.

By default XHProf only collects the information about parent and child functions. For this simple script

<?php

xhprof_enable();

for ($i = 0; $i < 3; $i++) {
     strlen(str_repeat("x", $i));
}

echo json_encode(xhprof_disable()); 

the output would look like the JSON structure below:

{
     "main()": {
         "ct": 1,
         "wt": 116
     },
     "main()==>str_repeat": {
         "ct": 3,
         "wt": 22
     },
     "main()==>strlen": {
         "ct": 3,
         "wt": 1
     },
     "main()==>xhprof_disable": {
         "ct": 1,
         "wt": 0
     } 
} 

If you wanted to know which of the three calls of strlen was slow, no luck.

Our hosting partner Syseleven worked on solving this question before and came up with a partial improvement of the XHProf extension that allowed defining a whitelist of functions whose arguments should be included in the profiling. Changing the script:

<?php

xhprof_enable(0, array('argument_functions' => 'strlen'));

for ($i = 0; $i < 3; $i++) {     strlen(str_repeat("x", $i)); }

echo json_encode(xhprof_disable()); 

Would yield:

{
     "main()": {
         "ct": 1,
         "wt": 130
     },
     "main()==>str_repeat": {
         "ct": 3,
         "wt": 18
     },
     "main()==>strlen#": {
         "ct": 1,
         "wt": 1
     },
     "main()==>strlen#x": {
         "ct": 1,
         "wt": 0
     },
     "main()==>strlen#xx": {
         "ct": 1,
         "wt": 0
     },
     "main()==>xhprof_disable": {
         "ct": 1,
         "wt": 0
     } 
} 

This works for simple functions only, not for those that rely on data from previous function calls. That means curl_exec, PDOStatement::execute and almost any filesystem related call such as fgets would not show the arguments you are interested in. In addition SQL queries, filenames and URLs can be very long, but we are limiting the size of keys to 255 chars to avoid massive memory consumption of the profiling data structure.

That is why we have improved the Syseleven patch to handle the following special cases:

  • fopen shows the opened file or url as well as the resource id. Query Strings are omitted.
  • fgets, fputs, fclose and many related functions show the passed resource id, allowing correlation with fopen calls.
  • curl_exec shows the requested url except the query string.
  • PDOStatement::execute shows the executed SQL query as a summary, which contains of the primary SQL keyword (select, update, delete, insert, other) and the affected main/first table found in the SQL statement.
  • Every PDO, ext/mysql and ext/mysqli query that executes a query shows a summary of the query.

Let’s look at a simple example to understand how those special cases are handled:

<?php

$args = array('fopen', 'fgets', 'curl_exec', 'PDOStatement::execute'); xhprof_enable(0, array('argument_functions' => $args));

$pdo = new PDO('sqlite:memory:'); $pdo->exec('CREATE TABLE foo (id INT)'); $stmt = $pdo->prepare('SELECT * FROM foo'); $stmt->execute();

$fh = fopen(__FILE__, 'r'); while ($line = fgets($fh)) { }

$ch = curl_init('http://qafoo.com'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_exec($ch);

echo json_encode(xhprof_disable()); 

And its related XHProf Output formatted as JSON:

{
     "main()": {
         "ct": 1,
         "wt": 5730
     },
     "main()==>PDO::__construct": {
         "ct": 1,
         "wt": 277
     },
     "main()==>PDO::exec": {
         "ct": 1,
         "wt": 379
     },
     "main()==>PDO::prepare": {
         "ct": 1,
         "wt": 39
     },
     "main()==>PDOStatement::execute#select foo": {
         "ct": 1,         "wt": 44     },
     "main()==>curl_exec#http://qafoo.com#7": {
         "ct": 1,
         "wt": 4457
     },
     "main()==>curl_init": {
         "ct": 1,
         "wt": 73
     },
     "main()==>curl_setopt": {
         "ct": 1,
         "wt": 15
     },
     "main()==>fgets#5": {
         "ct": 21,
         "wt": 28
     },
     "main()==>fopen#/tmp/args.php#4": {
         "ct": 1,
         "wt": 28
     },
     "main()==>xhprof_disable": {
         "ct": 1,
         "wt": 1
     } 
} 

Argument summaries are still experimental and we are currently cleaning up the code before releasing another binary and integrating its output into the Tideways UI.

If you want to experiment with it, the code is currently residing in the sql_summary branch on Github.

Compiling it requires one additional manual step, copying the file ext/curl/php_curl.h from the php-src into the include folder, because it isn’t exposed to other extensions by default.

We have plans for further improvements:

  • Support for profiling template engines such as Smarty and Twig
  • Grouping PDO and mysqli calls by Transaction-IDs to allow profiling commit operations and their related queries.
  • ext/MongoDB Support

We are also open for suggestions to add other extensions or functions, maybe even framework/application related support if it makes sense.

Asynchronous Calls

PHP has limited support for asynchronous I/O, some extensions however provide such functionality for example curl_multi_exec, mysqli_async_query and stream_select.

When profiling code with multiple execution paths running at the same time, XHProf would currently ignore all the asynchronouspaths and only report the wall time for the PHP request itself.

We are currently planing to add a feature that will track the asynchronous paths as well. With this functionality you can see the duration of async queries and requests through the Tideways UI and get numbers on how efficiently you use async operations.

Conclusion

XHProf is very much alive and we are enjoying to work on all the improvements. We want to contribute all these changes back to the community as OpenSource patches so you can benefit even without using our Profiler offering.

Improving XHProf Trace Analysis

With several waves of beta testers using the Tideways, we already recieved a fair share of feedback, both positive and negative. One point of criticism was centered around the user interface, particularly unexpected page reloads and weird back-button behavior.

Today we are happy to introduce the completely redesigend transaction and profiling traces view. You can now inspect several XHProf traces at the same time and never loose focus. We are using the javascript history API for navigation in traces, creating both a fast user experience and the possibility to share even the deepest bit of information with your colleagues by copying links.

In addition we have improved the summary of a trace to highlight the most relevant information for you.

New Graphical Tools

We have also added more graphical analysis tools. For XHProf traces two different sets of graphs are useful given exlusive and inclusive wall times of function calls:

  1. For exclusive wall-times, that means the real performance impact of a function without all calls to child functions, we have introduced a treemap. The bigger the box of a function the more exclusive wall time it is using during the request.

    By clicking on a box you can directly open the call details page.

  2. For inclusive wall-times, own and child wall time, we added a so-called sunburst chart, starting in the middle with a circle for the main method of the analysed trace and adding layers of circles around it always proportionally to their share of the response time.

Both graphs should be considered experimental and we already have a list of improvements, however even in this early state they are invaluable for spotting performance problems.

Searching for Traces

In the performance section of your application, searching for a particular XHProf trace was not easy. To allow you find traces we have added a new feature: Search. You can filter by transaction names, HTTP method, urls, servers and many other criteria to find traces you are interested in.

Search will be improved in the next weeks to allow even more filtering and integrate more smoothly into the trace details view.

We are looking forward to your feedback on these new features.

Efficient collection of profiling data

One of the first challenges when collecting profiling data from PHP requests regularly is the question of efficency. One central requirement we faced for the application performance monitoring is minimal overhead.

There are two dimensions to this question, one is the aspect of transmitting and storing the other is about the optimal sampling rate. This blog post will discuss the first aspect and the second one is left for another blog post.

With the requirement of minimal overhead in mind, directly transmitting profiling data to the profiler REST API disqualified immediately.

Direct transmission without degrading user performance might work with UDP, however xhprof profile traces can easily amount to hundreds of kilobytes, way too big for UDP packages. Sending data to a remote server via UDP will also very likely lead to a significant amount of missing packages.

Sending via HTTP (TCP) would degrade performance significantly. By default I/O is blocking in PHP. Sending several KB to another server around the world can easily translate into a poor performance for your end-users. Non-blocking I/O however is not trivial to use in PHP and in our case useless: sending the profiling data is done as the last operation in the request with no other work to parallelize.

We needed a way to separate storing the profiling data before sending it to the central platform and decided to implement a daemon, acting as a proxy between all your application PHP requests and the Profiler REST API. It is written in Go to allow for very high concurrency and efficient asynchronous I/O.

The daemon accepts data over two different network interfaces, UDP for the permanent request performance measurements and Unix Socket for profiling data. Given the daemon runs on a local machine, the socket timeouts can be set to very low numbers of milliseconds, avoiding to block PHP requests even more.

Efficency when transmitting and storing data is also important. The daemon aggregates the performance data on a minute by minute basis, avoiding a constant stream of one dedicated http request for every request your application serves. It also discards profiles that don’t add value for your analysis, for example when collecting profile traces with average wall times for the high traffic frontpage in small second intervals.

This serves two goals:

  1. Not transmitting huge amounts of traffic, potentially costing money.
  2. Preventing the daemons from accidently launching a distributed denial of service attack on the Profiler REST API when traffic starts to increase.

The current process works, however, there is still a lot of room for improvement. It will be one of the tasks during the closed beta to add more logic with regard to filtering and aggregation. Our early access customers already provide us with very differentiated usage patterns to improve the situation. We are preparing to add more beta testers in a few days to get more feedback on the process.