QL Tinkering

Helpful tips and guides, also new users can ask for help here.
Post Reply
RWAP
RWAP Master
Posts: 2834
Joined: Sun Nov 28, 2010 4:51 pm
Location: Stone, United Kingdom
Contact:

Re: QL Tinkering

Post by RWAP »

Great so we have the start of a new chapter for the SBASIC/SuperBASIC Reference Manual on writing SuperBASIC programs for speed - now all we need is for someone to volunteer to pull it together and create the chapter... :D


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

Re: QL Tinkering

Post by RWAP »

Of course the one thing which is missing (and which I did for my programs) was to track down the actual sources of bottlenecks in the program and re-write the function or procedure as a new machine code keyword....


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

Re: QL Tinkering

Post by qbits »

Hi,
RWAP having looked through my code, I do use a number of FOR loops, which have INK commands. I use then typically because with moving objects, colours change to background colour for them to disappear and then reset for them to reappear etc. I have utilised in some cases the OVER -1 (XOR) function. Be interested in your views - the illusion of moving objects across the screen and tricks in SuperBASIC to speed then up?

I’ve been doing a bit of reading up on QDOS and the SuperBASIC Interpreter I can see why integers are maybe quicker than floating point. Integers are represented as two-byte hexadecimal numbers. This gives a range of -32768 to 32767. Floating points have a larger range being held in two parts, a two-byte exponent and a four-byte mantissa.

Use of IF statements where you suggested
IF astro(n,7)>0 AND astro(n,5)<3:astro(n,5)=3 > is slightly quicker as nested IFs
IF astro(n,7)>0: IF astro(n,5)<3:astro(n,5)=3

Hope you can explain this!
Combination logical operators work solely on true and false floating point values. My IF statement would therefore return false AND false, true AND true, false AND true, true AND false. The same as your suggested nested IF statements. However by my logic nested IF statements also require the interpreter to keep a count of intervening IFs so as to be sure of always finding the right ELSE or END IF when searching for clauses to be acted upon. The interpreter has to evaluate both expressions in either case but surely keeping track of nested IF statement would cost the interpreter more time not less.

QBITS


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

Re: QL Tinkering

Post by RWAP »

qbits wrote: RWAP having looked through my code, I do use a number of FOR loops, which have INK commands. I use then typically because with moving objects, colours change to background colour for them to disappear and then reset for them to reappear etc. I have utilised in some cases the OVER -1 (XOR) function. Be interested in your views - the illusion of moving objects across the screen and tricks in SuperBASIC to speed then up?
I can't think of any other method of doing this in SuperBASIC, other than using a machine code sprite toolkit.

However, I spotted at least one loop where the INK colour was set on every iteration of the loop, but did not change within the loop, so could safely be set before the FOR command.
Use of IF statements where you suggested
IF astro(n,7)>0 AND astro(n,5)<3:astro(n,5)=3 > is slightly quicker as nested IFs
IF astro(n,7)>0: IF astro(n,5)<3:astro(n,5)=3

Hope you can explain this!
Combination logical operators work solely on true and false floating point values. My IF statement would therefore return false AND false, true AND true, false AND true, true AND false. The same as your suggested nested IF statements. However by my logic nested IF statements also require the interpreter to keep a count of intervening IFs so as to be sure of always finding the right ELSE or END IF when searching for clauses to be acted upon. The interpreter has to evaluate both expressions in either case but surely keeping track of nested IF statement would cost the interpreter more time not less.
I might be mistaken, but I thought that the interpreter would spot the first IF statement is false, and therefore step over statements until it found (ELSE, END IF or the end of the line); whereas with IF test>0 AND test2<3 THEN xx it has to check both whether both statements are true before searching for the ELSE, END IF or end of line.

I just did a very quick test of only a 200000 iteration loop, although on an emulator it is hard to compare (because the processor can be busy doing other things) and both approaches took nearly the same amount of time 47 seconds for IF... AND.... and 46 seconds for IF.... IF..... (ran the program twice for each test with the same results).


User avatar
NormanDunbar
Forum Moderator
Posts: 2251
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: QL Tinkering

Post by NormanDunbar »

Evening all,
RWAP wrote:Great so we have the start of a new chapter for the SBASIC/SuperBASIC Reference Manual on writing SuperBASIC programs for speed - now all we need is for someone to volunteer to pull it together and create the chapter... :D
Well, if someone, individual or group, gets a chapter written up in text format, bung it in my direction, and I'll write it up in Sphinx-doc for the online manual.

Speaking of which, two things:

1. Github are changing how things can be linked to your repository which might break the automatic build at ReadTheDocs. Time will tell if the new system can be linked to do such things.

2. Someone, me, is working on a utility that will read a text file and convert it to the required format for the online manual. It's a WIP at the moment. Watch this space --->[ ] ;)

Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
qbits
Trump Card
Posts: 171
Joined: Sun Dec 11, 2016 3:32 pm

Re: QL Tinkering

Post by qbits »

Hi,
WRAP thank you for bringing your SuperBASIC tricks to light... and provoking the thoughts... and maybe a new chapter...

Your results on composite AND or nested IFs does seem to bear you out. It must be the way the Interpreter accesses the keywords IF and AND...

If anyone’s serious about this new chapter for SBASIC/SuperBASIC reference Manual Norman here’s my contribution for starters...

QL SuperBASIC Interpreter Parsing
SuperBASIC is Procedure-based each uniquely named and being a set of directions required to reach a desired objective. Many of the SuperBASIC commands are themselves implemented as Procedures (PRINT, PAPER etc.) Structural commands are defined as Keywords (For, Select etc) and the remainder are Functions. The actions of a Function being similar to a Procedure, except it always returns a single value and can only be used in an expression (ie. PI).

Working with Procedures and Variable names it would be very time consuming and inefficient for the Interpreter in trying to execute a command when it had to run through the entire program checking where a procedure or variable name existed and what its value was. The process of checking of each element is parsing and when a Program written in QL SuperBASIC is first RUN each element of a numbered line is checked against the SuperBASIC language syntax. When a line parses satisfactorily it is absorbed into the current program with the variables and procedures names being held in a tokenised form.

There are three separate areas where details about the names are kept: the nametable, the namelist and the variable values. The namelist is, as it sounds, merely a continuous list of names. Each one is in the form, length of name, characters in name. The maximum number of characters in a name is 127 and names cannot start with a number. The nametable is the hub of the whole SuperBASIC system. It is an orderly sequence of entries each refers to one entry name and consists of the following information:

Type of name 1 byte - where the nametype is a code representing variable, procedure etc.
Type of variable if applicable 1 byte - the variabletype is a code representing floating point, string or integer.
Offset of name in namelist 2 bytes - the offset to namelist is, for example, 0 for PRINT, 6 for RUN etc.
Pointer to associated information 4 bytes - this might be the value of a variable or the position of a procedure. It depends on the type of name.

The variable values is a free space pointer to unused space in the area of memory usually referred to as the heap. SuperBASIC calls upon the free space manager to allocate a required area and its position. Because this area can be freed, each entry contains its length and a pointer to the next free space. The minimum size is eight bytes and larger areas of memory are allocated in multiples of eight bytes. Reassigning values to floating point or integers is simply a matter of changing the previously stored entry. For string variables if the old and new occupy the same number of allocated bytes it is simple change. However, if the string lengths differ, first the old space must be freed up and a new space requested. Arrays of floating point or integers are regular, String arrays are not entirely regular so the final dimension of a string array is the maximum size of each string in the array.

As the Interpreter parses a program if a name doesn’t already exist, it is added to the end of the namelist and a new entry created in the nametable to point to it. The number of the entry in the nametable which points to the name then forms part of the token used for that name in the internal arrangements of the program. Upper and lower case characters are considered equivalent so the form stored is that of the first time the name was entered.

SuperBASIC Interpreter Execution
Having finished parsing the program the Interpreter can now carry out execution running through the arranged order of SuperBASIC commands, named Procedures and statements using named variables. Each time it will use the namelist to identify and locate the area of program to execute. This places an opportunity to help minimise the Interpreters access by arranging the namelist such that the most called upon Procedures and variables are placed at the top and those least used are placed near the bottom.

Another action to minimise Interpreter time is the location of DATA statements. They may be put almost anywhere, but putting them at the very beginning of a program is the most efficient as the interpreter moving to a data item always starts from the top line of a program. If all the DATA statements are placed at the beginning of a program it lakes less time to find them.

Awaiting further input...

QBITS


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

Re: QL Tinkering

Post by RWAP »

Just an update - I thought I would run the same test program on QPC2 (ie under SMSQ/e) and even with SMSQ/E the IF x THEN IF y version is slightly quicker than IF x AND y

I also tried something different too - using integer variables in the FOR loop - now because I was doing 200,000 iterations, that means I had to use two FOR loops (as an integer variable can only hold a maximum of 32768). So I used an outer loop of 0 to 9 and an inner loop of 1 to 20000.

Here the overhead of the second loop slows down the program further than using a floating point variable, so the lesson is to only use integer loops where the value is always going to be in the range -32767 to 32768 and not try to be clever by using two loops.


User avatar
mk79
QL Wafer Drive
Posts: 1349
Joined: Sun Feb 02, 2014 10:54 am
Location: Esslingen/Germany
Contact:

Re: QL Tinkering

Post by mk79 »

RWAP wrote:Just an update - I thought I would run the same test program on QPC2 (ie under SMSQ/e) and even with SMSQ/E the IF x THEN IF y version is slightly quicker than IF x AND y
The technical term is "short circuit evaluation", which is employed by most programming languages but unfortunately not SuperBasic. SuperBasic always evaluates both AND terms even if it's clear after the first term that the AND condition cannot become true. That's where a nested IF can make sense, but it's semantically not the same as AND in case the second term has side-effects (function call).

Marcel


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

Re: QL Tinkering

Post by stevepoole »

Hi there,
Many years ago I wrote a small piece of SuperBasic code placed at the beginning of a program to test timings of all the different SB statements.
I sent the results off to Quanta, the most surprising of which was that (LET) assignements were very slow operations compared even to say divisions. I assume that this is because the bus takes more time to send or fetch values from memory than accessing registers. So to speed up programs, use as few assignments as Possible. This makes for poor clarity, but is essential in inner loops.

Now for my question ... Do LOCal values (or parameters) make any use of Cache memory ? That would make sense...

( By the way, the code timer is of little value on Emulators, since PCs have so many overheads, wheras the QL often didn't need to multitask! )

Regards,
Steve Poole.


User avatar
mk79
QL Wafer Drive
Posts: 1349
Joined: Sun Feb 02, 2014 10:54 am
Location: Esslingen/Germany
Contact:

Re: QL Tinkering

Post by mk79 »

stevepoole wrote:Hi there,
Many years ago I wrote a small piece of SuperBasic code placed at the beginning of a program to test timings of all the different SB statements.
I sent the results off to Quanta, the most surprising of which was that (LET) assignements were very slow operations compared even to say divisions. I assume that this is because the bus takes more time to send or fetch values from memory than accessing registers.
SBasic variables are never held in registers.
Now for my question ... Do LOCal values (or parameters) make any use of Cache memory ? That would make sense...
There are no caches (besides the data caches on 68040+ maybe).

Marcel


Post Reply