Benefits of Compiling PHP to .NET with Peachpie

As we continue making progress with the development of Peachpie, we have implemented several constructs that demonstrate the benefits of using a PHP compiler to .NET. This week, we would like to show some official PHP benchmarks and explain why this is significant.

The pitfalls of benchmarking performance

Peachpie is a PHP language compiler to .NET, targeting a full PHP 7 compatibility, improved performance and increased security. As effective as diagrams comparing the performance of PHP against Peachpie can look, our focus has in fact been on the compatibility and interoperability aspects, which are more difficult to demonstrate. Some of our benchmarks should perhaps have been called “comparison” instead, as measuring the performance on Azure with the basic subscription, for instance, is impossible to emulate on a different setup.

Performance, however, is dangerous as a comparative basis, because it is questionable while maintaining the dynamic nature of the PHP language. Therefore, as can be seen from the benchmarks below, when the basis of the tests is a script that makes use entirely of language dynamicity and does not benefit much from the compiler advantages, Peachpie will struggle to produce the same results. It is, however, a great chance to show how to profile and improve the performance of a PHP application running on top of .NET and how to overcome this hurdle.

Standard PHP benchmark

Seeing as we mostly produced our own microbenchmarks to date, testing individual constructs, we realized that it would behoove us to implement generally recognized PHP benchmarks and run a performance and compatibility test with these scripts. The following benchmarks are thus taken from the Internet and no adjustments have been made on our part. The focus with these tests is the fact that even legacy PHP code can be compiled to .NET, rather than a comparison of the performance. Nonetheless, besides depicting the benefits of compilation, we will also show how to make the code faster with a few additional and backward compatible lines of code.

Code sample:

The test code was taken from http://php_benchmark.onlinephpfunctions.com/.

Initial profiling

We profiled the code after compiling it with Peachpie using Visual Studio. At this moment, Peachpie is a compiler that is still in development, implying that there is still a lot of space for future optimizations. However, it is already a great achievement to compile and run legacy PHP code as it is on top of .NET. It means that the compiled code is compatible, while benefiting from a modern platform.

Compiling and running the code:

[bash]
peach.exe benchmark.php
benchmark.exe
[/bash]

The program outputted the following:

[bash]
########################################
| PHP BENCHMARK |
########################################
Start : 07/17/2016 23:25:58 pm
Server : @
PHP version : 7.0.0-peach
Platform : WinNT
########################################
Math : 0.890 sec.
String Manipulation : 0.987 sec.
Loops : 0.650 sec.
If/Else : 0.495 sec.
########################################
Total: : 3.022 sec.
[/bash]

If you were to try the same with the legacy `php.exe`, the code would currently be slightly faster than with Peachpie, since the .NET Framework adds quite a bit of non-trivial overhead. Examples of such aspects include garbage collection, array bounds checking, built-in reflection support and many other features that are there out of the box.

Luckily it is easy to profile our compiled script and find the weak spots. We can do this directly in Visual Studio using the Performance and Diagnostics tools. Then you can open, for example a call tree with the time spent in each function across the whole application.

profiling0

The performance of such Peachpie-compiled scripts, however, can be improved significantly with just a few additional lines of code that help the compiler.

A closer look

When we analyze the code more thoroughly, we can see how significantly we can improve the compilation without changing the compiler itself.

  • First, Peachpie is meant to run on a web server to handle heavy usage. That is why it makes use of dynamically compiled constructs that are cached when needed for the first time. It means the first run is always a little bit slower, so we will make two passes of the test where the first one is just a warmup.

  • There are a lot of loops while the compiler cannot assume the types of control variables. Let’s add type information for the method parameters. Thanks to this, while loops and for loops will be about 1000 times faster than before, since the compiler can make use of native Int64 types for control variables.

  • Then next optimization avoids repetitious memory copying. Since call_user_func_array() takes an associative array that has to be internally copied into a simple array, we shall use call_user_func() instead. It takes .NET params as a flat array already.

  • Just to see the overhead of dynamic calls caused by constant lookups into hashtables, let us get rid of call_user_func() completely. We will replace it with an actual functions call.

Results after the changes

[bash]
########################################
| PHP BENCHMARK |
########################################
Start : 07/18/2016 00:06:38 am
Server : @
PHP version : 7.0.0-peach
Platform : WinNT
########################################
Math : 0.109 sec.
String Manipulation : 0.263 sec.
Loops : 0.011 sec.
If/Else : 0.006 sec.
########################################
Total: : 0.389 sec.
[/bash]

As the program output above shows, by making these small adjustments to the code, the performance of Peachpie-compiled code can be boosted significantly. Just as a note, the modified code is 4 times faster on Peachpie compared to PHP 7.0.6.

Conclusion

The .NET Framework provides an outstanding ecosystem and Roslyn is a complete compiler platform that helps us build an efficient PHP compiler from scratch in a very short time. Consequently, the compiled PHP code can run producing the same results as legacy PHP, but faster in many instances, while allowing for a seamless interoperability with .NET. Code profiling and further optimizations are very simple with .NET and Visual Studio, giving developers a powerful tool to make targeted adjustments to their code to further increase its performance.


Download the demo together with the latest build of Peachpie:
https://github.com/iolevel/peachpie/releases/tag/2016-07-18

As a final remark, Mono provides additional JIT options that may improve the performance of .NET code even more. Stay tuned, as we will be demonstrating the benefits and specifics of the Mono JIT settings in connection to Peachpie in the coming weeks.

Posted on July 18, 2016, in category Profiling, tags: , , , , , , , ,