A little under two weeks ago, a performance improvement in ownCloud was accompanied by a graph showing the difference in code execution time. The tool used to generate the graph was Blackfire, a powerful and easy to use PHP profiler. Since that first graph, many more have been created and much code has been optimized.
The first optimizations
The easy to read and intuitive Blackfire images quickly spread over Github and led to a speedup in the AppStore, thanks to caching the responses from apps.owncloud.com. While the first fetching data from the app store takes a few seconds, subsequent page loads can rely on the cache, making a big perceptible difference for the end user, easily speeding up operations 20 times. The developer making the changes, Lukas, provided a nice graph showing the difference.
Getting serious
Lukas, who ‘discovered’ Blackfire initially, started to simply upload files and use the profiler to see what took a lot of time. This resulted in a series of changes to file related operations, collected in this Github issue — starting small with a 4% performance gain on the processing of `normalizeUnicode`, adding a simplification to a check on paths and ending with a performance boost of 24% for simple searches.
Speed up file deletion
Another extensive profiling session resulted in even more impressive results after Thomas noticed that deleting a folder with 3,000+ files in it took a huge amount of time to get processed. In total over 35 minutes, showing in the profiler as this graph. It shows clearly that the bottleneck are nearly 40,000 SQL requests which are causing over 70% of the total request time.
In the first iteration the request time went down to 10 minutes by reducing the SQL queries by a factor of 10. Now, another interesting bottleneck showed up: the PHP method `strlen` was called over 60,000 times by a component from a third party library that ownCloud uses, ZendSearch, from Zend Framework. Focus moved to this library and it became clear that `strlen` was used to just decide if a string has a defined length. Somebody came up with the idea of simply using the native language construct `isset` rather than a function like `strlen`. Instead of doing this…
if (strlen($name) > 49) { ... }
… you can do this which results in the exact same behavior, except that it is a lot faster:
if (isset($name[49])) { ... }
We provided a patch upstream which reduces the load for this code path greatly.
For the deletion use case, the improvement moved the instant processing to update the search index to a background job. This results in the execution time going down to just 1 minute! There is still room for further improvements but it is a great first step and it took only a moderate amount of effort to achieve. The change from `strlen` to `isset` turned out to also be relevant in ownCloud code, bringing a nice 20% increase in speed for processing a million path lookups.
Four Punic contributions
A debugging session led to finding another performance bottleneck with very large folders and another set of upstream improvements. The first patch going in the Punic localization library was caching getTimezoneNameNoLocationSpecific, followed by this and this. Familiar by now might be a patch to use isset() instead of strlen()! On the ownCloud side, reusing the array key of mimetypes helped improve performance and the session also found a bug which was subsequently fixed. More ideas are still coming in while this issue is tackled.
Architectural impact
Not all performance issues can be relatively easily fixed. Lukas discovered that the custom OC_Autoloader in ownCloud is quite a bit slower than the Composer loader we are transitioning to. These loaders bring in functionality from third party libraries ownCloud uses when needed in a piece of code. The OC_Autoloader is the ‘old’ way ownCloud has been handling that and the fact that OC_Autoloader wasn’t fast had been noted before. ownCloud 8 will introduce the Composer loader, a dependency manager strongly inspired by Node’s npm and Ruby’s bundler. Clearly, it not only saves the ownCloud team the work of maintaining their own loader but also offers performance improvements! Moving completely to the Composer loader is already on the agenda for ownCloud 8.1.
Another change coming in ownCloud 8.1 is related to memcache, something Lukas bumped into when going through code with Blackfire. It is a relatively big change but there is already code and some testing has been done. Due to the impact, however, it will have to wait until the next release.
Impact on reporting of issues
Blackfire is also starting to be used by users who report performance issues. When asked to run a profiling run, the results prompted a first optimization already and more are in the pipeline.
Nice things about Blackfire
As most of us here at ownCloud work remotely (as in “not in one city at all”) this is a nice way to share the results with other contributors. Blackfire makes it really easy to inspect all the calls that are made during a request and to spot bottlenecks in our application even if you didn’t run the profiler.
It has an easy to use user interface that just works and the profiler has a minimal setup effort. Running an agent, loading a PHP module and clicking on a browser plugin button. That’s all you need to get some nice graphs with really valuable metrics about your request. Of course we have some wish list items already, like the ability to more easily grab images from the result graphs (or export them to other formats) and a Blackfire Firefox plugin! Last but not least, it would be great if it could do the performance optimizations automatically. For this, integration with Skynet was suggested.
Enthusiasm around the tool is becoming very visible, with a large number of performance related pull requests showing up with Blackfire graphs. We expect more improvements in ownCloud performance thanks to Blackfire – a great tool!
This post also appeared on the Blackfire blog. Thanks to Morris Jobke and Lukas Reschke for providing much of the content of this blog. And of course to everybody for the awesome work! If you like to follow ownCloud development, keep an eye on our development reports – see our overview over December.