Page 1 of 1

Renumbering

Posted: Mon Mar 23, 2020 3:18 pm
by +3code
Hi,

I remember ever read that renumbering the lines of a BASIC program with 1 to 1 steps

1 bla
2 blabla
3 blablabla

goes a little faster than with 10 to 10 steps

10 bla
20 blabla
30 blablabla

but I don't notice any difference.

Does anyone know if it's true?

Re: Renumbering

Posted: Tue Mar 24, 2020 1:59 am
by djnzx48
Here are my results of testing this. This was the listing I used:

1 FOR a=1 TO 10
2 RESTORE 1
3 READ d
4 FOR b=1 TO 100
5 LET d=FN a(d)
6 NEXT b
7 PRINT d
8 NEXT a
9 DATA 100
10 DEF FN a(x)=x+1
11 PRINT PEEK 23672
12 RANDOMIZE USR 40000

I put a RET at address 40000 so I could detect when the program had finished.

I then took a snapshot just after typing RUN and pressing ENTER, and used the debugger to edit the program line numbers of each test. If I numbered the program in steps of 1 or 10, the timings were identical, down to the T-state. However, if I numbered the program in steps of 100, it actually executed faster. Assuming I didn't mess up the testing, my guess is that it has something to do with whether the high byte of the line number is zero (as for steps of 1 or 10), or non-zero (as for steps of 100).

Re: Renumbering

Posted: Tue Mar 24, 2020 2:09 am
by R-Tape
Oh wow. Good test. How much faster? Did it give a different clock value (23672), or was it a just a few tstates?

Re: Renumbering

Posted: Tue Mar 24, 2020 2:13 am
by djnzx48
The clock values were the same at the end when I ran it, but the PRINTs did produce different values. In total the difference was only around 16000 T-states.

Re: Renumbering

Posted: Tue Mar 24, 2020 8:34 am
by R-Tape
djnzx48 wrote: Tue Mar 24, 2020 2:13 am The clock values were the same at the end when I ran it, but the PRINTs did produce different values. In total the difference was only around 16000 T-states.
That's about 6 frames isn't it? Quite a lot.

Re: Renumbering

Posted: Tue Mar 24, 2020 8:56 am
by djnzx48
16000 T-states should be around a fifth of a frame. The whole test takes 13 seconds to run, so the difference is pretty minor, but it could provide a slight speedup for long-running programs.

Re: Renumbering

Posted: Tue Mar 24, 2020 9:14 am
by R-Tape
I'm an idiot. I don't usually work in tstates, and I confused my own timing units with them (my own timing units are the number of DEC BC, JR NZ loops something takes).

Re: Renumbering

Posted: Tue Mar 24, 2020 1:53 pm
by ZXDunny
BASin has a code profiler which will tell you precisely how many TStates each line of BASIC code takes.

Re: Renumbering

Posted: Tue Mar 24, 2020 8:35 pm
by djnzx48
R-Tape wrote: Tue Mar 24, 2020 9:14 am (my own timing units are the number of DEC BC, JR NZ loops something takes).
Oh, that makes sense now. Having your own units sounds like it would be useful - normally I have to calculate things like that manually for each timing loop.
ZXDunny wrote: Tue Mar 24, 2020 1:53 pm BASin has a code profiler which will tell you precisely how many TStates each line of BASIC code takes.
I considered using a tool such as BASin for testing, but I wasn't sure if they purely used the original ROM routines or hooked into them to run their own code.

Re: Renumbering

Posted: Tue Mar 24, 2020 11:01 pm
by ZXDunny
djnzx48 wrote: Tue Mar 24, 2020 8:35 pm
R-Tape wrote: Tue Mar 24, 2020 9:14 am (my own timing units are the number of DEC BC, JR NZ loops something takes).
Oh, that makes sense now. Having your own units sounds like it would be useful - normally I have to calculate things like that manually for each timing loop.
ZXDunny wrote: Tue Mar 24, 2020 1:53 pm BASin has a code profiler which will tell you precisely how many TStates each line of BASIC code takes.
I considered using a tool such as BASin for testing, but I wasn't sure if they purely used the original ROM routines or hooked into them to run their own code.
BASin hooks in to provide user input - INKEY$ and INPUT specifically are hooked to read the PC keyboard, though timings should not be affected. During runtime, the ROM runs pretty much uninterrupted aside from housekeeping tasks which happen invisibly to the emulated machine.

Re: Renumbering

Posted: Wed Mar 25, 2020 1:40 pm
by catmeows
djnzx48 wrote: Tue Mar 24, 2020 1:59 am Here are my results of testing this. This was the listing I used:

1 FOR a=1 TO 10
2 RESTORE 1
3 READ d
4 FOR b=1 TO 100
5 LET d=FN a(d)
6 NEXT b
7 PRINT d
8 NEXT a
9 DATA 100
10 DEF FN a(x)=x+1
11 PRINT PEEK 23672
12 RANDOMIZE USR 40000

I put a RET at address 40000 so I could detect when the program had finished.

I then took a snapshot just after typing RUN and pressing ENTER, and used the debugger to edit the program line numbers of each test. If I numbered the program in steps of 1 or 10, the timings were identical, down to the T-state. However, if I numbered the program in steps of 100, it actually executed faster. Assuming I didn't mess up the testing, my guess is that it has something to do with whether the high byte of the line number is zero (as for steps of 1 or 10), or non-zero (as for steps of 100).
My understanding is that every branch in Basic has to find the correct Basic line. Basic lines has most significant byte as first so I imagine the test "Is this correct line Basic line" would often fail early when lines are numbered in step 100. When lines are numbered in step of 1, the first byte would be always a success and therefore the second byte is always checked.
Considering there is 10*1000 branches in this case, the difference od 16k t-states seems quite fit in.
Or may be it is something else :)

Re: Renumbering

Posted: Wed Mar 25, 2020 10:14 pm
by djnzx48
I think you're right. The first divergence occurs in the CP_LINES routine here: https://skoolkid.github.io/rom/asm/1980.html

Therefore if you want the maximum benefit from this speedup (which is admittedly minor), you should number your program in steps of 256 so that each program line has a unique high byte. This does however limit your program to only 40 lines.