Discussion has come up a few times in comp.os.vms/INFO-VAX about relative speed of various languages on VMS.
I posted some numbers and some code.
This is just a summary of those posts with a few more details and comments.
Some may find the conclusions interesting.
Disclaimer: this is a micro-benchmark. Some may even call it a nano-benchmark. It measures optimization of a handful of lines with a rather silly calculation that does not reflect any real world calculation. It is chosen because it is easy to port between different languages. But be prepared for significant differences between this benchmark and your real application.
It may be unusual to start with the conclusion, but here it is:
Optimization | Compilers/interpreters |
---|---|
Very fast | clang with high optimization Java 8 |
Fast | traditional (Fortran, Pascal, Basic, C, C++) clang without high optimization Ada without checks and with high optimization |
Medium | Ada with checks and without high optimization Java 5 Groovy with @CompileStatic |
Slow | Jython Groovy without @CompileStatic |
Very slow | Python |
Nothing particular surprising.
For the traditional VMS languages (C non-clang, Fortran, Pascal, Basic) the release compilers are signficantly faster than the Field Test (FT) compilers.
The difference in Java 5 on VMS Alpha and Java 8 on VMS Itanium/VMS x86-64 is likely due to 3 factors:
Software versions:
VMS | compilers/interpreters |
---|---|
VMS 8.4-2 Alpha | C 7.4 C++ 7.4 Fortran 8.3 Pascal 6.2 Basic 1.8 GNAT 3.12 Java 5 Python 2.7 Jython 2.5 on Java 5 |
VMS 8.4-2 Itanium | C 7.4 C++ 7.4 Fortran 8.3 Pascal 6.2 Basic 1.8 Java 8 Python 3.10 Jython 2.7 on Java 8 Groovy 4.0 on Java 8 |
VMS 9.2-1 x86-64 | C 7.4 (*) C++/clang 10.0 (*) Fortran 8.5 (*) Pascal 6.3 (*) Java 8 (*) Jython 2.7 on Java 8 (*) Groovy 4.0 on Java 8 (*) |
VMS 9.2-2 x86-64 | C 7.5 C++/clang 10.0 Fortran 8.5 Pascal 6.3 Basic 1.8 (*) Java 8 Python 3.10 (*) Jython 2.7 on Java 8 Groovy 4.0 on Java 8 |
*) Field test version.
Million operations per second (rounded):
Language | VMS 8.4-2L2 Alpha simulator Xeon @ 3.7 GHz |
VMS 8.4-2L3 Itanium @ 1.6 Ghz |
VMS 9.2-1 FT compilers VMWare Player Xeon @ 3.7 GHz |
VMS 9.2-2 Release compilers VMWare Player Xeon @ 3.7 GHz |
---|---|---|---|---|
C with /OPT=LEVEL:5 clang clang with -O3 |
56 56 N/A N/A |
246 246 N/A N/A |
136 136 133 784 |
543 543 135 783 |
C++ with /OPT=LEVEL:5 clang clang with -O3 |
59 59 N/A N/A |
246 246 N/A N/A |
132 786 135 769 |
135 784 135 787 |
Fortran with /OPT=LEVEL:5 |
60 60 |
246 246 |
136 138 |
546 546 |
Pascal | 63 | 246 | 136 | 537 |
Basic with /NOCHECK |
44 60 |
45 246 |
N/A N/A |
719 546 |
Ada with -gnatp -O3 |
21 70 |
N/A N/A |
N/A N/A |
N/A N/A |
Java | 28 | 286 | 707 | 711 |
Python | 0.14 | 0.64 | N/A | 3.49 |
Jython | 0.08 | 3.05 | 16 | 17 |
Groovy with @CompileStatic |
N/A N/A |
3 19 |
13 64 |
13 131 |
That the Basic code is faster without /NOCHECK must be an anommly - I will retest when release version of Basic becomes available.
Million operations per second (rounded):
Language | VMS 8.4-2L2 Alpha simulator Xeon @ 3.7 GHz |
VMS 8.4-2L3 Itanium @ 1.6 Ghz |
VMS 9.2-1 FT compilers VMWare Player Xeon @ 3.7 GHz |
VMS 9.2-2 Release compilers VMWare Player Xeon @ 3.7 GHz |
---|---|---|---|---|
C with /OPT=LEVEL:5 clang clang with -O3 |
12 11 N/A N/A |
108 108 N/A N/A |
204 204 142 268 |
270 270 141 271 |
C++ with /OPT=LEVEL:5 clang clang with -O3 |
11 11 N/A N/A |
108 108 N/A N/A |
142 (optimized away) 144 265 |
145 (optimized away) 143 274 |
Fortran with /OPT=LEVEL:5 |
10 11 |
108 108 |
204 204 |
270 270 |
Pascal | 12 | 108 | 204 | 270 |
Basic with /NOCHECK |
12 12 |
77 79 |
N/A N/A |
46 45 |
Ada with -gnatp -O3 |
10 15 |
N/A N/A |
N/A N/A |
N/A N/A |
Java | 6 | 107 | 270 | 268 |
Python | 0.07 | 0.70 | N/A | 2.84 |
Jython | 0.09 | 2.65 | 20 | 26 |
Groovy with @CompileStatic |
N/A N/A |
3 107 |
16 218 |
14 205 |
Note that string operation speed is less about compiler optimization and more about string representation and string processing paradigms. The code tries to use strings as strings are typical used in the language - not what could be done for optimal performance. But I still consider the results a bit random.
Million operations per second (rounded):
Language | VMS 8.4-2L2 Alpha simulator Xeon @ 3.7 GHz |
VMS 8.4-2L3 Itanium @ 1.6 Ghz |
VMS 9.2-1 FT compilers VMWare Player Xeon @ 3.7 GHz |
VMS 9.2-2 Release compilers VMWare Player Xeon @ 3.7 GHz |
---|---|---|---|---|
C with /OPT=LEVEL:5 clang clang with -O3 |
0.26 0.26 N/A N/A |
1.94 1.94 N/A N/A |
2.60 2.60 2.20 2.80 |
2.70 2.70 2.27 2.93 |
C++ with /OPT=LEVEL:5 clang clang with -O3 |
0.01 0.01 N/A N/A |
0.40 0.40 N/A N/A |
1.80 2.30 1.70 2.40 |
2.00 2.06 1.74 2.00 |
Fortran with /OPT=LEVEL:5 |
0.46 0.46 |
6.95 6.95 |
0.00 0.00 |
0.00 0.00 |
Pascal | 0.01 | 0.32 | 0.15 | 0.16 |
Basic with /NOCHECK |
0.01 0.01 |
0.13 0.13 |
N/A N/A |
0.14 0.14 |
Ada with -gnatp -O3 |
0.01 0.01 |
N/A N/A |
N/A N/A |
N/A N/A |
Java | 0.08 | 1.77 | 16.00 | 17.00 |
Python | 0.01 | 0.06 | N/A | |
Jython | 0.01 | 0.34 | 1.60 | 1.50 |
Groovy with @CompileStatic |
N/A N/A |
0.19 0.56 |
1.20 2.90 |
1.00 3.00 |
If you want everything to test yourself, then get this kit - it has all source, scripts etc..
#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("%.4f 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"
#define VMS_FACTOR 100
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 * VMS_FACTOR; i++)
{
strcpy(buf, "");
for(j = 0; j < N / VMS_FACTOR; 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 / VMS_FACTOR) / 3;
ix2 = 2 * (N / VMS_FACTOR) / 3;
if(strlen(buf) != (N / VMS_FACTOR) || 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("C:\n");
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;
}
#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(4) << (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";
const int VMS_FACTOR = 100;
void teststr(int scale)
{
int nstrscale = NSTR / scale;
TIMECOUNT_T t1 = GET_TIMECOUNT;
for(int i = 0; i < nstrscale * VMS_FACTOR; i++)
{
string s, buf;
buf = "";
for(int j = 0; j < N / VMS_FACTOR; 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 / VMS_FACTOR) / 3;
int ix2 = 2 * (N / VMS_FACTOR) / 3;
if(buf.length() != (N / VMS_FACTOR) || 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 << "C++:" << 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;
}
program native_test
integer*4 REP
parameter (REP = 10)
integer*4 i, scale
character*256 cmdlin
integer*4 cmdlinlen
write(*,*) 'Fortran:'
call lib$get_foreign(cmdlin,,cmdlinlen)
if(cmdlinlen.gt.0) then
read(cmdlin(1:cmdlinlen),'(I)') 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 sys$gettim(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 sys$gettim(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 sys$gettim(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 sys$gettim(t2)
call printres(t1, t2, nfpscale, N, 'floating point operations')
end
c
subroutine teststr(scale)
integer*4 scale
integer*4 NSTR, N, VMS_FACTOR
character*26 ALFA
parameter (NSTR = 100, N = 1000000,
+ ALFA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', VMS_FACTOR = 100)
integer*4 i, j, nstrscale, slen, ix, ix1, ix2, ix1m, ix2m
character*52 s
character*32767 buf
integer*8 t1, t2
nstrscale = NSTR / scale
call sys$gettim(t1)
do 200 i = 1, nstrscale * VMS_FACTOR
slen = 0
do 100 j = 1, N / VMS_FACTOR, 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 / VMS_FACTOR) / 3
ix2 = 2 * (N / VMS_FACTOR) / 3
ix1m = mod(i - 1 + ix1, len(ALFA)) + 1
ix2m = mod(i - 1 + ix2, len(ALFA)) + 1
if((slen.ne.(N / VMS_FACTOR)).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 sys$gettim(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
real*8 xperf
xperf = n1 * 1.0 * n2 / ((t2 - t1) / 10000000.0)
write(*,'(1x,f9.4,9h million ,a,11h per second)')
+ (xperf / 1000000), ops
end
[inherit('sys$library:pascal$lib_routines')]
program native_test(input, output);
type
string = varying[32767] of char;
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:4, ' 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 := Clock;
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 := Clock;
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 := Clock;
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 := Clock;
printres(t1, t2, nfpscale, N, 'floating point operations');
end;
const
ALFA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
VMS_FACTOR = 100;
procedure teststr(scale : integer);
var
i, j, nstrscale, ix, ix1, ix2 : integer;
s, buf : string;
t1, t2 : Cardinal;
begin
nstrscale := NSTR div scale;
t1 := Clock;
for i := 1 to nstrscale * VMS_FACTOR do begin
buf := '';
for j := 1 to ((N div VMS_FACTOR) div 10) do begin
s := ALFA + ALFA;
ix := (i - 1 + 10 * (j - 1)) mod length(ALFA);
buf := buf + substr(s, ix + 1, 1) + substr(s, ix + 2, 2) + substr(s, ix + 4, 3) + substr(s, ix + 7, 4);
end;
ix1 := (N div VMS_FACTOR) div 3;
ix2 := 2 * (N div VMS_FACTOR) div 3;
if (length(buf) <> (N div VMS_FACTOR)) or
(buf[ix1] <> ALFA[((i - 1 + ix1 - 1) mod length(ALFA)) + 1]) or
(buf[ix2] <> ALFA[((i - 1 + ix2 - 1) mod length(ALFA)) + 1]) then begin
writeln('String test error');
halt;
end;
end;
t2 := Clock;
printres(t1, t2, nstrscale, N div 10, 'string operations');
end;
const
REP = 10;
var
i, scale : integer;
cmdlin : string;
begin
writeln('Pascal:');
lib$get_foreign(resultant_string:=cmdlin.body,resultant_length:=cmdlin.length);
if cmdlin.length > 0 then begin
readv(cmdlin, scale);
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.
program native_test
declare integer constant REP = 10
declare integer i, xscale
declare string cmdlin
external long function lib$get_foreign(string)
external sub testint(integer)
external sub testfp(integer)
external sub teststr(integer)
print "Basic:"
call lib$get_foreign(cmdlin)
if len(cmdlin) > 0 then
xscale = val%(cmdlin)
else
xscale = 1
end if
for i = 1 to REP
call testint(xscale)
next i
for i = 1 to REP
call testfp(xscale)
next i
for i = 1 to REP
call teststr(xscale)
next i
end program
!
sub testint(integer xscale)
declare integer constant NINT = 10000
declare integer constant N = 1000000
declare integer i, j, nintscale, sum
declare quad t1, t2
external sub printres(quad, quad, integer, integer, string)
external long function sys$gettim(quad)
nintscale = NINT / xscale
call sys$gettim(t1)
for i = 1 to nintscale
sum = i - 1%
for j = 1 to N
sum = ((sum + 1%) * 2% + 1%) / 2%
next j
if sum <> (i - 1% + N) then
print "Integer test error"
stop
end if
next i
call sys$gettim(t2)
call printres(t1, t2, nintscale, N, "integer operations")
end sub
!
sub testfp(integer xscale)
declare integer constant NFP = 1000
declare integer constant N = 1000000
declare integer i, j, nfpscale
declare double sum
declare quad t1, t2
external sub printres(quad, quad, integer, integer, string)
nfpscale = NFP / xscale
call sys$gettim(t1)
for i = 1 to nfpscale
sum = i - 1.0
for j = 1 to N
sum = ((sum + 1.0) * 2.0 + 1.0) / 2.0
next j
if abs(sum - (i - 1.0 + 1.5 * N)) > 1 then
print "Floating point test error"
stop
end if
next i
call sys$gettim(t2)
call printres(t1, t2, nfpscale, N, "floating point operations")
end sub
!
sub teststr(integer xscale)
declare integer constant NSTR = 100
declare integer constant N = 1000000
declare string constant ALFA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
declare integer constant VMS_FACTOR = 100
declare integer i, j, nstrscale, ix1, ix2
declare string s, buf
declare quad t1, t2
external sub printres(quad, quad, integer, integer, string)
nstrscale = NSTR / xscale
call sys$gettim(t1)
for i = 1 to nstrscale * VMS_FACTOR
buf = ""
for j = 1 to (N / VMS_FACTOR) / 10
s = ALFA + ALFA
ix = mod(i + 1 + 10 * (j - 1), len(ALFA))
buf = buf + mid(s, ix + 1, 1) + mid(s, ix + 2, 2) + mid(s, ix + 4, 3) + mid(s, ix + 7, 4)
next j
ix1 = (N / VMS_FACTOR) / 3
ix2 = 2 * (N / VMS_FACTOR) / 3
if((len(buf) <> (N / VMS_FACTOR)) or &
(mid(buf, ix1, 1) <> mid(ALFA, mod(i + ix1, len(ALFA)) + 1, 1)) or &
(mid(buf, ix2, 1) <> mid(ALFA, mod(i + ix2, len(ALFA)) + 1, 1))) then
print "String test error"
stop
end if
next i
call sys$gettim(t2)
call printres(t1, t2, nstrscale, N / 10, "string operations")
end sub
!
sub printres(quad t1, quad t2, integer n1, integer n2, string ops)
declare double xperf
xperf = n1 * 1.0 * n2 / ((t2 - t1) / 10000000.0)
print using "####.#### million 'E per second", (xperf / 1000000), ops
end sub
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 => 4, 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;
tsk : Task_Id;
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");
tsk := Current_Task;
Abort_Task(tsk);
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;
tsk : Task_Id;
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");
tsk := Current_Task;
Abort_Task(tsk);
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";
VMS_FACTOR : constant Integer := 100;
s : constant String := ALFA & ALFA;
nstrscale, ix, ix1, ix2, ix1alfa, ix2alfa : Integer;
buf : Unbounded_String;
t1, t2 : Time;
tsk : Task_Id;
begin
nstrscale := NSTR / scale;
t1 := Clock;
for i in 1..(nstrscale * VMS_FACTOR) loop
buf := To_Unbounded_String("");
for j in 1..(N / VMS_FACTOR) /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 / VMS_FACTOR) / 3;
ix2 := 2 * (N / VMS_FACTOR) / 3;
ix1alfa := (i - 1 + ix1 - 1) mod ALFA'Length + 1;
ix2alfa := (i - 1 + ix2 - 1) mod ALFA'Length + 1;
if To_String(buf)'Length /= (N / VMS_FACTOR) or To_String(buf)(ix1..ix1) /= ALFA(ix1alfa..ix1alfa) or To_String(buf)(ix2..ix2) /= ALFA(ix2alfa..ix2alfa) then
Put_Line("String test error");
tsk := Current_Task;
Abort_Task (tsk);
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
Put_Line("Ada:");
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;
import java.text.NumberFormat;
import java.text.DecimalFormat;
public class JvmTest {
private static NumberFormat nf = new DecimalFormat("0.0000");
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";
private final static int VMS_FACTOR = 100;
public static void teststr(int scale) {
int nstrscale = NSTR / scale;
long t1 = System.currentTimeMillis();
for(int i = 0; i < nstrscale * VMS_FACTOR; i++) {
StringBuffer sb = new StringBuffer("");
for(int j = 0; j < N / VMS_FACTOR; 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 / VMS_FACTOR) / 3;
int ix2 = 2 * (N / VMS_FACTOR) / 3;
if(sb.length() != (N / VMS_FACTOR) || 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("Java:");
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);
}
}
}
import sys
import time
import math
def printres(t1, t2, n1, n2, ops):
xperf = n1 * n2 / (t2 - t1)
print('%.4f 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'
VMS_FACTOR = 100
def teststr(scale):
nstrscale = NSTR // scale
t1 = time.time()
for i in range(nstrscale * VMS_FACTOR):
sb = ''
for j in range((N // VMS_FACTOR) // 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 // VMS_FACTOR) // 3
ix2 = 2 * (N // VMS_FACTOR) // 3
mix1 = (i + ix1) % len(ALFA)
mix2 = (i + ix2) % len(ALFA)
if len(sb) != (N // VMS_FACTOR) 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('Python:')
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)
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"
VMS_FACTOR = 100
void teststr(int scale) {
nstrscale = NSTR.intdiv(scale)
t1 = System.currentTimeMillis()
for(i = 0; i < nstrscale * VMS_FACTOR; i++) {
sb = new StringBuffer("")
for(j = 0; j < N.intdiv(VMS_FACTOR); 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(VMS_FACTOR).intdiv(3)
ix2 = (2 * N.intdiv(VMS_FACTOR)).intdiv(3)
if(sb.length() != N.intdiv(VMS_FACTOR) || 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("Groovy:")
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)
}
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 = 100000
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 = 100000
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 VMS_FACTOR = 100
int nstrscale = NSTR.intdiv(scale)
long t1 = System.currentTimeMillis()
for(int i = 0; i < nstrscale * VMS_FACTOR; i++) {
StringBuffer sb = new StringBuffer("")
for(int j = 0; j < N.intdiv(VMS_FACTOR); 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(VMS_FACTOR).intdiv(3)
int ix2 = (2 * N.intdiv(VMS_FACTOR)).intdiv(3)
if(sb.length() != N.intdiv(VMS_FACTOR) || 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("Groovy @CompileStatic:")
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)
}
Version | Date | Description |
---|---|---|
1.0 | December 6th 2023 | Initial version |
1.1 | December 15th 2023 | Add Groovy |
1.2 | March 29th 2024 | Add release compilers and FT Basic for x86-64 |
See list of all articles here
Please send comments to Arne Vajhøj