•  6 min read  •  176 views

Benchmarking PHP vs Javascript vs Java

Benchmarking PHP vs Javascript vs Java

PHP has a reputation for being dog slow. But like most of the criticisms leveled at PHP, this opinion may be based on impression from more than 10 years ago. Never mind that you have PHP sites serving millions (or even billions) of pages per day. In this article we benchmark some math-heavy code to see how modern PHP performs when compared to Javascript and Java.

Can PHP keep up with Javascript and Java?

PHP is a language that (since probably more than 15 years ago) essentially runs code that has been translated/compiled to a assembly-like language in it's runtime environment. If the PHP people would be better at marketing, they'd call it a virtual machine, just like the Java people do. In essence, PHP at a fundamental level, works the same way that both Javascript and Java, so it's interesting to see how they perform, especially now that PHP has a JIT (Just-In-Time compiler) component which allows for additional optimizations.

Architecture Considerations

Java, of course, is a strongly typed language which features an explicit compliation step, which allows the optimizer to make more inferences about the code and take all the time it needs (within reason, of course). Presumably this results in faster code.

Javascript is architecturally more similar to PHP but has benefited from major investment from the likes of Google and Microsoft to make its runtime as fast as possible.

PHP is the newcomer on the JIT front and we'll see how this impacts the same code we'll run. While not quite there yet, my guess would be that further improvements of PHP execution speed would be possible if some time and money were to be thrown at the problem (caveat, I'm not a compiler expert, the last (and only) compiler I wrote was in University, many years ago).

Benchmarking Considerations

It should be noted that the PHP JIT will offer limited benefits to typical web requests which run for maybe 0.1 seconds and don't perform much repetitive code. As such, the benchmarks I will be using here, are focussed on repeated mathematical calculations.

You may wonder why I care about this if this does not reflect the typical PHP workload? Well, many years ago, I wrote https://www.firedrake.org/terraform/, a terrain generator. Back then (in the late 90s), many of the operations were painfully slow, but since then we've seen massive improvements in processing power so that now bare metal C code might not be required anymore to get decent performance. Recently, with the advent of https://nativephp.com/ this area is again insteresting to me because it would provide another option to resurrect this code. The original code was written against the Gnome2 API but Gnome2 is dead and Gnome3 breaks (or rather removes) quite a few GUI-related things that the Terraform code relies on. Add to this that decent Gnome programming docs and tutorials basically don't exist (if you aren't very familiar with Gnome development, then good luck to you) and the need for a new platform that the code could be ported to without requiring an excessive effort, becomes apparent.

The Benchmarks

For this benchmark, I'll be using some code which generates random numbers according to a normal distribution. The reason for picking this routine are twofold:

  1. Terraform relies heavily on this random number generator
  2. The code is simple with no additional dependencies and is easy to translate to other programming languages.

So, now that you're on the edge of your seat and want to know the details, lets get started:

The PHP Code

<?php

for ($i=0; $i<1000*1000*100; $i++) {
        $rnd = getRandNormal01(0, 1);
        if ($i%10000000 == 0) {
                print "$rnd\n";
        }

}
        
function boxMullerTransform(float $mean, float $standardDev)
{               
        $x = mt_rand(0,10000000000)/10000000000;
        $y = mt_rand(0,10000000000)/10000000000;
        
        return sqrt(-2.0 * log($x)) * cos(2.0 * M_PI * $y) * $standardDev + $mean;
}       


function getRandNormal01($mean, $standardDev): float
{
        $min   = -6.0;
        $max   =  6.0; 
        $value = boxMullerTransform($mean, $standardDev);

        if ($value < $min) {
                return 0;
        } 
        if ($value > $max) {
                return 1;
        }
        
        return ($value - $min) / ($max - $min);
}

The Javascript Code

for (i=0; i<1000*1000*100; i++) {
        rnd = getRandNormal01(0, 1);
        if (i%10000000 == 0) {
                console.log(rnd);
        }
}

        
function boxMullerTransform(av, sd) 
{               
        const u1 = Math.random();
        const u2 = Math.random();
        
        return Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(2.0 * Math.PI * u2) * sd + av;
}       


function getRandNormal01(av, sd)
{
        const min   = -6.0;
        const max   =  6.0;
        const value = boxMullerTransform(av, sd);

        if (value < min) { 
                return 0;
        } else if (value > max) {
                return 1;
        }       
        
        return (value - min) / (max - min);
}       

The Java Code

public class Main
{
    public static void main(String[] args)
    {
        for (int i = 0; i < 1000 * 1000 * 100; i++) {
            double rnd = getRandNormal01(0, 1);
            if (i % 10000000 == 0) {
                System.out.println(rnd);
            }

        }
    }

    private static double boxMullerTransform(double av, int sd)
    {
        double u1 = Math.random();
        double u2 = Math.random();

        return Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(2.0 * Math.PI * u2) * sd + av;
    }

    private static double getRandNormal01(double av, int sd)
    {
        double min   = -6.0;
        double max   = 6.0;
        double value = boxMullerTransform(av, sd);

        if (value < min) {
            return 0;
        } else if (value > max) {
            return 1;
        }

        return (value - min) / (max - min);
    }
}

The Results

  • PHP 8.1 Default: 94 sec
  • PHP 8.1 with JIT: 10.1 sec
  • Javascript Node 18: 4.6 sec
  • Java OpenJDK 21: 3.0 sec

All results are in seconds elapsed, so lower is better. As expected, PHP in it's default configuration is quite slow. This was sort of expected, no real surprises there.

In case you prefer an image, here's a simple chart:

Benchmark Data

Since the PHP Default value is very large compared to the other values, lets remove it. We then get this:

Benchmark Data

The interesting thing is, that once PHP JIT is enabled, PHP gets an almost 10x performance increase and the performance gap to Javascript shrinks dramatically, bringing PHP to almost 50% of the performance of Javascript. Given the amount of tuning and optimization work that has gone into Javascript (and the realtive newness of PHP JIT), this is actually quite good. Since both these languages are essentially wrappers for the libc in terms of Math performance (I'm simplifying here, but bear with me), there is hope that over time PHP will be able to close this gap further.

Java is about 20% faster than Javascript, which again, is an expected result. The surprise here actually is that Java doesn't outperform Javascript by a greater margin.

What does this mean?

For certain applications (scientific number crunching, heavy data analysis, etc.) PHP has become a much more viable choice, especially given that it's much easier to implement complex code in PHP when compared to Java.

For Terraform, this might mean that the sweet spot is to build the GUI using PHP and do the math in Javascript which is an entirely viable approach given the archtecture used for PHPNative.

Addendum 1

In case you're wondering what Terraform looked like, here are a few screenshots.

Screenshot1 Screenshot2 Screenshot3

Addendum 2

It would appear that NativePHP is not quite there yet. I did some initial tests and it seems that on Linux (at least on Ubuntu 23.04, which is what I'm currently running), and I was unable to get a menu bar to display. There is an open bug here, for this issue, which for now, appears unresolved. Hopefully this will eventually be fixed and I can do some more experimentation.

Addendum 3

PHP has announced that a new JIT architecture will be developed/deployed (I think starting with PHP 8.3, but don't quote me on that) that should allow further improvements to the JIT engine. So with a bit of luck, the gap between PHP and Javascript will be further narrowed.


Related Posts