2015-02-03

C++, Java, HHVM, Ruby, NodeJS/Rhino/JSC/SpiderMonkey, Go, Scala, Python/PyPy String Conversion with CombSort Benchmark

Previously, we have benchmark CombSort algorithm implemented in various programming language for array of number. Let's compare this algorithm with addition integer to string conversion the language's built-in string library. The benchmark should not use any other built-in function other than string, integer conversion and array generation and printing. The benchmark uses AMD A8-6600K, 16GB RAM with Non-SSD disk.

$ alias | grep 'alias time'
alias time='/usr/bin/time -f "\nCPU: %Us\tReal: %es\tRAM: %MKB"'
$ time --version
GNU time 1.7

$ g++ --version
g++ (GCC) 4.9.2 20141224 (prerelease)
$ time g++ -std=c++11 scomb.cpp
CPU: 0.18s      Real: 0.20s     RAM: 35868KB
$ time ./a.out
CPU: 19.32s     Real: 19.60s    RAM: 548912KB
$ time g++ -std=c++11 -O2 scomb.cpp
CPU: 0.20s      Real: 0.24s     RAM: 38184KB
$ time ./a.out
CPU: 13.76s     Real: 14.05s    RAM: 548816KB

$ clang --version
clang version 3.5.1 (tags/RELEASE_351/final)
$ time clang++ -std=c++11 scomb.cpp
CPU: 0.15s      Real: 0.20s     RAM: 42240KB
$ time ./a.out
CPU: 18.89s     Real: 19.21s    RAM: 548868KB
$ time clang++ -std=c++11 -O2 scomb.cpp
CPU: 0.20s      Real: 0.23s     RAM: 45824KB
$ time ./a.out
CPU: 13.87s     Real: 14.15s    RAM: 548820KB

$ javac -version
javac 1.7.0_71
$ time javac scomb.java
CPU: 1.13s      Real: 0.80s     RAM: 65324KB
$ time java scomb
CPU: 48.96s     Real: 27.59s    RAM: 906652KB

$ hhvm --version
HipHop VM 3.5.0 (rel)
$ time hhvm -v Eval.Jit=true scomb.php
CPU: 89.92s     Real: 90.38s    RAM: 877468KB

$ ruby --version
ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-linux]
$ time ruby scomb.rb
CPU: 114.67s    Real: 115.21s   RAM: 870612KB

$ node --version
v0.10.35
$ time node scomb.js
CPU: 17.44s     Real: 17.41s    RAM: 411144KB

$ pacman -Qo `which jsc-3`
/usr/bin/jsc-3 is owned by webkitgtk 2.4.8-1
$ time jsc-3 scomb.js
CPU: 60.08s     Real: 43.66s    RAM: 834744KB

js24 --help | grep Version
Version: JavaScript-C24.2.0
$ time js24 scomb.js
CPU: 19.27s     Real: 19.62s    RAM: 735556KB

$ go version
go version go1.4.1 linux/amd64
$ time go build scomb.go
CPU: 0.14s      Real: 0.17s     RAM: 30428KB
$ time ./scomb
CPU: 11.45s     Real: 11.54s    RAM: 251628KB

$ scala -version
Scala code runner version 2.11.5 -- Copyright 2002-2013, LAMP/EPFL
$ time scala -J-Xmx3000M scomb.scala
CPU: 83.42s     Real: 46.10s    RAM: 1093924KB

$ python --version
Python 3.4.2
$ time python scomb.py
CPU: 121.33s    Real: 122.06s   RAM: 641844KB

$ pypy --version
Python 2.7.8 (c6ad44ecf5d8, Nov 18 2014, 18:04:31) [PyPy 2.4.0 with GCC 4.9.2]
$ time pypy scomb.py
CPU: 14.72s     Real: 14.97s    RAM: 522080KB

And here's the code:

//////////////////////////////
// scomb.cpp
#include<cstdio>
#include<string>
using namespace std;
int newGap(int gap){
    gap /= 1.3;
    if(gap == 9 || gap == 10) return 11;
    if(gap < 1) return 1;
    return gap;
}
void combSort(string a[], int len){
    int gap = len;
    bool swapped;
    do {
        swapped = false;
        gap = newGap(gap);
        for(int i=0; i < len-gap; ++i) {
            if(a[i] > a[i+gap]) {
                swapped = true;
                a[i].swap(a[i+gap]);
            }
        }
    } while(gap > 1 || swapped);
}
const int N = 10000000;
int main() {
    string* arr = new string[N];
    for(int z=0;z<N;++z) arr[z] = to_string(N-z);    
    combSort(arr,N);
    for(int z=1;z<N;++z) if(arr[z]<arr[z-1]) printf("!");
    delete[] arr;
}

//////////////////////////////
// scomb.java
public class scomb {
    public static int newGap(int gap){
        gap /= 1.3;
        if(gap == 9 || gap == 10) return 11;
        if(gap < 1) return 1;
        return gap;
    }
    public static void combSort(String a[], int len){
        int gap = len;
        String temp;
        boolean swapped;
        do {
            swapped = false;
            gap = newGap(gap);
            for(int i=0; i < len-gap; ++i) {
                if(a[i].compareTo(a[i+gap])>0) {
                    swapped = true;
                    temp = a[i];
                    a[i] = a[i+gap];
                    a[i+gap] = temp;
                }
            }
        } while(gap > 1 || swapped);
    }
    public static final int N = 10000000;
    public static void main(String[] args) {
        String[] arr = new String[N];
        for(int z=0;z<N;++z) arr[z] = "" + (N-z);    
        combSort(arr,N);
        for(int z=1;z<N;++z) if(arr[z].compareTo(arr[z-1])<0) System.out.print("!");
    }   
}

<? //////////////////////////////
   // scomb.php
function newGap($gap){
    $gap /= 1.3;
    $gap = intval($gap);
    if($gap == 9 || $gap == 10) return 11;
    if($gap < 1) return 1;
    return $gap;
}
function combSort(&$a) {
    $len = sizeof($a);
    $gap = $len;
    $temp = 0.0;
    $swapped = false;
    do {
        $swapped = false;
        $gap = newGap($gap);
        for($i=0; $i < $len-$gap; ++$i) {
            if($a[$i] > $a[$i+$gap]) {
                $swapped = true;
                $temp = $a[$i];
                $a[$i] = $a[$i+$gap];
                $a[$i+$gap] = $temp;
            }
        }
    } while($gap > 1 || $swapped);
}
const N = 10000000;
$arr = array_fill(0,N,'');
for($z=0;$z<N;++$z) $arr[$z] = ''.(N-$z);
combSort($arr);
for($z=1;$z<N;++$z) if($arr[$z]<$arr[$z-1]) echo "!";

##############################
# scomb.rb
def newGap gap
    gap /= 1.3;
    gap = gap.to_i;
    return 11 if gap == 9 or gap == 10
    return 1 if gap < 1
    gap
end
def combSort a
    len = a.length
    gap = len
    swapped = false
    begin
        swapped = false
        gap = newGap gap
        (0...(len-gap)).each do |i|
            if a[i] > a[i+gap]
                swapped = true
                a[i], a[i+gap] = a[i+gap], a[i]
            end
        end
    end while gap > 1 or swapped
end
N = 10000000;
arr = N.times.map{|x| (N-x).to_s }
combSort arr
(1...N).each{ |z| print '!' if arr[z]<arr[z-1] }

//////////////////////////////
// scomb.js
function newGap(gap){
    gap /= 1.3;
    gap = gap|0;
    if(gap == 9 || gap == 10) return 11;
    if(gap < 1) return 1;
    return gap;
}
function combSort(a){
    var len = a.length;
    var gap = len;
    var temp;
    var swapped;
    do {
        swapped = false;
        gap = newGap(gap);
        for(var i=0; i < len-gap; ++i) {
            if(a[i] > a[i+gap]) {
                swapped = true;
                temp = a[i];
                a[i] = a[i+gap];
                a[i+gap] = temp;
            }
        }
    } while(gap > 1 || swapped);
}
var N = 10000000;
var arr = new Array(N);
for(var z=0;z<N;++z) arr[z] = '' + (N-z);    
combSort(arr);
for(var z=1;z<N;++z) if(arr[z]<arr[z-1]) console.log("!");

//////////////////////////////
// scomb.go
package main
import "fmt"
import "strconv"
func newGap(gap int) int {
    gap = int(float64(gap) / 1.3)
    if gap == 9 || gap == 10 {
        return 11
    }
    if gap < 1 {
        return 1
    }
    return gap
}
func combSort(a []string) {
    xlen := len(a)
    gap := xlen
    swapped := false
    for {
        swapped = false
        gap = newGap(gap)
        for i := 0; i < xlen-gap; i++ {
            if a[i] > a[i+gap] {
                swapped = true
                a[i], a[i+gap] = a[i+gap], a[i]
            }
        }
        if !(gap > 1 || swapped) {
            break
        }
    }
}
const N = 10000000
func main() {
    arr := make([]string, N, N)
    for z := 0; z < N; z++ {
        arr[z] = strconv.Itoa(N - z)
    }
    combSort(arr)
    for z := 1; z < N; z++ {
        if arr[z] < arr[z-1] {
            fmt.Print("!")
        }
    }
}

//////////////////////////////
// scomb.scala
object scomb {
    def newGap(gap: Int): Int = {
        var ngap : Int = (gap.toDouble / 1.3).toInt;
        if(ngap == 9 || ngap == 10) return 11;
        if(ngap < 1) return 1;
        return ngap;
    }
    def combSort(a: Array[String]) : Array[String] = {
        var res : Array[String] = a;
        val len = a.length;
        var gap = len;
        var temp : String = "";
        var swapped : Boolean = false;
        do {
            swapped = false;
            gap = newGap(gap);
            for(i <- 0 until len-gap if res(i) > res(i+gap)) {
                swapped = true;
                temp = res(i);
                res(i) = res(i+gap);
                res(i+gap) = temp;
            }
        } while(gap > 1 || swapped);
        return res
    }
    val N = 10000000;
    def main(args: Array[String]) {
        var arr : Array[String] = new Array[String](N)
        for(z <- 0 until N) arr(z) = (N-z).toString;   
        arr = combSort(arr); 
        for(z <- 1 until N if arr(z)<arr(z-1)) print("!");
    }
}

##############################
# scomb.py
def newGap(gap):
    gap /= 1.3
    if gap == 9 or gap == 10:
        return 11
    if gap < 1:
        return 1
    return int(gap)
def combSort(a, len):
    gap = len
    while True:
        swapped = False
        gap = newGap(gap)
        for i in range(0,len-gap):
            if a[i] > a[i+gap]:
                swapped = True
                temp = a[i]
                a[i] = a[i+gap]
                a[i+gap] = temp
        if not(gap > 1 or swapped):
            break
N = 10000000;
arr = [ str(N-z) for z in range(0,N)] 
combSort(arr,N)
for z in range(1,N):
    if arr[z]<arr[z-1]:
        print("!")

And the summary:

Compiler / InterpreterLanguageCompile DurationCompile RAMRuntime DurationRuntime RAMTotal DurationMax RAM
g++ (debug)C++180358681932054891219500548912
g++ (-O2)C++200381841376054881613960548816
clang++ (debug)C++150422401889054886819040548868
clang++ (-O2)C++200458241387054882014070548820
javac, javaJava1130653244896090665250090906652
hhvmPHP8992087746889920877468
rubyRuby114670870612114670870612
nodeJavascript1744041114417440411144
jsc-3Javascript6008083474460080834744
js24Javascript1927073555619270735556
goGo140304281145025162811590251628
scalac, scalaScala834201093924834201093924
python3Python 3121330641844121330641844
pypyPython 21472052208014720522080

Write down your opinion (or pastie if you found a bug on these source, or if you want to add more language implementation) on the comment section ^^)b

Note #1: PHP 5.6.4, Rubinius 2.5.2, JRuby 9.0.0a1, Rhino 1.7, MCS 3.12 failed to end their execution within approx. 120s timeout

Note #2: I failed to implement Rust version, since I haven't learned about it much.

No comments :

Post a Comment