Powered by Blogger.

Recursion with PHP v5.4, HHVM 3.0/3.1, Javascript, Java and C/C++

Lessons learned:
  • HHVM runs recursive function calls 13-20 times faster than PHP
  • HHVM runs recursive function calls 25-50 percent slower than Javascript
  • HHVM runs recursive function calls 4-5 times slower than Java
  • HHVM runs recursive function calls 2-8 times slower than C

Here is a sample script using the Ackermann function:

<?php

function ack($n, $m) {
if ($n == 0) return $m + 1;
else if ($m == 0) return ack($n - 1, 1);
else return ack($n - 1, ack($n, $m - 1));
}

function ack_while($n, $m) {
while ($n != 0) {
if ($m == 0) $m = 1;
else $m = ack_while($n, $m - 1);
$n--;
}
return $m + 1;
}

$start = microtime(true);
ack_while(3, 7);
echo number_format(microtime(true)-$start, 4).'s'.PHP_EOL;

$start = microtime(true);
ack(3, 7);
echo number_format(microtime(true)-$start, 4).'s'.PHP_EOL;

Here is a sample script using the Fibonacci function:

<?php

function fib_it($n) {
$a = 0;
$b = 1;
for ($i = 0; $i < $n; $i++){
$sum = $a+$b;
$a = $b;
$b = $sum;
}
return $a;
}

function fib_rec($n) {
if ($n < 3) return 1;
return fib_rec($n - 1) + fib_rec($n - 2);
}

$start = microtime(true);
fib_it(38);
echo number_format(microtime(true)-$start, 4).'s'.PHP_EOL;

$start = microtime(true);
fib_rec(38);
echo number_format(microtime(true)-$start, 4).'s'.PHP_EOL;

Running ack(3, 7) with PHP 5.4.4, 64bit, 2.3GHz (QEMU):

0.1127s
0.1794s
Running ack(3, 7) with HHVM 3.0/2014.03.27:

0.0089s
0.0141s
Running ack(3, 7) with Javascript (node.js v0.10):

0.013s
0.009s
Running ack(3, 7) with Java (OpenJDK 1.6 64bit):

0.011s
0.006s
Running ack(3, 7) with C (gcc 4.7):

0.002s

Running ack(3, 10) with PHP:

8.6962s
14.8648s
Running ack(3, 10) with HHVM:

Fatal error: Stack overflow in ack.php on line 12
Running ack(3, 10) with Javascript:

0.374s
0.595s
Running ack(3, 10) with Java:

0.077s
0.155s
Running ack(3, 10) with C:

0.085s

Running ack(3, 11) with PHP:

32.4175s
63.0294s
Running ack(3, 11) with HHVM:

Fatal error: Stack overflow in ack.php on line 12
Running ack(3, 11) with Javascript:

RangeError: Maximum call stack size exceeded
Running ack(3, 11) with Java:

0.314s
0.612s
Running ack(3, 11) with C:

0.339s

Running fib(38) with PHP 5.4.4, 64bit, 2.3GHz (QEMU):

0.0000s
14.6734s
Running fib(38) with HHVM 3.1/2014.04.09:

0.0032s
0.7149s
Running fib(38) with Javascript:

0.008s
0.572s
Running fib(38) with Java:

0.0s
0.158s
Running fib(38) with C:

0.092s

ack.c (run: gcc -O3 -o ack.out ack.c && time ./ack.out)

unsigned int ack(unsigned int n, unsigned int m) {
if (n == 0) return m + 1;
else if (m == 0) return ack(n - 1, 1);
else return ack(n - 1, ack(n, m - 1));
}

unsigned int ack_while(unsigned int n, unsigned int m) {
while (n != 0) {
if (m == 0) {
m = 1;
} else {
m = ack_while(n, m - 1);
}
n--;
}
return m + 1;
}

int main(int argc, char* argv[]) {
ack_while(3, 7);
ack(3, 7);
}

fib.c (run: gcc -O3 -o fib.out fib.c && time ./fib.out)

unsigned int fib_it(unsigned int n) {
unsigned int a = 0;
unsigned int b = 1;
unsigned int sum;
unsigned int i;
for (i = 0; i < n; i++){
sum = a + b;
a = b;
b = sum;
}
return a;
}

unsigned int fib_rec(unsigned int n) {
if (n < 3) return 1;
return fib_rec(n - 1) + fib_rec(n - 2);
}

int main(int argc, char* argv[]) {
fib_it(38);
fib_rec(38);
}

ack.js (run: time nodejs ack.js)

function ack(n, m) {
if (n == 0) return m + 1;
else if (m == 0) return ack(n - 1, 1);
else return ack(n - 1, ack(n, m - 1));
}

function ack_while(n, m) {
while (n != 0) {
if (m == 0) {
m = 1;
} else {
m = ack_while(n, m - 1);
}
n--;
}
return m + 1;
}

var start = new Date().getTime();
ack_while(3, 7);
console.log((new Date().getTime() - start) / 1000 + 's');

start = new Date().getTime();
ack(3, 7);
console.log((new Date().getTime() - start) / 1000 + 's');

fib.js (run: time nodejs fib.js)

function fib_it(n) {
var a = 0;
var b = 1;
var sum = 0;
for (var i = 0; i < n; i++){
sum = a + b;
a = b;
b = sum;
}
return a;
}

function fib_rec(n) {
if (n < 3) return 1;
return fib_rec(n - 1) + fib_rec(n - 2);
}

var start = new Date().getTime();
fib_it(38);
console.log((new Date().getTime() - start) / 1000 + 's');

start = new Date().getTime();
fib_rec(38);
console.log((new Date().getTime() - start) / 1000 + 's');

ack.java (run: javac -g:none ack.java && java ack)

public class ack {
public static int ack(int n, int m) {
if (n == 0) return m + 1;
else if (m == 0) return ack(n - 1, 1);
else return ack(n - 1, ack(n, m - 1));
}

public static int ack_while(int n, int m) {
while (n != 0) {
if (m == 0) {
m = 1;
} else {
m = ack_while(n, m - 1);
}
n--;
}
return m + 1;
}

public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
ack_while(3, 7);
System.out.println((float) (System.currentTimeMillis() - start) / 1000);

start = System.currentTimeMillis();
ack(3, 7);
System.out.println((float)(System.currentTimeMillis() - start) / 1000);
}
}

fib.java (run: javac -g:none fib.java && java fib)

public class fib {
public static int fib_it(int n) {
int a = 0;
int b = 1;
int sum;
for (int i = 0; i < n; i++){
sum = a + b;
a = b;
b = sum;
}
return a;
}

public static int fib_rec(int n) {
if (n < 3) return 1;
return fib_rec(n - 1) + fib_rec(n - 2);
}

public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
fib_it(38);
System.out.println((float) (System.currentTimeMillis() - start) / 1000);

start = System.currentTimeMillis();
fib_rec(38);
System.out.println((float)(System.currentTimeMillis() - start) / 1000);
}
}

0 comments:

Post a Comment