+FarmerPotato Posted July 1, 2022 Share Posted July 1, 2022 18 hours ago, pixelpedant said: I saw what you did there… CALL ERR indeed. 1 Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted July 1, 2022 Share Posted July 1, 2022 11 hours ago, pixelpedant said: There is no performance advantage in putting multiple statements on a line in XB. Oh, I thought it was said, that looking up line-numbers was a somewhat significant overhead !? 1 Quote Link to comment Share on other sites More sharing options...
pixelpedant Posted July 1, 2022 Author Share Posted July 1, 2022 1 hour ago, sometimes99er said: Oh, I thought it was said, that looking up line-numbers was a somewhat significant overhead !? Well, I suppose I shouldn't say there is no performance overhead, but in the practical context and scale of BASIC timing with which I'm concerned, it's never been a substantive one in my testing. I was curious nonetheless to dig deeper, so I just did a long enough test to see a difference (20,000 loops), and the difference between Z=1 Q=0 and Z=1::Q=0 was 0.3ms, in that test. So while that's something, it still falls below my threshold of interest, in a language where a PRINT X takes 90ms. But just because I don't care doesn't mean it isn't there! 1 Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted July 1, 2022 Share Posted July 1, 2022 (edited) 4 hours ago, pixelpedant said: Well, I suppose I shouldn't say there is no performance overhead, but in the practical context and scale of BASIC timing with which I'm concerned, it's never been a substantive one in my testing. I was curious nonetheless to dig deeper, so I just did a long enough test to see a difference (20,000 loops), and the difference between Z=1 Q=0 and Z=1::Q=0 was 0.3ms, in that test. So while that's something, it still falls below my threshold of interest, in a language where a PRINT X takes 90ms. But just because I don't care doesn't mean it isn't there! Ok. Thanks. ? Often in XB you have / could have more statements on one line than just two ... Edited July 1, 2022 by sometimes99er Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted July 1, 2022 Share Posted July 1, 2022 (edited) It does make a difference when you GOTO or GOSUB. From the thread "What are the impacts of line numbering in Basic/XB execution speed" (Post #98) Getting back on the subject, (at last) I made a ridiculous program of 1601 lines. 1 X=X+1::GOSUB 2::GOTO 1 2 RETURN 3 ! 4 ! (Lines 3=1599 are comments) 1599 ! 1600 X=X+1::GOSUB 1601::GOTO 1600 1601 RETURN In 30 seconds: RUN 1 loops 125 times RUN 1600 loops 3421 times. Note that there is 1 GOSUB and 1 GOTO per loop. So there is definitely a speed advantage when going to a higher number line. Obviously, the example program is a little extreme. To fit 1600 lines into 24K, each line would average 15 bytes, and 6 of those are used for the line #, length byte and trailing zero. In the real world a really long program might be 400 lines, which would average around 54 bytes of code per line, so this effect would not be so extreme. I think this is true for Basic as well, but you might want to check to be sure. I think this order is true for Basic as well. (i.e. the higher line numbers are found more quickly than the lower line numbers) But you might want to check to be sure. Edited July 1, 2022 by senior_falcon Quote Link to comment Share on other sites More sharing options...
speccery Posted July 23, 2022 Share Posted July 23, 2022 (edited) Watched some of @pixelpedant's great videos yesterday. Hell's halls is truly amazing in TI BASIC. I took a look at the spreadsheet with Basic timing. My results (running on real iron) varied a little from those. I was testing CALL CHAR in loops, like this: This takes just under 25 seconds. I then assigned the string constant to A$ before the loop and the execution time dropped to about 22.5 seconds. It appears a single loop iteration (i.e. running NEXT) takes something like 3.5 milliseconds (or an empty loop of 1000 iterations is around 3.5 seconds), so with 201 iterations we're talking about 0.7 seconds for the loop alone. With that CALL CHAR(32,A$) appears to take about 108 ms, somewhat less than what the very nice BASIC execution time spreadsheet indicates. Still the difference is only about 10% and falls in the margin of error. Anyway CALL CHAR is just very very slow at 100ms+ for a single character. Compared to CALL CLEAR (44ms according to the table) it is just miserably slow. CALL CLEAR does not have to deal with argument evaluation, which just goes to show how slow that is. The payload of CALL CLEAR is 768 writes to VDP memory, the payload of CALL CHAR is 8 writes... In practice processing of CALL CHAR probably contains a ton of VDP activity just to evaluate the arguments. I have earlier measured that the TMS9900 runs at around 0.13 MIPS or something like that, meaning that a single CALL CHAR is around 14 000 machine code instructions. Wow. This makes me feel humbled and really just highlights how amazing great TI BASIC games like Hell's hall are. Edited July 23, 2022 by speccery 4 Quote Link to comment Share on other sites More sharing options...
RXB Posted July 23, 2022 Share Posted July 23, 2022 On 6/30/2022 at 10:06 PM, pixelpedant said: Well, I suppose I shouldn't say there is no performance overhead, but in the practical context and scale of BASIC timing with which I'm concerned, it's never been a substantive one in my testing. I was curious nonetheless to dig deeper, so I just did a long enough test to see a difference (20,000 loops), and the difference between Z=1 Q=0 and Z=1::Q=0 was 0.3ms, in that test. So while that's something, it still falls below my threshold of interest, in a language where a PRINT X takes 90ms. But just because I don't care doesn't mean it isn't there! So are you saying Line Numbers are faster then :: as there are several steps to go to next line number unlike :: that is only the next byte. As the line is being processed it is already on the correct address for next byte with :: unlike a line number that has to be switched and that takes time. As for PRINT is slow as it has way to many options so slow down the program. This is why I made CALL HPUT(row,column,variable[,...]) Also why DISPLAY AT(row,column) was put into XB to speed it up, problem is they screwed up and used same code making it worse. Quote Link to comment Share on other sites More sharing options...
RXB Posted July 23, 2022 Share Posted July 23, 2022 On 7/1/2022 at 8:58 AM, senior_falcon said: It does make a difference when you GOTO or GOSUB. From the thread "What are the impacts of line numbering in Basic/XB execution speed" (Post #98) Getting back on the subject, (at last) I made a ridiculous program of 1601 lines. 1 X=X+1::GOSUB 2::GOTO 1 2 RETURN 3 ! 4 ! (Lines 3=1599 are comments) 1599 ! 1600 X=X+1::GOSUB 1601::GOTO 1600 1601 RETURN In 30 seconds: RUN 1 loops 125 times RUN 1600 loops 3421 times. Note that there is 1 GOSUB and 1 GOTO per loop. So there is definitely a speed advantage when going to a higher number line. Obviously, the example program is a little extreme. To fit 1600 lines into 24K, each line would average 15 bytes, and 6 of those are used for the line #, length byte and trailing zero. In the real world a really long program might be 400 lines, which would average around 54 bytes of code per line, so this effect would not be so extreme. I think this is true for Basic as well, but you might want to check to be sure. I think this order is true for Basic as well. (i.e. the higher line numbers are found more quickly than the lower line numbers) But you might want to check to be sure. Why would higher line numbers be faster? All line numbers in Basic or XB are a 1 word value >0001 to >7FFF is valid and >8000 to >FFFF is not valid line numbers. So are you saying line number >7FE0 is faster than line number >0032 ? Also XB and Basic both have exactly the same set up for String Variables, but XB uses upper 24K for Numeric Variables for the number itself storage. Not really much of an advantage considering X=9 takes 17 bytes in Basic or XB, with XB 32K having the FP 8 bytes in RAM instead of VDP. Quote Link to comment Share on other sites More sharing options...
RXB Posted July 23, 2022 Share Posted July 23, 2022 9 hours ago, speccery said: Watched some of @pixelpedant's great videos yesterday. Hell's halls is truly amazing in TI BASIC. I took a look at the spreadsheet with Basic timing. My results (running on real iron) varied a little from those. I was testing CALL CHAR in loops, like this: This takes just under 25 seconds. I then assigned the string constant to A$ before the loop and the execution time dropped to about 22.5 seconds. It appears a single loop iteration (i.e. running NEXT) takes something like 3.5 milliseconds (or an empty loop of 1000 iterations is around 3.5 seconds), so with 201 iterations we're talking about 0.7 seconds for the loop alone. With that CALL CHAR(32,A$) appears to take about 108 ms, somewhat less than what the very nice BASIC execution time spreadsheet indicates. Still the difference is only about 10% and falls in the margin of error. Anyway CALL CHAR is just very very slow at 100ms+ for a single character. Compared to CALL CLEAR (44ms according to the table) it is just miserably slow. CALL CLEAR does not have to deal with argument evaluation, which just goes to show how slow that is. The payload of CALL CLEAR is 768 writes to VDP memory, the payload of CALL CHAR is 8 writes... In practice processing of CALL CHAR probably contains a ton of VDP activity just to evaluate the arguments. I have earlier measured that the TMS9900 runs at around 0.13 MIPS or something like that, meaning that a single CALL CHAR is around 14 000 machine code instructions. Wow. This makes me feel humbled and really just highlights how amazing great TI BASIC games like Hell's hall are. The reason why a CALL CHAR(32,"007F41414141417F") is slower then CALL CHAR(32,A$) is the interpreter has to load the first one's string into a temp buffer. Whereas the second only has to go to the address of the string and use it. Anything using VDP is slower than RAM as you get wait cycles to use VDP unlike RAM. (Also you can only write 1 byte at a time unlike RAM) 2 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted July 24, 2022 Share Posted July 24, 2022 9 hours ago, RXB said: Why would higher line numbers be faster? All line numbers in Basic or XB are a 1 word value >0001 to >7FFF is valid and >8000 to >FFFF is not valid line numbers. So are you saying line number >7FE0 is faster than line number >0032 ? It's not the actual line number that matters, it's where it is in the program. The program example that I gave has 1601 lines. If you look at the program you will see that line 1 is exactly the same as line 1600 except for the line numbers, yet RUN 1 is much slower than RUN 1600. So yes, going to a higher line number in the program is faster than going to a lower line number in the program. Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted July 24, 2022 Share Posted July 24, 2022 10 hours ago, RXB said: The reason why a CALL CHAR(32,"007F41414141417F") is slower then CALL CHAR(32,A$) is the interpreter has to load the first one's string into a temp buffer. Whereas the second only has to go to the address of the string and use it. Nope. It is because A$ is 2 bytes long and 007f41414141417F is 16 bytes long. If you make the variable and the string the same length you will find that using the variable is a tiny bit slower. (about 1%) The variable can be AAAAAAAAAAAAAAA$ or the string can be "FF" 2 Quote Link to comment Share on other sites More sharing options...
RXB Posted July 24, 2022 Share Posted July 24, 2022 1 hour ago, senior_falcon said: It's not the actual line number that matters, it's where it is in the program. The program example that I gave has 1601 lines. If you look at the program you will see that line 1 is exactly the same as line 1600 except for the line numbers, yet RUN 1 is much slower than RUN 1600. So yes, going to a higher line number in the program is faster than going to a lower line number in the program. I can find nothing in GPL or Assembly ROMs that would explain this difference. The only possibility is the line number table but as it is sequential the only delay would be a GOTO to find that Line Number. Do know why this could possibly be true? Quote Link to comment Share on other sites More sharing options...
RXB Posted July 24, 2022 Share Posted July 24, 2022 45 minutes ago, senior_falcon said: Nope. It is because A$ is 2 bytes long and 007f41414141417F is 16 bytes long. If you make the variable and the string the same length you will find that using the variable is a tiny bit slower. (about 1%) The variable can be AAAAAAAAAAAAAAA$ or the string can be "FF" First off they use the same string to be loaded at the character so no that would not make it slower. An Assembly ROM routine finds the A$ in the Variable list and points to it. (FBSYMB is the routine in XB ROMs that does this.) On the other hand, a string has to have a temporary VDP buffer of that string added to VDP tables and used, this is mostly GPL with some Assembly too. There are like 20 more instructions to be done in GPL for a STRING vs Assembly ROM for a String variable. And longer variable names take longer to find and use as even you have even stated this one. Can you show the GPL or Assembly code that would explain this difference you see? Quote Link to comment Share on other sites More sharing options...
Willsy Posted July 24, 2022 Share Posted July 24, 2022 Presumably it's a linked list that has to be "walked" from the beginning to find a particular line number. Quote Link to comment Share on other sites More sharing options...
speccery Posted July 24, 2022 Share Posted July 24, 2022 (edited) 5 hours ago, Willsy said: Presumably it's a linked list that has to be "walked" from the beginning to find a particular line number. In TI BASIC a bit surprisingly it's not like that, there is no linked list. Just an array, with two 16-bit values per entry. One entry is the line number, the other pointer to the line's tokens. I guess it points to the length byte of the line. So in TI BASIC you don't need to do pointer chasing, and like someone pointed out - I forget who and in which thread - if you renumbered the lines of the program with a constant interval - such as 1 ? you could find any line in a GOTO situation in fixed time with a single lookup. I don't think TI BASIC does such a thing, but would be a good way to optimise. Most other BASICs I've looked at (Commodore, Sinclair) don't have the line number table as an array of fixed length entries, but they store that information among the tokenised BASIC program code, so you need to traverse a linked list of the program lines to find anything. Of course TI BASIC makes this also special in that the line number table is stored in the VDP memory... Edited July 24, 2022 by speccery Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted July 24, 2022 Share Posted July 24, 2022 8 hours ago, RXB said: First off they use the same string to be loaded at the character so no that would not make it slower. An Assembly ROM routine finds the A$ in the Variable list and points to it. (FBSYMB is the routine in XB ROMs that does this.) On the other hand, a string has to have a temporary VDP buffer of that string added to VDP tables and used, this is mostly GPL with some Assembly too. There are like 20 more instructions to be done in GPL for a STRING vs Assembly ROM for a String variable. And longer variable names take longer to find and use as even you have even stated this one. Can you show the GPL or Assembly code that would explain this difference you see? In post #59, you explained why using a string variable for the pattern was faster. I stated that the real reason it is faster is because A$ is 2 bytes long, and the string was 16 bytes long. This program shows that. 100 OPEN #1:"CLOCK" :: INPUT #1:A$,B$,C$ 110 X$="FF" 120 FOR I=1 TO 1000 :: CALL CHAR(32,X$):: NEXT I 130 INPUT #1:D$,E$,F$ :: PRINT A$,D$:B$,E$,C$,F$ Try this with CALL CHAR(32,X$) and CALL CHAR(32,"FF") Or you can change the program to use a 15 byte long variable name XXXXXXXXXXXXXX$=" and a 15 byte long pattern Either way, when the string and the variable name are the same length, you will see that the direct string is a wee bit faster than using the variable. For the GPL or Assembly code that would explain this, I will quote Mr. Spock's words to Scottie. "I note it, Mr. Scott, without necessarily understanding it." Quote Link to comment Share on other sites More sharing options...
RXB Posted July 24, 2022 Share Posted July 24, 2022 5 hours ago, senior_falcon said: In post #59, you explained why using a string variable for the pattern was faster. I stated that the real reason it is faster is because A$ is 2 bytes long, and the string was 16 bytes long. This program shows that. 100 OPEN #1:"CLOCK" :: INPUT #1:A$,B$,C$ 110 X$="FF" 120 FOR I=1 TO 1000 :: CALL CHAR(32,X$):: NEXT I 130 INPUT #1:D$,E$,F$ :: PRINT A$,D$:B$,E$,C$,F$ Try this with CALL CHAR(32,X$) and CALL CHAR(32,"FF") Or you can change the program to use a 15 byte long variable name XXXXXXXXXXXXXX$=" and a 15 byte long pattern Either way, when the string and the variable name are the same length, you will see that the direct string is a wee bit faster than using the variable. For the GPL or Assembly code that would explain this, I will quote Mr. Spock's words to Scottie. "I note it, Mr. Scott, without necessarily understanding it." Ran your demo but changed 1000 to 10000 and first run confirmed your statement run time 3 seconds after 10,000 loop. Second run I changed to 110 X$="FFFFFFFFFFFFFFFF" and got 43:35 run time. Then I changed CALL CHAR(32,X$) into CALL CHAR(32,"FFFFFFFFFFFFFFFF") and got 43:35 run time. So no change at all after 10,000 loop guess I could test a 100,000 loop to see if something pops up. So CALL CHAR(32,X$) and CALL CHAR(32,"FFFFFFFFFFFFFFFF") confirmed what I had already stated that string variables more usable than hard coded strings. You have to re-write a XB program to change CALL CHAR(32,"FFFFFFFFFFFFFFFF") but X$="FFFFFFFFFFFFFFFF" is more fluid to use. The advantage is still to use String Variables overall as more benifits exist for them then hard coded strings. Quote Link to comment Share on other sites More sharing options...
RXB Posted July 24, 2022 Share Posted July 24, 2022 OK took over 3 hours to do 100,000 loop and results are in: X$="FFFFFFFFFFFFFFFF" took 3 hours 16 minutes and 5 seconds CALL CHAR(32,"FFFFFFFFFFFFFFFF") took 3 hours 16 minutes and 6 seconds. Thus String variable is not really a huge improvement at all, but is much more versatile and useful then hard coded strings. Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted July 25, 2022 Share Posted July 25, 2022 Sorry for mucking up this thread. All of my testing was done in XB, and of course the thread is about TI BASIC. I will try to be more observant next time. 3 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.