QL Tinkering

Helpful tips and guides, also new users can ask for help here.
qbits
Trump Card
Posts: 171
Joined: Sun Dec 11, 2016 3:32 pm

Re: QL Tinkering

Post by qbits »

Hi, WRAP I have some further checks and interesting results on composite AND as opposed to nested IF statements. As to FOR loops my Iteration Test prog results show as you implied For loop using integers are slightly faster maybe.

Ref; New chapter for SBASIC/SuperBASIC Reference Manual Norman here’s a possible part two...

SuperBASIC Interpreter Timings
A number of factors in executing elements of a program have already been suggested by the way the Interpreter acts on the code elements and syntax of each line. Prioritising the namelist is one, how keywords process variables is another.

‘IF’ expressions and how they are handled by the Interpreter in execution, can nested IF expressions be executed faster by the interpreter than processing multiple expressions using combination logical operators.

For example nested IFs: IF a<b :IF c<d THEN if both are true the following statement is executed. This can also be written: IF a<b AND c<d THEN again if both are true the following statement is executed. The following Program carries out a number of iterations to determine the SuperBASIC Interpreters speed of processing certain actions. The First half deals with the IF expressions:- Procedure Test01

REPeat loops run for both nested IF and combination logical AND expressions. Then run again for a second time but in reverse order to compensate any advantage of one loop running before the other. By altering the Value on line number 130,142, 154,166 the set trial time can be extended. However be sure to compensate for the full amount of time by changing the values following the commands PRINT +5 etc.

100 REMark SBTimeTrial (SuperBASIC Iteration Timer)
102 :
104 WINDOW#2,512,200,0,0:PAPER#2,0:CLS#2
106 WINDOW 400,84,20,12:PAPER 0:BORDER 2,2:INK 7:Test01
108 :
110 DEFine PROCedure Test01
112 LOCal a,b,c,d,n,st,ts,sw$:a=5:b=3:c=3:d=5
114 CSIZE 2,1:CURSOR 10,2:PRINT 'IF a>b:IF c<d Test'
116 CURSOR 10,40:PRINT 'IF a>b AND c<d Test':CSIZE 0,0
118 CURSOR 10,24:PRINT 'Iterations: ':CURSOR 200,24:PRINT 'Stopwatch: '
120 CURSOR 10,64:PRINT 'Iterations: ':CURSOR 200,64:PRINT 'Stopwatch: '
122 n=0:st=DATE
124 REPeat lp
126 IF a>b:IF c<d:n=n+1
128 CURSOR 88,24:PRINT n:CURSOR 266,24
130 IF DATE-st=5:PRINT 5:EXIT lp:ELSE PRINT DATE-st
132 END REPeat lp
134 n=0:st=DATE
136 REPeat lp
138 IF a>b AND c<d:n=n+1
140 CURSOR 88,64:PRINT n:CURSOR 266,64
142 IF DATE-st=5:PRINT 5:EXIT lp:ELSE PRINT DATE-st
144 END REPeat lp
146 n=0:st=DATE
148 REPeat lp
150 IF a>b AND c<d:n=n+1
152 CURSOR 140,64:PRINT n:CURSOR 266,64
154 IF DATE-st=5:PRINT 10:EXIT lp:ELSE PRINT 5+DATE-st
156 END REPeat lp
158 n=0:st=DATE
160 REPeat lp
162 IF a>b:IF c<d:n=n+1
164 CURSOR 140,24:PRINT n:CURSOR 266,24
166 IF DATE-st=5:PRINT 10:EXIT lp:ELSE PRINT 5+DATE-st
168 END REPeat lp
170 END DEFine
172 :

The second half of the Program redraws the output window for the Procedure Test02 output. This looks at the FOR loop executing Integer variables as opposed to Floating Point variables. Variables suffixed with ‘a%’ are identified as Integer variables, variables held by ‘a’ will be treated as a Floating Point. REPeat loops run for both Integer and Floating Point FOR loop then run a second time but in reverse order to compensate any advantage one may hold over the other. By altering the Value on line number 200,216, 232,248 the trial time can be reduced. The reason being emulators such as QPC2 running on today’s faster computers will run into overflow with the limit of Integer numbers (-32768 to +32767). However be sure to change the time values that follow the PRINT commands etc. in line with IF DATE-st=4.

174 WINDOW 400,84,20,100:BORDER 2,2:Test02
176 :
178 DEFine PROCedure Test02
180 LOCal n1%,n12,ts,st,ta
182 CSIZE 2,1:CURSOR 10,2:PRINT 'For loop Integer Test'
184 CURSOR 10,40:PRINT 'For loop Floating Point Test':CSIZE 0,0
186 CURSOR 10,24:PRINT 'Iterations: ':CURSOR 200,24:PRINT 'Stopwatch: '
188 CURSOR 10,64:PRINT 'Iterations: ':CURSOR 200,64:PRINT 'Stopwatch: '
190 n1%=0:st=DATE
192 REPeat lp
194 FOR i=1 TO 20000
196 n1%=n1%+1
198 CURSOR 88,24:PRINT n1%:CURSOR 266,24
200 IF DATE-st=4:PRINT 4:EXIT lp:ELSE PRINT DATE-st
202 END FOR i
204 END REPeat lp
206 n12=0:st=DATE
208 REPeat lp
210 FOR i=1 TO 20000
212 n12=n12+1
214 CURSOR 88,64:PRINT n12:CURSOR 266,64
216 IF DATE-st=4:PRINT 4:EXIT lp:ELSE PRINT DATE-st
218 END FOR i
220 END REPeat lp
222 n12=0:st=DATE
224 REPeat lp
226 FOR i=1 TO 20000
228 n12=n12+1
230 CURSOR 140,64:PRINT n12:CURSOR 266,64
232 IF DATE-st=4:PRINT 8:EXIT lp:ELSE PRINT 4+DATE-st
234 END FOR i
236 END REPeat lp
238 n1%=0:st=DATE
240 REPeat lp
242 FOR i=1 TO 20000
244 n1%=n1%+1
246 CURSOR 140,24:PRINT n1%:CURSOR 266,24
248 IF DATE-st=4:PRINT 8:EXIT lp:ELSE PRINT 4+DATE-st
250 END FOR i
252 END REPeat lp
254 END DEFine

The results:- ???

QBITS
Attachments
SBTimeTrials.zip
(867 Bytes) Downloaded 161 times
SBTimeTest 04.jpg
SBTimeTest 03.jpg


User avatar
pjw
QL Wafer Drive
Posts: 1286
Joined: Fri Jul 11, 2014 8:44 am
Location: Norway
Contact:

Re: QL Tinkering

Post by pjw »

And lets not forget the mighty SELect ON construct, when its possible to use:

Code: Select all

100 CLS: its = 1E7: REMark <- set no. iterations according to system
110 :
120 PRINT 'IF-OR float'; TO 32;
130 n = 0: a = 1: t = DATE
140 FOR i = 0 TO its: IF a = 1 OR a = 2: n = n + 1: END IF : END FOR i
150 PRINT DATE - t
160 REMark 13-14s on my system (SBASIC)
170 :
180 PRINT 'SEL ON, float, first choice'; TO 32;
190 n = 0: a = 1: t = DATE
200 FOR i = 0 TO its: SELect ON a: = 1, 2: n = n + 1: END SELect : END FOR i
210 PRINT DATE - t
220 REMark 7-8s on my system (SBASIC)
230 :
Results vary slightly, depending on whether the first or n'th choice is taken, but it seems to me that in SBASIC, at least, the SEL ON construct is almost twice as fast in situations like this.


Per
dont be happy. worry
- ?
User avatar
M68008
Trump Card
Posts: 223
Joined: Sat Jan 29, 2011 1:55 am
Contact:

Re: QL Tinkering

Post by M68008 »

qbits wrote:New chapter for SBASIC/SuperBASIC Reference Manual
If a document is written about SuperBASIC performance, keep in mind that there are separate SuperBASIC runtimes and what is true for one may or may not be true for another (I assume that's why you tested both on QPC and QL2K):
  • Sinclair SuperBASIC
  • Minerva SuperBASIC (I assume it's different?)
  • SBASIC
  • Turbo-compiled
  • Qliberator-compiled
That doesn't mean all of them need to be covered, but all results should make it clear to which variants they refer.

In theory the emulator of HW platform could also affect optimization choices, although that's probably less of a factor.


Knowing best practices for interpreted SuperBASIC may be interesting for small programs.
If it gets to a point where performance is critical, the recipe is relatively simple and Rich already mentioned it:
  • Compile with Turbo!
  • Use IMPLICIT% to mark any integer variables that don't already end with % as integer
This usually results in huge speed-ups compared to interpreters!


For critical apps like games, if further speedup is needed, identify the performance-critical sections (typically just a few loops in the program) and:
  • Consider alternative, faster algorithms when available
  • Use good toolkits if available, otherwise rewrite in assembly and call that code from the main SuperBASIC program

Going back the "IF AND" vs "IF IF" question, without benchmarking I would expect:
  • The first version is a single expression and it might avoid the small overhead of the interpreter moving to a different statement (when using an interpreter)
  • The second avoids the second test when the first test is false. If the second test is a complex expression (for example involving function calls) rather than just a simple variable, it should be quite faster on average


User avatar
M68008
Trump Card
Posts: 223
Joined: Sat Jan 29, 2011 1:55 am
Contact:

Re: QL Tinkering

Post by M68008 »

[deleted duplicate post]
Last edited by M68008 on Fri Sep 21, 2018 9:31 pm, edited 1 time in total.


User avatar
Andrew
Aurora
Posts: 786
Joined: Tue Jul 17, 2018 9:10 pm

Re: QL Tinkering

Post by Andrew »

OK - here are my results.
I used the QL + Tetroid's GoldCard and QEmulator set to QL speed and then to GoldCard speed
The only conclusions I have are:
- QEmulator set to GoldCard speed is about twice as fast as the QL with GoldCard !
- after running the program several tiemes = on QEmulator on the first run of each test (the first 5 seconds) the results can vary with as much as 20% - the second run (next 5 seconds) the results are more consistent, the variation is 5%
- on QL+Goldcard the results vary with only 1% or less
- the construction IF a>b AND c<d Test always had more iterations than the double IF
- the "For loop Integer Test" always had more iterations than the floating point (but I guess that this is because integer addition is faster than fp addition, not because of the for loop)
Attachments
QL with GoldCard
QL with GoldCard
QEmulator set to GoldCard speed
QEmulator set to GoldCard speed
QEmulator set to QL speed
QEmulator set to QL speed


qbits
Trump Card
Posts: 171
Joined: Sun Dec 11, 2016 3:32 pm

Re: QL Tinkering

Post by qbits »

Hi, 23 Sep 2018
Thanks Andrew for posting your results..and M68008 I take note and understand you point of relevance to different builds. SELect ON pjw I have left a section open in my updated Prog just for such...

Updated Prog... see attached.

The checks carried out so far do not appear to give the results I was half expecting. I note that my tests are run on emulators not hardware. For the namelists First/Last entry in some of the tests came out heavily in favour of the Last not First. The nested IFs as opposed to the logical operators when like for like the results were often about even. When the number of false expressions increased the nested IFs were constantly ahead (as you would expect).

The FOR loop identifier I have since learnt always uses a simple Floating Point variable name. As to FOR loops with Integer variables being faster than Floating Point variables the results in most cases for the QPC2 emulator appear to favour the FP. The QL2K emulator running at singles clock multiplier speed (ie original QL speed) implies FOR loop with Integer variables are faster.

SBTrials01.jpg was run with nested IFs / Logical operators where all expressions are true
SBTrials02.jpg was run with nested IFs / Logical operators where only the first expression is true
SBTrials03.jpg QL2K emulator clock multiplier x1

QBITS
Attachments
SBTrials_dos.zip
(1.83 KiB) Downloaded 138 times
SBTrials01.jpg
SBTrials02.jpg
SBTrials03.jpg


stevepoole
Super Gold Card
Posts: 712
Joined: Mon Nov 24, 2014 2:03 pm

Re: QL Tinkering

Post by stevepoole »

Hi qbits,
Integer FOR loops are faster than FP ones if you Turbo them. (The Turbo manual is full of good tips on fast coding tricks).
I find timings using an emulator are not consistant, as they are on QL hardware, because of PC overheads.
Timings on QLs are slower than on emulators, but can be scaled so as to be relatively meaningful.
If you want maximum speed, code in C++.
If you want user-friendly coding, use your QL or emulator... as you will write and debug code much faster !
As a general rule in Industry, don't take more time coding than will be saved by using that new code.
But as tinkerers, we may just enjoy coding for fun...
QL Forever !
Regards,
Steve.


qbits
Trump Card
Posts: 171
Joined: Sun Dec 11, 2016 3:32 pm

Re: QL Tinkering

Post by qbits »

Hi,
stevepoole
If I recall TURBO has an IMPLICIT% command to make variables used for FOR and SELect identifiers Integers as opposed to the standard QL SuperBASIC FP.

As a general rule in Industry, don't take more time coding than will be saved by using that new code.
But as tinkerers, we may just enjoy coding for fun...


As it should be...

And so Tinkering on...
The SELect ON where the identifying variable is a Floating Point variable, gives a wide choice of options. In evaluating an expression using an Inline form SELect a=65,97:PRINT ‘Aa’ is very similar to IF x=65 OR a=97:PRINT’Aa’.

One of the requirements in Games is checking if a boundary has been reached or the limitations of the area surrounding a target that qualifies as a hit. In either case the limits can be described as xmin, xmax, ymin, ymax. Here the use of the SELect command as an alternative can be compared with nested IF clauses and IF combination Logic operator clauses:-

IF x>xmin: IF x<xmax: IF y>ymin: IF y<ymax:PRINT ‘Home’

IF x>xmin AND x<xmax AND y>ymin AND y<ymax:PRINT ‘Home’

SELect ON x
=xmin TO xmax:SELect On y=ymin TO ymax:PRINT ‘Home’
END SEL

Observations after 10 passes on the QPC2 Emulator for each set of comparisons when x,y are True (ie. fall within the boundaries), nested IFs clauses and If clauses using Logical operators are about even but SELect scores higher against both. When x,y both fall outside the boundary area ie. all expressions are False, nested IFs score consistently higher than Logical operators, but surprisingly SELect still out performs them both.

Further upgrades to my Prog SBTrials...

This all being a slight diversion has anyone tried running QBAD2370v5QPC2!

QBITS
Attachments
SBTrials.zip
(2.38 KiB) Downloaded 136 times
QBAD2370v5QPC2.zip
(2.07 MiB) Downloaded 138 times


RWAP
RWAP Master
Posts: 2834
Joined: Sun Nov 28, 2010 4:51 pm
Location: Stone, United Kingdom
Contact:

Re: QL Tinkering

Post by RWAP »

I have tried QBAD - it runs fairly well on QPC2 - with Lightning to speed up the graphics routines (or Minerva) it is not too bad on q-emulator either....


User avatar
pjw
QL Wafer Drive
Posts: 1286
Joined: Fri Jul 11, 2014 8:44 am
Location: Norway
Contact:

Re: QL Tinkering

Post by pjw »

While I agree that GO TO/GO SUB should not be left in the hands of those most likely
to use them, I do rather miss the ON var GO TO construct. In certain situations it
avoids all the IFs, ANDs and buts, as in the case of If a = 1, do this, If a = 2, do that.
SELect ON compensates for that in many ways, and I guess we'll all become better
people for not longer using GO TOs. Apart from eliminating a lot of spaghetti coding,
getting rid of GO TOs is necessitated by the use of text editors and such to write
programs in. There line numbers are a hassle. Unless one had LABels, that is.

In SuperBASIC there is a peek to get at the current line number. I no longer
remember what it is, but it should be easy to find out. In SBASIC that is no longer
as easy (PEEK_W(\\ $64) doesnt seem to work). However, getting the current DATA
statement line number IS possible with a simple peek. So the following synthetic
programming example offers a way to define labels (in certain types of programs) and
resurrect the use of ON .. GO SUB if one is thus inclined. I havent speed tested, as it
involves the use of sub routines rather than the simple statement we used in earlier
examples, but it should (in theory) be faster than IF AND, IF IF and SEL ON - in certain
situations. (This is SBASIC only. Ive not tried compiling either.)

Code: Select all

100 CLS
110 RESTORE
120 READ dummy
130 READ LABel1
140 READ LABel2
150 READ LABel3
160 :
170 DATA 0: REMark Dummy
180 PRINT LABel1, LABel2, LABel3
190 :
200 FOR i = 0 TO 5
210  choose = RND(1 TO 3)
220  PRINT 'Choice'! choose,
230  ON choose GO SUB LABel1, LABel2, LABel3
240 END FOR i
250 STOP
260 :
270 REMark Lable 1
280 DATA PEEK_W(\\$94)
290 PRINT 1: RETurn
300 :
310 REMark Lable 2
320 DATA PEEK_W(\\$94)
330 PRINT 2: RETurn
340 :
350 REMark Lable 3
360 DATA PEEK_W(\\$94)
370 PRINT 3: RETurn
380 :


Per
dont be happy. worry
- ?
Post Reply