There are a few machines I'm quite interested in comparing so I decided to create a simple Basic benchmark to get an idea of their relative speed. The benchmark tests 7 aspects and is inspired by qsbb, which is included with the qlay Sinclair QL emulator. The Basic source code for all the machines tested is available in the GitHub repo. I chose Basic because it was available on all the machines I wanted to test and because the versions I created for each machine would require few changes.
Benchmarks are only ever a test of what you are benchmarking and there are often other tasks that the machines would do much better at. In this case because all the benchmarks are written in Basic they are a test of both the hardware and the Basic implementation as can be seen by the Spectrum results.
Results
The results are listed below and for each the higher the number the faster they are.
Machine | Basic | Printing | Functions | Strings | For Loops | Gosubs | Arrays | Maths | Average |
---|---|---|---|---|---|---|---|---|---|
Atari ST | ST Basic | 243 | 177 | 96 | 53 | 363 | 269 | 119 | 189 |
Amstrad CPC6128 | Locomotive Basic | 143 | 29 | 164 | 39 | 384 | 193 | 53 | 144 |
Amstrad PCW 9256 | Mallard Basic | 251 | 26 | 140 | 43 | 314 | 173 | 53 | 143 |
Spectrum +3 | Mallard Basic | 145 | 26 | 136 | 42 | 306 | 167 | 52 | 125 |
C128c1 | Basic 7.0 | 305 | 22 | 86 | 32 | 108 | 141 | 35 | 104 |
Amstrad PCW 9256 | Basic-80 (MBasic) | 214 | 19 | 89 | 21 | 240 | 104 | 31 | 103 |
C128c2 | Basic 7.0 | 292 | 22 | 82 | 30 | 93 | 137 | 35 | 99 |
Vic-20 | Basic 2 | 267 | 14 | 109 | 28 | 140 | 115 | 25 | 98 |
Spectrum +3 | Basic-80 (MBasic) | 117 | 18 | 86 | 20 | 235 | 101 | 30 | 87 |
C64 | Basic 2 | 222 | 12 | 92 | 24 | 117 | 97 | 21 | 84 |
Pet 8032 | Basic 4.0 | 249 | 12 | 86 | 24 | 86 | 98 | 22 | 82 |
MFA Mikrocomputerm1 | Basic-80 (MBasic) | 186 | 14 | 64 | 15 | 167 | 77 | 23 | 78 |
Sinclair QL | SuperBasic | 112 | 43 | 68 | 16 | 93 | 98 | 77 | 72 |
Plus/4 | Basic 3.5 | 180 | 14 | 53 | 18 | 70 | 83 | 22 | 63 |
C128c4 | Basic 7.0 | 144 | 11 | 41 | 16 | 52 | 68 | 17 | 50 |
C128c3 | Basic 7.0 | 148 | 11 | 40 | 15 | 45 | 66 | 17 | 49 |
C128c5 | Basic-80 (MBasic) | 99 | 9 | 42 | 9 | 101 | 52 | 15 | 47 |
Spectrum 48k | 48 Basic | 88 | 6 | 28 | 5 | 27 | 42 | 17 | 30 |
Spectrum +3 | +3 Basic | 69 | 6 | 24 | 4 | 23 | 34 | 16 | 25 |
Notes
m1 2Mhz 8085 machine - Thanks to Robert
Observations
The benchmarks for a few of the machines stand out for me because they were unexpected or confirmed what I had already heard.
Sinclair QL
The biggest surprise for me was how slow the Sinclair QL was. I knew it was hampered by the choice of a Motorola 68008, instead of a 68000, but the benchmark indicates just what a difference this decision made. It is particularly apparent if you consider the Amstrad PCW and Amstrad CPC6128 which were aimed at or could appeal to a similar market and deliver the sorts of speed that the QL should have delivered even if they had just stuck with the z80. That said, when it comes to the Functions and Maths test it was ahead of all the 8-bit machines and it would have been much easier to make use of the extra memory it could address without having to resort to bank switching.
Commodore 128
It is often said how slow CP/M was on the C128 and if you compare the benchmarks for the C128 vs the Amstrad PCW using Basic-80, it is quite clear just how slow it was. I'm also struck by how much slower the C128 was using Basic 7.0 in slow mode than the C64 using Basic 2. It would be interesting to know why this is.
Atari ST
The benchmark for ST Basic, while being top of the list, probably says more about the poor implementation of Basic than it does about the Hardware itself.
Sinclair Spectrum
This really underlines what a difference the implementation of Basic makes. If you take the Spectrum +3 running +3 Basic compared to when it is running Mallard Basic under CP/M; the Mallard Basic version runs about 5 times as quickly on the same hardware.
Emulators
All the tests have been run on emulators as I don't have all the machines and it makes the tests easy to reproduce. They all aim to be cycle accurate, but naturally they have to allow some flexibility otherwise they would be too resource intensive. Therefore the benchmark figures will never be quite as accurate as running on real hardware, but should give a good indication of their speed.
Emulator | Machines |
---|---|
Arnold | Amstrad: CPC6128 |
Fuse | Sinclair: Spectrum 48k, Spectrum +3 |
Hatari | Atari: ST |
JOYCE | Amstrad: PCW |
Q-emuLator | Sinclair: QL |
Vice | Commodore: Pet, Vic-20, C64, C128, Plus/4 |
The Basic Code
I have put the Commodore Basic version below as I think it is the simplest version to understand. In the code the variable ti
holds the value of the system clock and is updated every 1/60th of a second. The Basic source code for all versions are held in the GitHub repo.
10 rem basic benchmark
20 rem inspired by qsbb from qlay sinclair ql emulator
30 rem
40 rem copyright (c) 2019 lawrence woodman
50 rem licensed under an mit licence
100 rem array used later
110 dim ar(20)
200 print "basic benchmark"
210 print "7 tests, 20 seconds each"
220 print
1000 rem calculate benchmarks
1010 print
1020 print "please wait..."
1030 print
1100 rem benchmark printing
1110 t=ti
1120 p=0
1130 for i=1 to 20
1140 print ".";
1150 next i
1160 p=p+1
1170 if ti-t<=1200 then goto 1130
1300 rem benchmark functions
1310 t=ti
1320 f=0
1330 for i=1 to 20
1340 ra=sin(0.1):rb=log(4):rc=exp(10)
1350 next i
1360 f=f+1
1370 if ti-t<=1200 then goto 1330
1500 rem benchmark strings
1510 t=ti
1520 s=0
1530 for i=1 to 20
1540 a$="abcdefghijklmnopqrstuvwxyz"
1550 b$="zyxwvutsrqponmlkjihgfedcba"
1560 c$=a$+b$
1570 next i
1580 s=s+1
1590 if ti-t<=1200 then goto 1530
1700 rem benchmark for loops
1710 t=ti
1720 l=0
1730 for i=1 to 20
1740 for j=1 to 20: next j
1750 next i
1760 l=l+1
1770 if ti-t<=1200 then goto 1730
1800 rem benchmark gosubs
1810 goto 1830
1820 return
1830 t=ti
1840 g=0
1850 for i=1 to 20
1860 gosub 1820:gosub 1910
1870 next i
1880 g=g+1
1890 if ti-t<=1200 then goto 1850
1900 goto 1920
1910 return
1920 :
2000 rem benchmark arrays
2010 t=ti
2020 a=0
2030 for i=1 to 20
2040 ar(i)=i:b=ar(i)
2050 next i
2060 a=a+1
2070 if ti-t<=1200 then goto 2030
2200 rem benchmark maths
2210 t=ti
2220 m=0
2230 ka=5
2240 kb=6.2
2250 for i=1 to 20
2260 r=ka+kb-ka/kb*ka*kb
2270 r=5+6.2-5/6.2*5*6.2
2280 next i
2290 m=m+1
2300 if ti-t<=1200 then goto 2250
3010 print:print
3020 print "results"
3030 print "======="
3040 print "printing: "; p
3050 print "functions: "; f
3060 print "strings: "; s
3070 print "for loops: "; l
3080 print "gosubs: "; g
3090 print "arrays: "; a
3100 print "maths: "; m