Language Speed

Purpose:

The purpose of this article is to show some speed comparisons between different languages and different compilers/runtimes.

Disclaimers:

There is an old saying that "There are lies, damned lies and benchmarks.". There are some element of truth to that saying. Benchmark results should always be treated with lots of skepticism.

First, then real world application performance often depends a lot more on disk speed and network speed than CPU speed.

Second, different real world applications are by definition very different. The instruction mix they end up executing are different and the particular instruction mix used by the benchmark is not super relevant.

Third, short benchmarks aka microbenchmarks are notoriously vulnerable to exaggerating the impact of certain optimizations. If a benchmark only does 3 things and a compiler can optimize one of them heavily then it may reduce the benchmark time by 33%, but that does not mean that it can achieve the same for a real world application that does 3000 things.

So bottom line is that by far the best benchmark is the real application.

Foe more information about pitfalls of benchmarks and potential mitigation see Benchmarking.

Benchmark code:

JvmTest.java:

import java.text.NumberFormat;
import java.text.DecimalFormat;

public class JvmTest {
    private static NumberFormat nf = new DecimalFormat("0.00");
    private static void printres(long t1, long t2, int n1, int n2, String ops) {
        double xperf = (double)n1 * (double)n2 / ((t2 - t1) / 1000.0) ;
        String sperf = nf.format(xperf / 1000000);
        System.out.println(sperf + " million " + ops + " per second");
    }
    private final static int NINT = 10000;
    private final static int NFP = 1000;
    private final static int NSTR = 1000;
    private final static int N = 1000000;
    public static void testint(int scale) {
        int nintscale = NINT / scale;
        long t1 = System.currentTimeMillis();
        for(int i = 0; i < nintscale; i++) {
            int sum = i;
            for(int j = 0; j < N; j++) {
                sum = ((sum + 1) * 2 + 1) / 2;
            }
            if(sum != (i + N)) {
                System.out.println("Integer test error");
                System.exit(1);
            }
        }
        long t2 = System.currentTimeMillis();
        printres(t1, t2, nintscale, N, "integer operations");
    }
    public static void testfp(int scale) {
        int nfpscale = NFP / scale;
        long t1 = System.currentTimeMillis();
        for(int i = 0; i < nfpscale; i++) {
            double sum = i;
            for(int j = 0; j < N; j++) {
                sum = ((sum + 1) * 2 + 1) / 2;
            }
            if(Math.abs(sum - (i + 1.5 * N)) > 1) {
                System.out.println("Floating point test error");
                System.exit(1);
            }
        }
        long t2 = System.currentTimeMillis();
        printres(t1, t2, nfpscale, N, "floating point operations");
    }
    private final static String ALFA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    public static void teststr(int scale) {
        int nstrscale = NSTR / scale;
        long t1 = System.currentTimeMillis();
        for(int i = 0; i < nstrscale; i++) {
            StringBuffer sb = new StringBuffer("");
            for(int j = 0; j < N; j = j + 10) {
                String s = ALFA + ALFA;
                int ix = (i + j) % ALFA.length();
                sb.append(s.substring(ix, ix + 1) + s.substring(ix + 1, ix + 3) + s.substring(ix + 3, ix + 6) + s.substring(ix + 6, ix + 10));
            }
            int ix1 = N / 3;
            int ix2 = 2 * N / 3; 
            if(sb.length() != N || sb.charAt(ix1) != ALFA.charAt((i + ix1) % ALFA.length()) || sb.charAt(ix2) != ALFA.charAt((i + ix2) % ALFA.length())) {
                System.out.println("String test error");
                System.exit(1);
            }
        }
        long t2 = System.currentTimeMillis();
        printres(t1, t2, nstrscale, N / 10, "string operations");
    }
    private final static int REP = 10;
    public static void main(String[] args) {
        System.out.println(System.getProperty("java.vm.vendor") + " " + System.getProperty("java.vm.name") + " " + System.getProperty("java.vm.version"));
        int scale = 1;
        if(args.length > 0) {
            scale = Integer.parseInt(args[0]);
        }
        for(int i = 0; i < REP; i++) {
            testint(scale);
        }
        for(int i = 0; i < REP; i++) {
            testfp(scale);
        }
        for(int i = 0; i < REP; i++) {
            teststr(scale);
        }
    }
}

DotNETTest.cs:

using System;
using System.Text;

public class DotNETTest
{
    private static void printres(long t1, long t2, int n1, int n2, String ops)
    {
        double xperf = (double)n1 * (double)n2 / ((t2 - t1) / 1000.0) ;
        string sperf = String.Format("{0:0.00}", xperf / 1000000);
        Console.WriteLine(sperf + " million " + ops + " per second");
    }
    private const int NINT = 10000;
    private const int NFP = 1000;
    private const int NSTR = 100;
    private const int N = 1000000;
    public static void testint(int scale)
    {
        int nintscale = NINT / scale;
        long t1 = DateTime.Now.Ticks / 10000;
        for(int i = 0; i < nintscale; i++)
        {
            int sum = i;
            for(int j = 0; j < N; j++)
            {
                sum = ((sum + 1) * 2 + 1) / 2;
            }
            if(sum != (i + N))
            {
                Console.WriteLine("Integer test error");
                Environment.Exit(1);
            }
        }
        long t2 = DateTime.Now.Ticks / 10000;
        printres(t1, t2, nintscale, N, "integer operations");
    }
    public static void testfp(int scale)
    {
        int nfpscale = NFP / scale;
        long t1 = DateTime.Now.Ticks / 10000;
        for(int i = 0; i < nfpscale; i++)
        {
            double sum = i;
            for(int j = 0; j < N; j++)
            {
                sum = ((sum + 1) * 2 + 1) / 2;
            }
            if(Math.Abs(sum - (i + 1.5 * N)) > 1)
            {
                Console.WriteLine("Floating point test error");
                Environment.Exit(1);
            }
        }
        long t2 = DateTime.Now.Ticks / 10000;
        printres(t1, t2, nfpscale, N, "floating point operations");
    }
    private const string ALFA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    public static void teststr(int scale)
    {
        int nstrscale = NSTR / scale;
        long t1 = DateTime.Now.Ticks / 10000;
        for(int i = 0; i < nstrscale; i++)
        {
            StringBuilder sb = new StringBuilder("");
            for(int j = 0; j < N; j = j + 10)
            {
                string s = ALFA + ALFA;
                int ix = (i + j) % ALFA.Length;
                sb.Append(s.Substring(ix, 1) + s.Substring(ix + 1, 2) + s.Substring(ix + 3, 3) + s.Substring(ix + 6, 4));
            }
            int ix1 = N / 3;
            int ix2 = 2 * N / 3;
            if(sb.Length != N || sb[ix1] != ALFA[(i + ix1) % ALFA.Length] || sb[ix2] != ALFA[(i + ix2) % ALFA.Length])
            {
                Console.WriteLine("String test error");
                Environment.Exit(1);
            }
        }
        long t2 = DateTime.Now.Ticks / 10000;
        printres(t1, t2, nstrscale, N / 10, "string operations");
    }
    private const int REP = 10;
    public static void Main(string[] args)
    {
        Console.WriteLine("{0} ({1} bit)", Environment.Version, IntPtr.Size * 8);
        int scale = 1;
        if(args.Length > 0)
        {
            scale = int.Parse(args[0]);
        }
        for(int i = 0; i < REP; i++)
        {
            testint(scale);
        }
        for(int i = 0; i < REP; i++)
        {
            testfp(scale);
        }
        for(int i = 0; i < REP; i++)
        {
            teststr(scale);
        }
    }
}

native_test.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "high_res_timer.h"

void printres(TIMECOUNT_T t1, TIMECOUNT_T t2, int n1, int n2, char *ops)
{
    double xperf;
    xperf = (double)n1 * (double)n2 / ((t2 - t1) * 1.0 / UNITS_PER_SECOND);
    printf("%.2f million %s per second\n", xperf / 1000000, ops);
}

#define NINT 10000
#define NFP 1000
#define NSTR 100
#define N 1000000

void testint(int scale)
{
    int i, j;
    int nintscale, sum;
    TIMECOUNT_T t1, t2;
    nintscale = NINT / scale;
    t1 = GET_TIMECOUNT;
    for(i = 0; i < nintscale; i++)
    {
        sum = i;
        for(j = 0; j < N; j++)
        {
            sum = ((sum + 1) * 2 + 1) / 2;
        }
        if(sum != (i + N))
        {
            printf("Integer test error\n");
            exit(0);
        }
    }
    t2 = GET_TIMECOUNT;
    printres(t1, t2, nintscale, N, "integer operations");
}

void testfp(int scale)
{
    int i, j;
    int nfpscale;
    double sum;
    TIMECOUNT_T t1, t2;
    nfpscale = NFP / scale;
    t1 = GET_TIMECOUNT;
    for(i = 0; i < nfpscale; i++)
    {
        sum = i;
        for(j = 0; j < N; j++)
        {
            sum = ((sum + 1) * 2 + 1) / 2;
        }
        if(fabs(sum - (i + 1.5 * N)) > 1)
        {
            printf("Floating point test error\n");
            exit(0);
        }
    }
    t2 = GET_TIMECOUNT;
    printres(t1, t2, nfpscale, N, "floating point operations");
}

#define ALFA "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

void teststr(int scale)
{
    int i, j;
    int ix, ix1, ix2;
    int nstrscale;
    char s[1000], buf[N+1];
    TIMECOUNT_T t1, t2;
    nstrscale = NSTR / scale;
    t1 = GET_TIMECOUNT;
    for(i = 0; i < nstrscale; i++)
    {
        strcpy(buf, "");
        for(j = 0; j < N; j = j + 10)
        {
            strcpy(s, ALFA);
            strcat(s, ALFA);
            ix = (i + j) % strlen(ALFA);
            strncat(buf + j, s + ix, 1);
            strncat(buf + j, s + ix + 1, 2);
            strncat(buf + j, s + ix + 3, 3);
            strncat(buf + j, s + ix + 6 , 4);
        }
        ix1 = N / 3;
        ix2 = 2 * N / 3; 
        if(strlen(buf) != N || buf[ix1] != ALFA[(i + ix1) % strlen(ALFA)] || buf[ix2] != ALFA[(i + ix2) % strlen(ALFA)])
        {
            printf("String test error\n");
            exit(0);
        }
    }
    t2 = GET_TIMECOUNT;
    printres(t1, t2, nstrscale, N / 10, "string operations");
}

#define REP 10

int main(int argc, char *argv[])
{
    int i;
    int scale;
    printf("%d bit\n", (int)(sizeof(char *) * 8));
    if(argc > 1)
    {
        scale = atoi(argv[1]);
    }
    else
    {
        scale = 1;
    }
    for(i = 0; i < REP; i++)
    {
        testint(scale);
    }
    for(i = 0; i < REP; i++)
    {
        testfp(scale);
    }
    for(i = 0; i < REP; i++)
    {
        teststr(scale);
    }
    return 0;
}

native_test.cpp:

#include "high_res_timer.h"

#include <iostream>
#include <iomanip>
#include <ios>
#include <string>
#include <cmath>
#include <cstdlib>

using namespace std;

void printres(TIMECOUNT_T t1, TIMECOUNT_T t2, int n1, int n2, const char *ops)
{
    double xperf = (double)n1 * (double)n2 / ((t2 - t1) * 1.0 / UNITS_PER_SECOND);
    cout << fixed << setprecision(2) << (xperf / 1000000) << " million " << ops << " per second" << endl;
}

const int NINT = 10000;
const int NFP = 1000;
const int NSTR = 100;
const int N = 1000000;

void testint(int scale)
{
    int nintscale = NINT / scale;
    TIMECOUNT_T t1 = GET_TIMECOUNT;
    for(int i = 0; i < nintscale; i++)
    {
        int sum = i;
        for(int j = 0; j < N; j++)
        {
            sum = ((sum + 1) * 2 + 1) / 2;
        }
        if(sum != (i + N))
        {
            cout << "Integer test error" << endl;
            exit(0);
        }
    }
    TIMECOUNT_T t2 = GET_TIMECOUNT;
    printres(t1, t2, nintscale, N, "integer operations");
}

void testfp(int scale)
{
    int nfpscale = NFP / scale;
    TIMECOUNT_T t1 = GET_TIMECOUNT;
    for(int i = 0; i < nfpscale; i++)
    {
        double sum = i;
        for(int j = 0; j < N; j++)
        {
            sum = ((sum + 1) * 2 + 1) / 2;
        }
        if(fabs(sum - (i + 1.5 * N)) > 1)
        {
            cout << "Floating point test error" << endl;
            exit(0);
        }
    }
    TIMECOUNT_T t2 = GET_TIMECOUNT;
    printres(t1, t2, nfpscale, N, "floating point operations");
}

const string ALFA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

void teststr(int scale)
{
    int nstrscale = NSTR / scale;
    TIMECOUNT_T t1 = GET_TIMECOUNT;
    for(int i = 0; i < nstrscale; i++)
    {
        string s, buf;
        buf = "";
        for(int j = 0; j < N; j = j + 10)
        {
            s = ALFA + ALFA;
            int ix = (i + j) % ALFA.length();
            //buf = buf + s.substr(ix, 1) + s.substr(ix + 1, 2) + s.substr(ix + 3, 3) + s.substr(ix + 6, 4);
            buf.append(s, ix, 1);
            buf.append(s, ix + 1, 2);
            buf.append(s, ix + 3, 3);
            buf.append(s, ix + 6, 4);
        }
        int ix1 = N / 3;
        int ix2 = 2 * N / 3; 
        if(buf.length() != N || buf[ix1] != ALFA[(i + ix1) % ALFA.length()] || buf[ix2] != ALFA[(i + ix2) % ALFA.length()])
        {
            cout << "String test error" << endl;
            exit(0);
        }
    }
    TIMECOUNT_T t2 = GET_TIMECOUNT;
    printres(t1, t2, nstrscale, N / 10, "string operations");
}

#define REP 10

int main(int argc, char *argv[])
{
    int i;
    int scale;
    cout << (sizeof(char *) * 8) << " bit" << endl;
    if(argc > 1)
    {
        scale = atoi(argv[1]);
    }
    else
    {
        scale = 1;
    }
    for(i = 0; i < REP; i++)
    {
        testint(scale);
    }
    for(i = 0; i < REP; i++)
    {
        testfp(scale);
    }
    for(i = 0; i < REP; i++)
    {
        teststr(scale);
    }
    return 0;
}

native_test.pas:

program native_test(input, output);

{$APPTYPE CONSOLE}

uses
    SysUtils, Windows;

procedure printres(t1, t2 : Cardinal; n1, n2 : integer; ops : string);

var
    xperf : double;

begin
    xperf := n1 * 1.0 * n2 / ((t2 - t1) / 1000.0);
    writeln((xperf / 1000000):1:2, ' million ', ops, 'per second');
end;

const
    NINT = 10000;
    NFP = 1000;
    NSTR = 100;
    N = 1000000;

procedure testint(scale : integer);

var
    i, j, nintscale, sum : integer;
    t1, t2 : Cardinal;

begin
    nintscale := NINT div scale;
    t1 := GetTickCount;
    for i := 1 to nintscale do begin
        sum := i - 1;
        for j := 1 to N do begin
            sum := ((sum + 1) * 2 + 1) div 2;
        end;
        if sum <> (i - 1 + N) then begin
            writeln('Integer test error');
            halt;
        end;
    end;
    t2 := GetTickCount;
    printres(t1, t2, nintscale, N, 'integer operations');
end;

procedure testfp(scale : integer);

var
    i, j, nfpscale : integer;
    sum : double;
    t1, t2 : Cardinal;

begin
    nfpscale := NFP div scale;
    t1 := GetTickCount;
    for i := 1 to nfpscale do begin
        sum := i - 1;
        for j := 1 to N do begin
            sum := ((sum + 1) * 2 + 1) / 2;
        end;
        if abs(sum - (i - 1 + 1.5 * N)) > 1 then begin
            writeln('Floating point test error');
            halt;
        end;
    end;
    t2 := GetTickCount;
    printres(t1, t2, nfpscale, N, 'floating point operations');
end;

const
    ALFA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';

procedure teststr(scale : integer);

var
    i, j, nstrscale, ix, ix1, ix2 : integer;
    s, buf, temp : string;
    t1, t2 : Cardinal;

begin
    nstrscale := NSTR div scale;
    t1 := GetTickCount;
    for i := 1 to nstrscale do begin
        buf := '';
        SetLength(buf, N);
        for j := 1 to (N div 10) do begin
            s := ALFA + ALFA;
            ix := (i - 1 + 10 * (j - 1)) mod Length(ALFA);
            temp := Copy(s, ix + 1, 1) + Copy(s, ix + 2, 2) + Copy(s, ix + 4, 3) + Copy(s, ix + 7, 4);
            Move(temp[1], buf[10 * (j - 1) + 1], 10);
        end;
        ix1 := N div 3;
        ix2 := 2 * N div 3;
        if (Length(buf) <> N) or (buf[ix1] <> ALFA[(i - 2 + ix1) mod Length(ALFA) + 1]) or (buf[ix2] <> ALFA[(i - 2 + ix2) mod Length(ALFA) + 1]) then begin
            writeln('String test error');
            halt;
        end;
    end;
    t2 := GetTickCount;
    printres(t1, t2, nstrscale, N div 10, 'string operations');
end;

const
    REP = 10;

var
    i, scale : integer;

begin
    if paramCount > 0 then begin
        scale := StrToInt(paramStr(1));
    end else begin
        scale := 1;
    end;
    for i := 1 to REP do begin
        testint(scale);
    end;
    for i := 1 to REP do begin
        testfp(scale);
    end;
    for i := 1 to REP do begin
        teststr(scale);
    end;
end.

native_test.for:

      program native_test
      integer*4 REP
      parameter (REP = 10)
      integer*4 i, scale
      character*256 cmdlin
      integer*4 cmdlinlen
      if(iargc().gt.0) then
        call getarg(1, cmdlin)
        read(cmdlin,'(I4)') scale
      else
        scale = 1
      end if
      do 100 i =1,REP
        call testint(scale)
100   continue
      do 200 i =1,REP
        call testfp(scale)
200   continue
      do 300 i =1,REP
        call teststr(scale)
300   continue
      end
c
      subroutine testint(scale)
      integer*4 scale
      integer*4 NINT,N
      parameter (NINT = 10000, N = 1000000)
      integer*4 i, j, nintscale, sum
      integer*8 t1, t2
      nintscale = NINT / scale
      call system_clock(t1)
      do 200 i = 1, nintscale
        sum = i - 1
        do 100 j = 1, N
          sum = ((sum + 1) * 2 + 1) / 2
100     continue
        if(sum.ne.(i - 1 + N)) then
          write(*,*) 'Integer test error'
          stop
        end if
200   continue
      call system_clock(t2)
      call printres(t1, t2, nintscale, N, 'integer operations')
      end
c
      subroutine testfp(scale)
      integer*4 scale
      integer*4 NFP, N
      parameter (NFP = 1000, N = 1000000)
      integer*4 i, j, nfpscale
      real*8 sum
      integer*8 t1, t2
      nfpscale = NFP / scale
      call system_clock(t1)
      do 200 i = 1, nfpscale
        sum = i - 1
        do 100 j = 1, N
          sum = ((sum + 1) * 2 + 1) / 2
100     continue
        if(abs(sum - (i - 1 + 1.5 * N)).gt.1) then
          write(*,*) 'Floating point test error'
          stop
        end if
200   continue
      call system_clock(t2)
      call printres(t1, t2, nfpscale, N, 'floating point operations')
      end
c
      subroutine teststr(scale)
      integer*4 scale
      integer*4 NSTR, N
      character*26 ALFA
      parameter (NSTR = 100, N = 1000000,
     +           ALFA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
      integer*4 i, j, nstrscale, slen, ix, ix1, ix2, ix1m, ix2m
      character*52 s
      character*1000000 buf
      integer*8 t1, t2
      nstrscale = NSTR / scale
      call system_clock(t1)
      do 200 i = 1, nstrscale
        slen = 0
        do 100 j = 1, N, 10
          s = ALFA // ALFA
          ix = mod(i - 1 + j - 1, len(ALFA))
          buf(slen:slen+9) = s(ix + 1:ix + 1) // s(ix + 2:ix + 3) //
     +      s(ix + 4: ix + 6) // s(ix + 7:ix + 10)
          slen = slen + 10
100     continue
        ix1 = N / 3
        ix2 = 2 * N / 3
        ix1m = mod(i - 1 + ix1, len(ALFA)) + 1
        ix2m = mod(i - 1 + ix2, len(ALFA)) + 1
        if((slen.ne.N).or.
     +     (buf(ix1:ix1).ne.ALFA(ix1m:ix1m)).or.
     +     (buf(ix2:ix2).ne.ALFA(ix2m:ix2m))) then
          write(*,*) 'String test error'
          stop
        end if
200   continue
      call system_clock(t2)
      call printres(t1, t2, nstrscale, N / 10,
     +   'string operations')
      end
c
      subroutine printres(t1, t2, n1, n2, ops)
      integer*8 t1, t2
      integer*4 n1, n2
      character*(*) ops
      integer*8 dummy, t
      real*8 xperf
      call system_clock(dummy, t)
      xperf = n1 * 1.0 * n2 / ((t2 - t1) / (1.0 * t))
      write(*,'(1x,f8.2,9h million ,a,11h per second)')
     +  (xperf / 1000000), ops
      end

native_test.adb:

with Ada.Command_line,
     Ada.Task_Identification,
     Ada.Strings.Unbounded,
     Ada.Text_IO,
     Ada.Integer_Text_IO,
     Ada.Float_Text_IO,
     Ada.Real_Time;

use Ada.Command_line,
    Ada.Task_Identification,
    Ada.Strings.Unbounded,
    Ada.Text_IO,
    Ada.Integer_Text_IO,
    Ada.Float_Text_IO,
    Ada.Real_Time;

procedure Native_Test is

procedure Print_Res(t1, t2 : Time; n1, n2 : Integer; ops: String) is

xperf : Float;

begin
    xperf := Float(n1) * Float(n2) / Float(To_Duration(t2 - t1));
    Put(xperf / 1000000.0, Aft => 2, Exp => 0);
    Put(" million ");
    Put(ops);
    Put(" per second");
    New_Line;
end Print_Res;

NINT : constant Integer := 10000;
NFP : constant Integer := 1000;
NSTR : constant Integer := 100;
N : constant Integer := 1000000;

procedure Test_Int(scale : Integer) is

nintscale, sum : Integer;
t1, t2 : Time;

begin
    nintscale := NINT / scale;
    t1 := Clock;
    for i in 1..nintscale loop
        sum := i - 1;
        for j in 1..N loop
            sum := ((sum + 1) * 2 + 1) / 2;
        end loop;
        if sum /= (i - 1 + N) then
            Put_Line("Integer test error");
            Abort_Task (Current_Task);
        end if;
    end loop;
    t2 := Clock;
    Print_Res(t1, t2, nintscale, N, "integer operations");
end Test_Int;

procedure Test_FP(scale : Integer) is

nfpscale : Integer;
sum : Long_Float;
t1, t2 : Time;

begin
    nfpscale := NFP / scale;
    t1 := Clock;
    for i in 1..nfpscale loop
        sum := Long_Float(i - 1);
        for j in 1..N loop
            sum := ((sum + 1.0) * 2.0 + 1.0) / 2.0;
        end loop;
        if abs (sum - (Long_Float(i - 1) + 1.5 * Long_Float(N))) > 1.0 then
            Put_Line("Floating point test error");
            Abort_Task (Current_Task);
        end if;
    end loop;
    t2 := Clock;
    Print_Res(t1, t2, nfpscale, N, "floating point operations");
end Test_Fp;

procedure Test_Str(scale : Integer) is

ALFA : constant String := "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
s : constant String := ALFA & ALFA;
nstrscale, ix, ix1, ix2, ix1alfa, ix2alfa : Integer;
buf : Unbounded_String;
t1, t2 : Time;

begin
    nstrscale := NSTR / scale;
    t1 := Clock;
    for i in 1..nstrscale loop
        buf := To_Unbounded_String("");
        for j in 1..N /10 loop
            ix := (i - 1 + 10 * (j - 1)) mod ALFA'Length;
            Append(buf, s(ix+1..ix+1));
            Append(buf, s(ix+2..ix+3));
            Append(buf, s(ix+4..ix+6));
            Append(buf, s(ix+7..ix+10));
        end loop;
        ix1 := N / 3;
        ix2 := 2 * N / 3;
        ix1alfa := (i - 2 + ix1) mod ALFA'Length + 1;
        ix2alfa := (i - 2 + ix2) mod ALFA'Length + 1;
        if To_String(buf)'Length /= N or To_String(buf)(ix1..ix1) /= ALFA(ix1alfa..ix1alfa) or To_String(buf)(ix2..ix2) /= ALFA(ix2alfa..ix2alfa) then
            Put_Line("String test error");
            Abort_Task (Current_Task);
        end if;
    end loop;
    t2 := Clock;
    Print_Res(t1, t2, nstrscale, N/10, "string operations");
end Test_Str;

REP : constant Integer := 10;
scale : Integer;

begin
    if Argument_Count > 0 then
        scale := Integer'Value(Argument(1));
    else
        scale := 1;
    end if;
    for i in 1..REP loop
        Test_Int(scale);
    end loop;
    for i in 1..REP loop
        Test_FP(scale);
    end loop;
    for i in 1..REP loop
        Test_Str(scale);
    end loop;
end Native_Test;

script_test.py:

import sys
import time
import math

def printres(t1, t2, n1, n2, ops):
    xperf = n1 * n2 / (t2 - t1)
    print('%.2f million %s per second' % (xperf / 1000000, ops))

NINT = 10000
NFP = 10000
NSTR = 10000
N = 10000

def testint(scale):
    nintscale = NINT // scale
    t1 = time.time()
    for i in range(nintscale):
        sum = i
        for j in range(N):
            sum = ((sum + 1) * 2 + 1) // 2
        if sum != (i + N):
            print('Integer test error')
            sys.exit(0)
    t2 = time.time()
    printres(t1, t2, nintscale, N, 'integer operations')

def testfp(scale):
    nfpscale = NFP // scale
    t1 = time.time()
    for i in range(nfpscale):
        sum = i
        for j in range(N):
            sum = ((sum + 1.0) * 2 + 1) / 2
        if math.fabs(sum - (i + 1.5 * N)) > 1:
            print('Floating point test error')
            sys.exit(0)
    t2 = time.time()
    printres(t1, t2, nfpscale, N, 'floating point operations')

ALFA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

def teststr(scale):
    nstrscale = NSTR // scale
    t1 = time.time()
    for i in range(nstrscale):
        sb = ''
        for j in range(N // 10):
            realj = 10 * j
            s = ALFA + ALFA
            ix = (i + j) % len(ALFA)
            sb = sb + s[ix:ix+1] + s[ix+1:ix+3] + s[ix+3:ix+6] + s[ix+6:ix+10]
        ix1 = N // 3
        ix2 = 2 * N // 3
        mix1 = (i + ix1) % len(ALFA)
        mix2 = (i + ix2) % len(ALFA)
        if len(sb) != N or sb[ix1:ix1] != ALFA[mix1:mix1] or sb[ix2:ix2] != ALFA[mix2:mix2]:
            print('String test error')
            sys.exit(0)
    t2 = time.time()
    printres(t1, t2, nstrscale, N // 10, 'string operations')

REP = 10

print(sys.version)
if len(sys.argv) > 1:
    scale = int(sys.argv[1])
else:
    scale = 1
for i in range(REP):
    testint(scale)
for i in range(REP):
    testfp(scale)
for i in range(REP):
    teststr(scale)

script_test_cython.pyx:

import sys
import time
import math

cdef printres(int t1, int t2, int n1, int n2, ops):
    cdef double xperf
    xperf = n1 * 1.0 * n2 / (t2 - t1)
    print('%.2f million %s per second' % (xperf / 1000000, ops))

cdef int NINT = 1000000
cdef int NFP = 1000000
cdef int NSTR = 10000
cdef int N = 10000

cdef testint(int scale):
    cdef int nintscale, sum, i, j
    nintscale = NINT // scale
    t1 = time.time()
    for i in range(nintscale):
        sum = i
        for j in range(N):
            sum = ((sum + 1) * 2 + 1) // 2
        if sum != (i + N):
            print('Integer test error')
            sys.exit(0)
    t2 = time.time()
    printres(t1, t2, nintscale, N, 'integer operations')

cdef testfp(scale):
    cdef int nfpscale, i, j
    cdef double sum
    nfpscale = NFP // scale
    t1 = time.time()
    for i in range(nfpscale):
        sum = i
        for j in range(N):
            sum = ((sum + 1.0) * 2 + 1) / 2
        if math.fabs(sum - (i + 1.5 * N)) > 1:
            print('Floating point test error')
            sys.exit(0)
    t2 = time.time()
    printres(t1, t2, nfpscale, N, 'floating point operations')

ALFA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

cdef teststr(scale):
    cdef int nstrscale, i, j, realj, ix, ix1, ix2
    nstrscale = NSTR // scale
    t1 = time.time()
    for i in range(nstrscale):
        sb = ''
        for j in range(N // 10):
            realj = 10 * j
            s = ALFA + ALFA
            ix = (i + j) % len(ALFA)
            sb = sb + s[ix:ix+1] + s[ix+1:ix+3] + s[ix+3:ix+6] + s[ix+6:ix+10]
        ix1 = N // 3
        ix2 = 2 * N // 3
        mix1 = (i + ix1) % len(ALFA)
        mix2 = (i + ix2) % len(ALFA)
        if len(sb) != N or sb[ix1:ix1] != ALFA[mix1:mix1] or sb[ix2:ix2] != ALFA[mix2:mix2]:
            print('String test error')
            sys.exit(0)
    t2 = time.time()
    printres(t1, t2, nstrscale, N // 10, 'string operations')

REP = 10

print(sys.version + ' with cdef')
if len(sys.argv) > 1:
    scale = int(sys.argv[1])
else:
    scale = 1
for i in range(REP):
    testint(scale)
for i in range(REP):
    testfp(scale)
for i in range(REP):
    teststr(scale)

script_test_codon.py:

import sys
import time
import math

def printres(t1, t2, n1, n2, ops):
    xperf = n1 * n2 / (t2 - t1)
    print(f'{xperf / 1000000} million {ops} per second')

NINT = 10000
NFP = 10000
NSTR = 100
N = 10000

def testint(scale):
    nintscale = NINT // scale
    t1 = time.time()
    for i in range(nintscale):
        sum = i
        for j in range(N):
            sum = ((sum + 1) * 2 + 1) // 2
        if sum != (i + N):
            print('Integer test error')
            sys.exit(0)
    t2 = time.time()
    printres(t1, t2, nintscale, N, 'integer operations')

def testfp(scale):
    nfpscale = NFP // scale
    t1 = time.time()
    for i in range(nfpscale):
        sum = i + 0.0
        for j in range(N):
            sum = ((sum + 1.0) * 2 + 1) / 2
        if math.fabs(sum - (i + 1.5 * N)) > 1:
            print('Floating point test error')
            sys.exit(0)
    t2 = time.time()
    printres(t1, t2, nfpscale, N, 'floating point operations')

ALFA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

def teststr(scale):
    nstrscale = NSTR // scale
    t1 = time.time()
    for i in range(nstrscale):
        sb = ''
        for j in range(N // 10):
            realj = 10 * j
            s = ALFA + ALFA
            ix = (i + j) % len(ALFA)
            sb = sb + s[ix:ix+1] + s[ix+1:ix+3] + s[ix+3:ix+6] + s[ix+6:ix+10]
        ix1 = N // 3
        ix2 = 2 * N // 3
        mix1 = (i + ix1) % len(ALFA)
        mix2 = (i + ix2) % len(ALFA)
        if len(sb) != N or sb[ix1:ix1] != ALFA[mix1:mix1] or sb[ix2:ix2] != ALFA[mix2:mix2]:
            print('String test error')
            sys.exit(0)
    t2 = time.time()
    printres(t1, t2, nstrscale, N // 10, 'string operations')

REP = 10

if len(sys.argv) > 1:
    scale = int(sys.argv[1])
else:
    scale = 1
for i in range(REP):
    testint(scale)
for i in range(REP):
    testfp(scale)
for i in range(REP):
    teststr(scale)

script_test.groovy:

import java.text.DecimalFormat

nf = new DecimalFormat("0.00")

void printres(long t1, long t2, int n1, int n2, String ops) {
    xperf = n1 * n2 / ((t2 - t1) / 1000.0) 
    sperf = nf.format(xperf / 1000000)
    println("${sperf} million ${ops} per second")
}
    
NINT = 10000
NFP = 10000
NSTR = 10000
N = 10000
    
void testint(int scale) {
    nintscale = NINT.intdiv(scale)
    t1 = System.currentTimeMillis()
    for(i = 0; i < nintscale; i++) {
        int sum = i
        for(j = 0; j < N; j++) {
            sum = ((sum + 1) * 2 + 1).intdiv(2)
        }
        if(sum != (i + N)) {
            println("Integer test error")
            System.exit(1)
        }
    }
    t2 = System.currentTimeMillis()
    printres(t1, t2, nintscale, N, "integer operations")
}

void testfp(int scale) {
    nfpscale = NFP.intdiv(scale)
    t1 = System.currentTimeMillis()
    for(i = 0; i < nfpscale; i++) {
        double sum = i
        for(j = 0; j < N; j++) {
            sum = ((sum + 1) * 2 + 1) / 2
        }
        if(Math.abs(sum - (i + 1.5 * N)) > 1) {
            println("Floating point test error")
            System.exit(1)
        }
    }
    t2 = System.currentTimeMillis()
    printres(t1, t2, nfpscale, N, "floating point operations")
}

ALFA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

void teststr(int scale) {
    nstrscale = NSTR.intdiv(scale)
    t1 = System.currentTimeMillis()
    for(i = 0; i < nstrscale; i++) {
        sb = new StringBuffer("")
        for(j = 0; j < N; j = j + 10) {
            s = ALFA + ALFA
            ix = (i + j) % ALFA.length()
            sb << (s[ix .. ix] + s[ix + 1 .. ix + 2] + s[ix + 3 .. ix + 5] + s[ix + 6 .. ix + 9])
        }
        ix1 = N.intdiv(3)
        ix2 = (2 * N).intdiv(3) 
        if(sb.length() != N || sb[ix1] != ALFA[(i + ix1) % ALFA.length()] || sb[ix2] != ALFA[(i + ix2) % ALFA.length()]) {
            println("String test error")
            System.exit(1)
        }
    }
    t2 = System.currentTimeMillis()
    printres(t1, t2, nstrscale, N.intdiv(10), "string operations")
}

REP = 10

println("${GroovySystem.version} / ${System.getProperty("java.vm.vendor")} ${System.getProperty("java.vm.name")} ${System.getProperty("java.vm.version")}")
int scale = 1
if(args.length > 0) {
    scale = Integer.parseInt(args[0])
}
for(i in 1..REP) {
    testint(scale)
}
for(i in 1..REP) {
    testfp(scale)
}
for(i in 1..REP) {
    teststr(scale)
}

script_test_static.groovy:

import java.text.DecimalFormat
import java.text.NumberFormat

import groovy.transform.*

@CompileStatic
void printres(long t1, long t2, int n1, int n2, String ops) {
    NumberFormat nf = new DecimalFormat("0.00")
    double xperf = n1 * n2 / ((t2 - t1) / 1000.0) 
    String sperf = nf.format(xperf / 1000000)
    println("${sperf} million ${ops} per second")
}
    
@CompileStatic
void testint(int scale) {
    int NINT = 10000
    int N = 10000
    int nintscale = NINT.intdiv(scale)
    long t1 = System.currentTimeMillis()
    for(int i = 0; i < nintscale; i++) {
        int sum = i
        for(int j = 0; j < N; j++) {
            sum = ((sum + 1) * 2 + 1).intdiv(2)
        }
        if(sum != (i + N)) {
            println("Integer test error")
            System.exit(1)
        }
    }
    long t2 = System.currentTimeMillis()
    printres(t1, t2, nintscale, N, "integer operations")
}

@CompileStatic
void testfp(int scale) {
    int NFP = 10000
    int N = 10000
    int nfpscale = NFP.intdiv(scale)
    long t1 = System.currentTimeMillis()
    for(int i = 0; i < nfpscale; i++) {
        double sum = i
        for(int j = 0; j < N; j++) {
            sum = ((sum + 1) * 2 + 1) / 2
        }
        if(Math.abs(sum - (i + 1.5d * N)) > 1) {
            println("Floating point test error")
            System.exit(1)
        }
    }
    long t2 = System.currentTimeMillis()
    printres(t1, t2, nfpscale, N, "floating point operations")
}

@CompileStatic
void teststr(int scale) {
    int NSTR = 10000
    int N = 10000
    String ALFA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    int nstrscale = NSTR.intdiv(scale)
    long t1 = System.currentTimeMillis()
    for(int i = 0; i < nstrscale; i++) {
        StringBuffer sb = new StringBuffer("")
        for(int j = 0; j < N; j = j + 10) {
            String s = ALFA + ALFA
            int ix = (i + j) % ALFA.length()
            sb << (s[ix .. ix] + s[ix + 1 .. ix + 2] + s[ix + 3 .. ix + 5] + s[ix + 6 .. ix + 9])
        }
        int ix1 = N.intdiv(3)
        int ix2 = (2 * N).intdiv(3) 
        if(sb.length() != N || sb[ix1] != ALFA[(i + ix1) % ALFA.length()] || sb[ix2] != ALFA[(i + ix2) % ALFA.length()]) {
            println("String test error")
            System.exit(1)
        }
    }
    long t2 = System.currentTimeMillis()
    printres(t1, t2, nstrscale, N.intdiv(10), "string operations")
}

REP = 10

println("${GroovySystem.version} (static) / ${System.getProperty("java.vm.vendor")} ${System.getProperty("java.vm.name")} ${System.getProperty("java.vm.version")}")
int scale = 1
if(args.length > 0) {
    scale = Integer.parseInt(args[0])
}
for(i in 1..REP) {
    testint(scale)
}
for(i in 1..REP) {
    testfp(scale)
}
for(i in 1..REP) {
    teststr(scale)
}

script_test.php:

<?php

function printres($t1, $t2, $n1, $n2, $ops) {
    $xperf = $n1 * 1.0 * $n2 / ($t2 - $t1);
    echo sprintf("%.2f million %s per second\r\n", $xperf / 1000000, $ops);
}

define('NINT', 10000);
define('NFP', 10000);
define('NSTR', 10000);
define('N', 10000);

function testint($scale) {
    $nintscale = NINT / $scale;
    $t1 = microtime(true);
    for($i = 0; $i < $nintscale; $i++) {
        $sum = $i;
        for($j = 0; $j < N; $j++) {
            $sum = (int)((($sum + 1) * 2 + 1) / 2);
        }
        if($sum != ($i + N)) {
            die('Integer test error');
        }
    }
    $t2 = microtime(true);
    printres($t1, $t2, $nintscale, N, 'integer operations');
}

function testfp($scale) {
    $nfpscale = NFP / $scale;
    $t1 = microtime(true);
    for($i = 0; $i < $nfpscale; $i++) {
        $sum = $i;
        for($j = 0; $j < N; $j++) {
            $sum = (($sum + 1.0) * 2.0 + 1.0) / 2.0;
        }
        if(abs($sum - ($i + 1.5 * N)) > 1) {
            die('Floating point test error');
        }
    }
    $t2 = microtime(true);
    printres($t1, $t2, $nfpscale, N, 'floating point operations');
}

define('ALFA', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');

function teststr($scale) {
    $nstrscale = NSTR / $scale;
    $t1 = microtime(true);
    for($i = 0; $i < $nstrscale; $i++) {
        $buf = '';
        for($j = 0; $j < N; $j = $j + 10) {
            $s = ALFA . ALFA;
            $ix = ($i + $j) % strlen(ALFA);
            $buf = $buf . substr($s, $ix, 1) . substr($s, $ix + 1, 2) . substr($s, $ix + 3, 3) . substr($s, $ix + 6, 4);
        }
        $ix1 = (int)(N / 3);
        $ix2 = (int)(2 * N / 3);
        if(strlen($buf) != N || $buf[$ix1] != ALFA[($i + $ix1) % strlen(ALFA)] || $buf[$ix2] != ALFA[($i + $ix2) % strlen(ALFA)]) {
            die('String test error');
        }
    }
    $t2 = microtime(true);
    printres($t1, $t2, $nstrscale, N / 10, 'string operations');
}

define('REP', 10);

echo sprintf("PHP %s (%d bit)\r\n", phpversion(), PHP_INT_SIZE * 8);
if($argc > 1) {
    $scale = (int)$argv[1];
} else {
    $scale = 1;
}
for($i = 0; $i < REP; $i++) {
    testint($scale);
}
for($i = 0; $i < REP; $i++) {
    testfp($scale);
}
for($i = 0; $i < REP; $i++) {
    teststr($scale);
}
?>

Results:

JVM and Java:

Language Compiler/Runtime Integer performance Floating point performance String performance Total performance
Java IBM 1.7.0 64 bit 668 209 19.55 139.75
Java IBM 1.7.0 32 bit 667 209 18.91 138.14
Java IBM 1.6.0 32 bit 695 208 15.87 131.89
Java SUN 21.0 Server 64 bit 551 238 13.11 119.80
Java IBM 1.8.0 32 bit 667 209 11.55 117.21
Java IBM 1.8.0 64 bit 666 209 11.49 116.94
Java SUN 17.0 Server 64 bit 548 209 13.50 115.63
Java SUN 11.0 Server 64 bit 473 209 13.19 109.25
Java OJDK 11.0 Hotspot 64 bit 473 209 13.05 108.86
Java BEA 1.6.0 64 bit 417 238 10.61 101.74
Java SUN 1.6.0 Server 64 bit 473 209 9.57 98.17
Java SUN 1.6.0 Server 32 bit 468 209 9.58 97.86
Java SUN 1.7.0 Server 32 bit 468 209 9.51 97.62
Java BEA 1.6.0 32 bit 417 238 9.29 97.33
Java SUN 1.8.0 Server 64 bit 473 209 9.25 97.06
Java OJDK 1.8.0 Hotspot 64 bit 473 209 9.03 96.29
Java SUN 1.8.0 Server 32 bit 469 209 9.04 96.05
Java SUN 1.5.0 Server 64 bit 551 209 7.58 95.57
Java SUN 1.7.0 Server 64 bit 473 209 8.77 95.35
Java SUN 11.0 Graal 64 bit 417 185 10.67 93.72
Java SUN 1.5.0 Server 32 bit 550 209 6.85 92.34
Java IBM 8 OpenJ9 64 bit 667 208 4.74 86.96
Java OJDK 1.8.0 OpenJ9 64 bit 663 209 3.96 81.87
Java IBM 11 OpenJ9 64 bit 668 208 3.68 79.96
Java OJDK 11.0 OpenJ9 64 bit 667 209 3.56 79.17
Java SUN 1.4.2 Server 32 bit 550 209 3.49 73.75
Java IBM 17 OpenJ9 64 bit 668 208 2.16 66.95
Java SUN 1.3.1 Server 32 bit 635 119 3.64 65.03
Java GraalVM 22.3 native 64 bit 417 185 2.48 57.62
Java SUN 1.5.0 Client 32 bit 371 133 3.03 53.07
Java Apache 1.6.0 32 bit 371 177 2.24 52.79
Java SUN 1.4.2 Client 32 bit 371 133 2.16 47.41
Java SUN 1.6.0 Client 32 bit 112 185 4.37 44.90
Java SUN 1.8.0 Client 32 bit 111 185 4.32 44.60
Java SUN 1.7.0 Client 32 bit 112 185 4.00 43.60
Java SUN 1.3.1 Client 32 bit 109 133 3.31 36.34

We see that:

The first three conclusions are as expected.

.NET CLR and C#:

Language Compiler/Runtime Integer performance Floating point performance String performance Total performance
C# .NET 2.0 /o+ 32 bit 1665 185 6.41 125.45
C# .NET 4.0 /o+ 32 bit 1669 185 5.43 118.80
C# .NET 2.0 32 bit 1112 185 6.41 109.66
C# .NET 8.0 64 bit 660 206 9.32 108.21
C# .NET 6.0 64 bit 667 208 9.09 108.04
C# .NET 5.0 64 bit 668 209 8.22 104.70
C# .NET 4.0 32 bit 1112 185 5.51 104.27
C# .NET 6.0 32 bit 667 208 7.87 102.97
C# Core 3.1 64 bit 668 185 7.81 98.82
C# .NET 2.0 /o+ 64 bit 786 186 5.93 95.35
C# .NET 5.0 32 bit 665 209 6.05 94.39
C# .NET 4.0 /o+ 64 bit 556 185 8.01 93.75
C# .NET 4.0 64 bit 555 185 7.91 93.30
C# .NET 7.0 64 bit 660 144 8.09 91.61
C# Core 3.1 32 bit 668 185 6.05 90.76
C# .NET 2.0 64 bit 668 167 5.93 87.13
C# Mono 4.0 32 bit 417 134 4.24 61.88
C# Mono 4.0 -optimize+ 32 bit 417 134 4.22 61.78

We see that:

Native (C, Pascal, Fortran, Ada):

Language Compiler/Runtime Integer performance Floating point performance String performance Total performance
C GCC 11.1 -O3 -funroll-loops 32 bit 13354 236 25.71 432.72
Fortran GCC 11.1 -O3 -funroll-loops 64 bit 13334 238 25.29 431.35
C GCC 11.1 -O3 -funroll-loops 64 bit 13358 239 23.10 419.36
Fortran GCC 11.1 -O3 -funroll-loops 32 bit 13332 236 15.28 363.62
C++ GCC 11.1 -O3 -funroll-loops 64 bit 13351 238 6.10 268.62
C++ GCC 11.1 -O3 -funroll-loops 32 bit 13349 236 3.84 229.56
Fortran GCC 11.1 -O3 64 bit 1666 238 25.55 216.38
C GCC 11.1 -O3 32 bit 1670 223 25.73 212.40
C GCC 11.1 -O3 64 bit 1670 239 23.31 210.32
Fortran GCC 11.1 -O3 32 bit 1667 222 15.91 180.57
C GCC 13.1 -O3 -funroll-loops 64 bit 668 239 25.25 159.15
C GCC 13.1-O3 64 bit 668 239 22.52 153.20
C MSVC++ VS19 /O2 64 bit 1055 239 13.76 151.39
C++ MSVC++ VS19 /O2 64 bit 1047 238 11.56 142.29
C MSVC++ VS19 /O2 32 bit 835 239 13.93 140.61
C MSVC++ VS12 /O2 64 bit 833 209 15.75 139.97
C LLVM 16.0 -O3 64 bit 557 239 19.89 138.34
C LLVM 12.0 -O3 64 bit 557 239 19.54 137.53
C++ GCC 11.1 -O3 64 bit 1669 238 6.08 134.17
C MSVC++ VS12 /O2 32 bit 835 209 13.62 133.46
C++ GCC 11.1 -O3 32 bit 1662 223 4.09 114.87
C++ MSVC++ VS19 /O2 32 bit 835 238 6.95 111.37
C++ GCC 13.1 -O3 -funroll-loops 64 bit 668 239 8.34 110.01
C++ GCC 13.1 -O3 64 bit 668 239 8.28 109.75
C++ LLVM 16.0 -O3 64 bit 557 239 8.28 103.30
Fortran GCC 11.1 64 bit 278 139 24.63 98.37
Ada Gnat 2017 -gnatp -O3 64 bit 554 238 5.74 91.13
Ada Gnat 2017 -O3 64 bit 505 238 5.73 88.31
C GCC 13.1 64 bit 278 139 17.19 87.25
C GCC 11.1 32 bit 277 139 16.46 85.90
C MSVC++ VS12 64 bit 371 134 12.70 85.79
C MSVC++ VS19 64 bit 371 134 12.70 85.79
C GCC 11.1 64 bit 278 139 16.31 85.74
C MSVC++ VS19 32 bit 371 134 12.20 84.65
C MSVC++ VS12 32 bit 371 133 12.16 84.34
Fortran GCC 11.1 32 bit 278 139 14.30 82.06
C++ GCC 13.1 64 bit 278 139 6.05 61.60
C++ GCC 11.1 64 bit 278 139 5.73 60.50
Ada Gnat 2017 -gnatp 64 bit 276 138 5.44 59.17
Pascal FPC 3.2 -O4 64 bit 417 186 2.41 57.18
C LLVM 16.0 64 bit 103 145 12.18 56.66
Ada Gnat 2017 64 bit 256 138 5.10 56.48
C LLVM 12.0 64 bit 103 134 12.35 55.45
C++ GCC 11.1 32 bit 278 139 3.64 52.01
C++ MSVC++ VS19 64 bit 371 134 2.55 50.23
Pascal Delphi 7 32 bit 834 134 1.12 50.02
Pascal FPC 3.2 64 bit 278 145 2.40 45.91
C++ LLVM 16.0 64 bit 103 145 6.28 45.43
C++ MSVC++ VS19 32 bit 371 133 1.77 44.37
Pascal Delphi 7 -$O- 32 bit 370 134 1.12 38.15

We see that:

GCC -funroll-loops has a huge impact on the integer test, but as mentioned in disclaimer such an improvement should not be expected for a real application.

Script (Python, PHP):

Language Compiler/Runtime Integer performance Floating point performance String performance Total performance
Groovy Groovy 4.0 / Oracle Java 17 64 bit @CompileStatic 535 207 3.04 69.57
Python PyPy 7.3 (Python 2.7) 64 bit 402 207 2.46 58.94
Python PyPy 7.3 (Python 3.7) 64 bit 401 207 2.31 57.66
Groovy Groovy 2.5 / Oracle Java 8 64 bit @CompileStatic 160 207 2.86 45.58
Groovy Groovy 3.0 / Oracle Java 11 64 bit @CompileStatic 145 207 3.14 45.51
Python GraalPython 3.8 / Graal Java 11 64 bit 243 172 1.46 39.37
Python codon 0.16.3 run -release 824 236 0.28 37.90
Python Cython 3.0 (Python 3.6) pyx cdef 256 238 0.67 34.43
Python GraalPython 3.10 / Graal Java 21 64 bit 291 183 0.29 24.90
PHP HHVM 3.30 33 44 2.22 14.81
Python codon 0.16.3 run 366 72 0.07 12.26
PHP PHP 7.2 GCC 64 bit 17 25 1.83 9.31
PHP PHP 8.3 FrankenPHP 1.0.0 64 bit 19 29 1.36 9.08
PHP PHP 7.4 GCC 64 bit 22 34 0.67 7.91
PHP PHP 8.0 MSVC++ 64 bit 13 18 1.34 6.70
PHP PHP 8.2 MSVC++ 64 bit 11 14 1.30 5.76
Groovy Groovy 4.0 / Oracle Java 17 64 bit 13 15 0.86 5.53
PHP PHP 8.0 MSVC++ 32 bit 9 13 1.24 5.39
PHP PHP 8.2 MSVC++ 32 bit 10 13 1.20 5.37
PHP PHP 7.4 MSVC++ 64 bit 9 13 1.39 5.37
Python Cython 3.0 (Python 3.6) 10 22 0.61 5.07
PHP PHP 7.2 MSVC++ 32 bit 9 12 1.11 4.85
Groovy Groovy 2.5 / Oracle Java 8 64 bit 10 10 1.04 4.63
PHP PeachPie 1.0 / .NET 6 64 bit 8 14 0.87 4.56
PHP PHP 7.4 MSVC++ 32 bit 8 9 1.19 4.39
PHP PeachPie 1.0 / .NET 5 64 bit 7 15 0.80 4.40
Groovy Groovy 3.0 / Oracle Java 11 64 bit 8 8 0.99 4.08
Python Jython 2.7 / SUN Java 11 64 bit 13 13 0.32 3.78
Python CPython 3.6 GCC 64 bit 6 8 0.76 3.30
PHP PHP 5.6 MSVC++ 32 bit 8 10 0.39 3.13
PHP Quercus 4.0 free / SUN JDK 11 64 bit 6 6 0.61 2.79
Python CPython 3.8 GCC 64 bit 7 7 0.41 2.78
Python CPython 2.7 MSVC++ 64 bit 8 6 0.42 2.72
Python IronPython 2.7 / .NET 4 64 bit 8 11 0.18 2.49
Python CPython 3.6 MSVC++ 64 bit 5 5 0.44 2.22
Python IronPython 2.7 / .NET 4 32 bit 9 7 0.16 2.18

We see that:

The second one should not surprise anyone.

All:

Language Compiler/Runtime Integer performance Floating point performance String performance Total performance
C GCC 11.1 -O3 -funroll-loops 32 bit 13354 236 25.71 432.72
Fortran GCC 11.1 -O3 -funroll-loops 64 bit 13334 238 25.29 431.35
C GCC 11.1 -O3 -funroll-loops 64 bit 13358 239 23.10 419.36
Fortran GCC 11.1 -O3 -funroll-loops 32 bit 13332 236 15.28 363.62
C++ GCC 11.1 -O3 -funroll-loops 64 bit 13351 238 6.10 268.62
C++ GCC 11.1 -O3 -funroll-loops 32 bit 13349 236 3.84 229.56
Fortran GCC 11.1 -O3 64 bit 1666 238 25.55 216.38
C GCC 11.1 -O3 32 bit 1670 223 25.73 212.40
C GCC 11.1 -O3 64 bit 1670 239 23.31 210.32
Fortran GCC 11.1 -O3 32 bit 1667 222 15.91 180.57
C GCC 13.1 -O3 -funroll-loops 64 bit 668 239 25.25 159.15
C GCC 13.1-O3 64 bit 668 239 22.52 153.20
C MSVC++ VS19 /O2 64 bit 1055 239 13.76 151.39
C++ MSVC++ VS19 /O2 64 bit 1047 238 11.56 142.29
C MSVC++ VS19 /O2 32 bit 835 239 13.93 140.61
C MSVC++ VS12 /O2 64 bit 833 209 15.75 139.97
Java IBM 1.7.0 64 bit 668 209 19.55 139.75
C LLVM 16.0 -O3 64 bit 557 239 19.89 138.34
Java IBM 1.7.0 32 bit 667 209 18.91 138.14
C LLVM 12.0 -O3 64 bit 557 239 19.54 137.53
C++ GCC 11.1 -O3 64 bit 1669 238 6.08 134.17
C MSVC++ VS12 /O2 32 bit 835 209 13.62 133.46
Java IBM 1.6.0 32 bit 695 208 15.87 131.89
C# .NET 2.0 /o+ 32 bit 1665 185 6.41 125.45
Java SUN 21.0 Server 64 bit 551 238 13.11 119.80
C# .NET 4.0 /o+ 32 bit 1669 185 5.43 118.80
Java IBM 1.8.0 32 bit 667 209 11.55 117.21
Java IBM 1.8.0 64 bit 666 209 11.49 116.94
Java SUN 17.0 Server 64 bit 548 209 13.50 115.63
C++ GCC 11.1 -O3 32 bit 1662 223 4.09 114.87
C++ MSVC++ VS19 /O2 32 bit 835 238 6.95 111.37
C++ GCC 13.1 -O3 -funroll-loops 64 bit 668 239 8.34 110.01
C++ GCC 13.1 -O3 64 bit 668 239 8.28 109.75
C# .NET 2.0 32 bit 1112 185 6.41 109.66
Java SUN 11.0 Server 64 bit 473 209 13.19 109.25
Java OJDK 11.0 Hotspot 64 bit 473 209 13.05 108.86
C# .NET 8.0 64 bit 660 206 9.32 108.21
C# .NET 6.0 64 bit 667 208 9.09 108.04
C# .NET 5.0 64 bit 668 209 8.22 104.70
C# .NET 4.0 32 bit 1112 185 5.51 104.27
C++ LLVM 16.0 -O3 64 bit 557 239 8.28 103.30
C# .NET 6.0 32 bit 667 208 7.87 102.97
Java BEA 1.6.0 64 bit 417 238 10.61 101.74
C# Core 3.1 64 bit 668 185 7.81 98.82
Fortran GCC 11.1 64 bit 278 139 24.63 98.37
Java SUN 1.6.0 Server 64 bit 473 209 9.57 98.17
Java SUN 1.6.0 Server 32 bit 468 209 9.58 97.86
Java SUN 1.7.0 Server 32 bit 468 209 9.51 97.62
Java BEA 1.6.0 32 bit 417 238 9.29 97.33
Java SUN 1.8.0 Server 64 bit 473 209 9.25 97.06
Java OJDK 1.8.0 Hotspot 64 bit 473 209 9.03 96.29
Java SUN 1.8.0 Server 32 bit 469 209 9.04 96.05
Java SUN 1.5.0 Server 64 bit 551 209 7.58 95.57
Java SUN 1.7.0 Server 64 bit 473 209 8.77 95.35
C# .NET 2.0 /o+ 64 bit 786 186 5.93 95.35
C# .NET 5.0 32 bit 665 209 6.05 94.39
C# .NET 4.0 /o+ 64 bit 556 185 8.01 93.75
Java SUN 11.0 Graal 64 bit 417 185 10.67 93.72
C# .NET 4.0 64 bit 555 185 7.91 93.30
Java SUN 1.5.0 Server 32 bit 550 209 6.85 92.34
C# .NET 7.0 64 bit 660 144 8.09 91.61
Ada Gnat 2017 -gnatp -O3 64 bit 554 238 5.74 91.13
C# Core 3.1 32 bit 668 185 6.05 90.76
Ada Gnat 2017 -O3 64 bit 505 238 5.73 88.31
C GCC 13.1 64 bit 278 139 17.19 87.25
C# .NET 2.0 64 bit 668 167 5.93 87.13
Java IBM 8 OpenJ9 64 bit 667 208 4.74 86.96
C GCC 11.1 32 bit 277 139 16.46 85.90
C MSVC++ VS12 64 bit 371 134 12.70 85.79
C MSVC++ VS19 64 bit 371 134 12.70 85.79
C GCC 11.1 64 bit 278 139 16.31 85.74
C MSVC++ VS19 32 bit 371 134 12.20 84.65
C MSVC++ VS12 32 bit 371 133 12.16 84.34
Fortran GCC 11.1 32 bit 278 139 14.30 82.06
Java OJDK 1.8.0 OpenJ9 64 bit 663 209 3.96 81.87
Java IBM 11 OpenJ9 64 bit 668 208 3.68 79.96
Java OJDK 11.0 OpenJ9 64 bit 667 209 3.56 79.17
Java SUN 1.4.2 Server 32 bit 550 209 3.49 73.75
Groovy Groovy 4.0 / Oracle Java 17 64 bit @CompileStatic 535 207 3.04 69.57
Java IBM 17 OpenJ9 64 bit 668 208 2.16 66.95
Java SUN 1.3.1 Server 32 bit 635 119 3.64 65.03
C# Mono 4.0 32 bit 417 134 4.24 61.88
C# Mono 4.0 -optimize+ 32 bit 417 134 4.22 61.78
C++ GCC 13.1 64 bit 278 139 6.05 61.60
C++ GCC 11.1 64 bit 278 139 5.73 60.50
Ada Gnat 2017 -gnatp 64 bit 276 138 5.44 59.17
Python PyPy 7.3 (Python 2.7) 64 bit 402 207 2.46 58.94
Python PyPy 7.3 (Python 3.7) 64 bit 401 207 2.31 57.66
Java GraalVM 22.3 native 64 bit 417 185 2.48 57.62
Pascal FPC 3.2 -O4 64 bit 417 186 2.41 57.18
C LLVM 16.0 64 bit 103 145 12.18 56.66
Ada Gnat 2017 64 bit 256 138 5.10 56.48
C LLVM 12.0 64 bit 103 134 12.35 55.45
Java SUN 1.5.0 Client 32 bit 371 133 3.03 53.07
Java Apache 1.6.0 32 bit 371 177 2.24 52.79
C++ GCC 11.1 32 bit 278 139 3.64 52.01
C++ MSVC++ VS19 64 bit 371 134 2.55 50.23
Pascal Delphi 7 32 bit 834 134 1.12 50.02
Java SUN 1.4.2 Client 32 bit 371 133 2.16 47.41
Pascal FPC 3.2 64 bit 278 145 2.40 45.91
Groovy Groovy 2.5 / Oracle Java 8 64 bit @CompileStatic 160 207 2.86 45.58
Groovy Groovy 3.0 / Oracle Java 11 64 bit @CompileStatic 145 207 3.14 45.51
C++ LLVM 16.0 64 bit 103 145 6.28 45.43
Java SUN 1.6.0 Client 32 bit 112 185 4.37 44.90
Java SUN 1.8.0 Client 32 bit 111 185 4.32 44.60
C++ MSVC++ VS19 32 bit 371 133 1.77 44.37
Java SUN 1.7.0 Client 32 bit 112 185 4.00 43.60
Python GraalPython 3.8 / Graal Java 11 64 bit 243 172 1.46 39.37
Pascal Delphi 7 -$O- 32 bit 370 134 1.12 38.15
Python codon 0.16.3 run -release 824 236 0.28 37.90
Java SUN 1.3.1 Client 32 bit 109 133 3.31 36.34
Python Cython 3.0 (Python 3.6) pyx cdef 256 238 0.67 34.43
Python GraalPython 3.10 / Graal Java 21 64 bit 291 183 0.29 24.90
PHP HHVM 3.30 33 44 2.22 14.81
Python codon 0.16.3 run 366 72 0.07 12.26
PHP PHP 7.2 GCC 64 bit 17 25 1.83 9.31
PHP PHP 8.3 FrankenPHP 1.0.0 64 bit 19 29 1.36 9.08
PHP PHP 7.4 GCC 64 bit 22 34 0.67 7.91
PHP PHP 8.0 MSVC++ 64 bit 13 18 1.34 6.70
PHP PHP 8.2 MSVC++ 64 bit 11 14 1.30 5.76
Groovy Groovy 4.0 / Oracle Java 17 64 bit 13 15 0.86 5.53
PHP PHP 8.0 MSVC++ 32 bit 9 13 1.24 5.39
PHP PHP 8.2 MSVC++ 32 bit 10 13 1.20 5.37
PHP PHP 7.4 MSVC++ 64 bit 9 13 1.39 5.37
Python Cython 3.0 (Python 3.6) 10 22 0.61 5.07
PHP PHP 7.2 MSVC++ 32 bit 9 12 1.11 4.85
Groovy Groovy 2.5 / Oracle Java 8 64 bit 10 10 1.04 4.63
PHP PeachPie 1.0 / .NET 6 64 bit 8 14 0.87 4.56
PHP PHP 7.4 MSVC++ 32 bit 8 9 1.19 4.39
PHP PeachPie 1.0 / .NET 5 64 bit 7 15 0.80 4.40
Groovy Groovy 3.0 / Oracle Java 11 64 bit 8 8 0.99 4.08
Python Jython 2.7 / SUN Java 11 64 bit 13 13 0.32 3.78
Python CPython 3.6 GCC 64 bit 6 8 0.76 3.30
PHP PHP 5.6 MSVC++ 32 bit 8 10 0.39 3.13
PHP Quercus 4.0 free / SUN JDK 11 64 bit 6 6 0.61 2.79
Python CPython 3.8 GCC 64 bit 7 7 0.41 2.78
Python CPython 2.7 MSVC++ 64 bit 8 6 0.42 2.72
Python IronPython 2.7 / .NET 4 64 bit 8 11 0.18 2.49
Python CPython 3.6 MSVC++ 64 bit 5 5 0.44 2.22
Python IronPython 2.7 / .NET 4 32 bit 9 7 0.16 2.18

We see that:

The last one should not surprise anyone.

Article history:

Version Date Description
1.0 January 14th 2004 Initial version (in Danish) published on Eksperten.dk
2.0 October 2nd 2021 New benchmark code and complete rewrite (in English)
2.1 November 16th 2021 Add Ada
2.2 December 26th 2022 Add a few new versions
2.3 May 7th 2022 Add C++ and Fortran
2.4 May 17th 2022 Add some new versions
2.5 December 15th 2023 Add more script tests (Groovy, codon, cython, FrankenPHP)

Other articles:

See list of all articles here

Comments:

Please send comments to Arne Vajhøj