Node.js vs PHP Performance – Maths

Node.js has a reputation of being a very efficient framework, and most of the discussions around this focus on its event-driven nature, rather than the engine itself. I think it’s pretty obvious to most that when written properly, an event-driven application can be more efficient.

However, what’s not so often discussed is how the JavaScript powering node.js (and specifically the V8 engine under the bonnet) compares to other languages on simple, like-for-like tasks. With this in mind, I’m going to benchmark node.js against PHP with some very simple tasks.

This isn’t being run in completely controlled conditions, so there will be a fair amount noise in the numbers, but I’ll do my best to keep the tests fair. I’m a big believer in using the right technologies for the right purpose, and hopefully this will help ensure that.

I’m running all these tests on my own computer, which has the following specification:

  • Intel Core2 Duo E4500 @ 2.2GHz
  • 4GB memory
  • Gentoo (x86_64) with 2.6.38 kernel
  • PHP version 5.3.6
  • Node.js version 0.4.6

For each test, I intend to create a script in PHP and a corresponding script written in Node.js. They will each be written as simple, procedural, single-threaded code – remember, I’m trying to test the raw capabilities of the underlying engine, not the language constructs.

To begin with, let’s start with maths – it seems as good a place as any.

Maths

This is a really simple test. We’ll create a simple for loop containing some basic mathematical operations. We can then increase the number of loop iterations to see how each one scales.

I’m aware that this behaviour of running static sums over and over again isn’t likely to be seen in the wild, so to vary things a little, we’ll involve the counter in the sums. This will also ensure that neither engine tries to cache the outcome of each sum.

We should also be able to ensure that each script is running the loop as the duration should scale linearly with the loop size.

Here are the scripts then. First, in PHP (opening tag omitted):

  1. $a = null;
  2. $b = null;
  3. $c = null;
  4. $i = null;
  5. $max = 1e6;
  6.  
  7. $start = microtime(true);
  8.  
  9. for ($i = 0; $i < $max; $i++)
  10. {
  11.     $a = 1234 + 5678 + $i;
  12.     $b = 1234 * 5678 + $i;
  13.     $c = 1234 / 2 + $i;
  14. }
  15.  
  16. var_dump(microtime(true) - $start);
$a = null;
$b = null;
$c = null;
$i = null;
$max = 1e6;

$start = microtime(true);

for ($i = 0; $i < $max; $i++)
{
    $a = 1234 + 5678 + $i;
    $b = 1234 * 5678 + $i;
    $c = 1234 / 2 + $i;
}

var_dump(microtime(true) - $start);

and in node.js:

  1. var i, a, b, c, max;
  2.  
  3. max = 1e6;
  4.  
  5. console.time('maths');
  6.  
  7. for (i = 0; i < max; i++)
  8. {
  9.     a = 1234 + 5678 + i;
  10.     b = 1234 * 5678 + i;
  11.     c = 1234 / 2 + i;
  12. }
  13.  
  14. console.timeEnd('maths');
var i, a, b, c, max;

max = 1e6;

console.time('maths');

for (i = 0; i < max; i++)
{
    a = 1234 + 5678 + i;
    b = 1234 * 5678 + i;
    c = 1234 / 2 + i;
}

console.timeEnd('maths');

Both these scripts will be run from a terminal, in CLI mode, e.g.:

  1. $ php -f maths.php
  2. $ node maths.js
$ php -f maths.php
$ node maths.js

You’ll notice that in each case I have instantiated the variables outside of the for loop – I have done this to keep the loops as clean and similar as possible.

Results

To try and make this even vaguely scientific, I ran each test 5 times and took the median value for each.

Time (seconds)
Loop size PHP node.js
100,000 0.077 0.002
1,000,000 0.759 0.016
10,000,000 7.605 0.157
100,000,000 75.159 1.567

Whoa! In every case, node.js is around 50x faster than PHP. I certainly wasn’t expecting that! Maybe somewhat naively, I had assumed that both JS and PHP would defer these calculations into very similar underlying code, but apparently not!

It’s worth noting that the the linear relationship we hoped to see is definitely there – as the number of loop iterations increased by 10x, so did the durations for both PHP and node.js. This is good, as it shows that the engine isn’t doing any sneaky optimisations and ignoring some iterations for example – a behaviour seen in other languages (Fortran90 for example) at higher optimisation levels.

Whilst running these tests, I also observed that the deviation of the durations in PHP was significantly higher than in node.js. For example, the readings for the longest experiment deviated from the median value by 5.92 seconds (7.9%) in PHP, versus only 2 milliseconds (0.1%) in node.js.

I was going to insert a pretty graph here, but I think the results speak for themselves – roughly speaking, node.js is 50x faster than PHP when it comes to simple mathematical operations.

I’d be really interested to hear how other people get on – try out the scripts above and let me know your results. When I get a chance, I’ll look to create a slightly more rigorous test suite that I can leave for a few hours in more controlled conditions and extract some more statistical goodness.

Next time, I’ll look at JSON parsing in node.js and PHP.

6 thoughts on “Node.js vs PHP Performance – Maths

  1. I think you should retest differently.

    Instead of
    a = 1234 + 5678 + i;
    b = 1234 * 5678 + i;
    c = 1234 / 2 + i;

    can you try :
    a = 1234 + i + 5678;
    b = 1234 + i * 5678 ;
    c = 1234 + i / 2 ;

    I suspect that the JS optimizer is not doing the full math and it’s doing pre-calculation like any C compiler.
    When it converts the program into byte code it probably do the calculation there. Leaving only a=6912+i

  2. Iuc, that is probably right, but I suspect that the PHP interpreter will do the same. Also your changes wont change anything, any compiler doing pre-calculation will still do those calculations first.

    To the author: “You’ll notice that in each case I have instantiated the variables outside of the for loop”. Actually you haven’t instantiated anything there. You only _declared_ them.

  3. Iam very interested in node for embedded systems and industrial automation use.
    I changed the code and on my machine for 1,000,000 iterations it went from 2 ms to 3 ms or 4ms , which seems to suggest that it is doing the maths! its very fast anyway.
    when I made the variables global the time increased to 13 ms, which I think is reasonable.

    Actually I connected this maths function to a 1 sec timer and in the same test software I am running a simple browser app and one hardly notices the additional over head.

    This rather confirms my wildest dreams that we can use a server side script to compute process control set points and then pick them up by a simple httpget from a client sensor or actuator.

    Definitely food for thought and worthy of a lot more testing.

  4. Pingback: That thing about PHP | Gant's Blog

  5. I’ve just tested the above code to see the evolution over the years.
    Here are the results for 10,000,000 iterations on win7 x64
    node: ’0.10.13′, v8: ’3.14.5.9′ : 19ms
    php 5.5.3, opcache 7.0.3, xdebug 2.2.3: 3453.3450603485ms

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code lang=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" extra="">