|
Post by atomose on Aug 1, 2022 9:11:27 GMT -5
Hi every one, I found a strange thing on LB. I show you the code into the file, you can test it as well. When you use the normal syntax : - with timer version : 50-55 fps on the majority of computers - with goto version : 60-64 fps on the majority of computers but you lose keyboard system. - The stranger version ^^ : 120-140 fps on all computers Into the code, i creat a fake sprite (i dont have the sprite i want to make a error with this line) but ... this will not crash the game. Just before it, i use "an error goto [whereIwant]" and this make me a goto faster than the "true" goto. So i dont have a error but a game performance improved by 200-300% ... You can change the line into the code a put a simple goto or timer and you will see the difference. How is it possible ? why the initial goto dont use it for better performance ?? thx .BAS file : HERE.BAS file + EXE + DATA : HERE
|
|
bplus
Full Member
 
Posts: 123
|
Post by bplus on Aug 1, 2022 10:52:18 GMT -5
That sounds really interesting! Is there a chance you can simplify the demo down from 120 KB to 1?
Don't really want to wade through that much code to figure out the trick. I wonder if it might be applied to drawing graphics?
|
|
|
Post by atomose on Aug 1, 2022 11:08:36 GMT -5
i can on some lines  (just put your code in the "...." space) Normal code :
[endLEVEL] ... ... goto [endLEVEL] or [endLEVEL] timer 0 ... ... timer 100, [endLEVEL] : wait
error code :
[endLEVEL] ... ... on error goto [endLEVEL] print #main.map,"removesprite fakeSPRITE";test;" fakeSPRITE" : wait ' here we remoove a fake sprite to have a error and jump
|
|
|
Post by Rod on Aug 1, 2022 11:13:43 GMT -5
I have not had time to look at the code yet. The overhead of the timer has always slowed things down. You get reliable smooth animation but paced at the minimum timer tick of 16ms.
A go to loop is much faster and can still read the keyboard if scan is used. The downside is that you are drawing at Windows paced speed which is noticeably jerky. It isn’t timed it is paced by processor cycles handed out by Windows.
Not drawing at all will of course be much faster still. Drawing on a Windows 64bit or 32bit screen which is just one of many surfaces in play is what holds us back. Getting a pixel drawn is no mean feat. Long gone are the days of directly addressable 8bit screens measuring a few hundred pixels.
|
|
|
Post by atomose on Aug 1, 2022 11:31:43 GMT -5
thx but, i my code, i drawn a lot of sprite every second. I add, draw and remoove sprite in the code and a the end, i use the error for speed up the "goto" function. You really should look the code in the file demo. You will se what i mean (im not really good in english so i can really explain)
|
|
|
Post by Carl Gundel on Aug 1, 2022 16:14:23 GMT -5
thx but, i my code, i drawn a lot of sprite every second. I add, draw and remoove sprite in the code and a the end, i use the error for speed up the "goto" function. You really should look the code in the file demo. You will se what i mean (im not really good in english so i can really explain) interesting. If you can demonstrate with the simplest example, check to see if the LB5 alpha does the same.
|
|
|
Post by Chris Iverson on Aug 1, 2022 18:59:44 GMT -5
Heh, reminds me of the story of "the hunt for a faster syscall trap", from one of the Microsoft Windows developers. A syscall trap is an instruction that gets executed that causes the CPU to change execution modes, usually between privilege levels, to allow the system to take over for some action that needs a higher level of access than the current code has. The story is here: devblogs.microsoft.com/oldnewthing/20041215-00/?p=37003The gist is that, in the early 90's, in the day of the 386 processor, Intel and Microsoft were having a meeting discussing the development of the processor. Intel asked Microsoft, "if you could choose one thing to be made faster, what would it be?" One of the Windows kernel devs immediately replied "Speed up faulting on an invalid instruction." The Intel guys thought it was a joke, until they profiled the Windows kernel, and found that it DOES spend a lot of time executing invalid instructions. Why? Well, while executing various Windows programs, the execution level of the CPU would have to change. And when the system needed to take over again, the execution level would need to be changed back. And it turned out that, while profiling all the various ways they could get from one execution to another(in this case, V86-mode to kernel-mode), they found that the fastest way to do so was to execute an invalid instruction, which would cause the processor to fault into a kernel-mode error handler. So that's how they implemented their switch-to-kernel-mode call back then.
|
|
|
Post by Carl Gundel on Aug 1, 2022 19:37:37 GMT -5
it turned out that, while profiling all the various ways they could get from one execution to another(in this case, V86-mode to kernel-mode), they found that the fastest way to do so was to execute an invalid instruction, which would cause the processor to fault into a kernel-mode error handler. So that's how they implemented their switch-to-kernel-mode call back then. LOL! I love it! 🤣
|
|
|
Post by Rod on Aug 2, 2022 4:09:36 GMT -5
I have still to look at the code. I pulled this demo together that displays a sprite using a timed loop, a simple loop and an on error loop. It shows a couple of concepts. Firstly that the timer is constrained by the Windows clock. It only changes its clockface once every 16ms so our timer can only react when the clock face changes. You will see the timer code react at 16ms and 32ms.
The timer adds overhead but the timing and pacing is welcome. Remember the display is updated quite slowly in relation to the processor speed, 50 or 60 frames per second, 17ms to 20ms. Animation can run slower. Run any faster and you are wasting your time. The graphics you create wont ever be seen on screen.So my point is that we don't want to loop faster than say 60fps
But we would all like to draw more, faster. Can this happen? I have my doubts but I still need to look at the code. This demo shows me that the simple loop is slightly faster than the error loop but both those loops are not surprisingly a lot faster than the timed, paced loop.
Now off to look at the code and try and see what is going on.
'nomainwin WindowWidth = 600 WindowHeight = 400 open "Meson" for graphics_nsb_nf as #1 #1, "trapclose [quit]"
' make meson sprite and save to memory #1, "down" #1, "color white; backcolor white" #1, "place 0 0" #1, "boxfilled 30 30" #1, "color black; backcolor black" #1, "Place 0 30" #1, "boxfilled 30 60" #1, "color pink; backcolor pink" #1, "place 15 45; circlefilled 12" #1, "color black; backcolor black" #1, "place 15 15; circlefilled 12" #1, "getbmp meson 0 0 30 60"
' make simple background and set up sprite #1, "fill white" #1, "getbmp bg 0 0 600 400" #1, "background bg" #1, "addsprite meson meson" #1, "spritexy meson 0 200"
' draw the sprite #1, "drawsprites"
degreex=-4 incrementx=4 x=0 degreey=-8 incrementy=8 degreez=-8 incrementz=8
print "We will run on a timer from 1 to 33 ms note the 16ms increments." for n=1 to 33 st=time$("ms") counter=0
timer n, [Drawit] wait
[Drawit] pos=pos+1 if pos>600 then pos=0 degreex=degreex+incrementx if degreex>359 then degreex=0 y=Int((sin(degreex/57.29577951)*100)+200) degreey=degreey+incrementy if degreey>359 then degreey=0 x=Int((sin(degreey/57.29577951)*20)+pos) degreez=degreez+incrementz if degreez>359 then degreez=0 z=Int((sin(degreey/57.29577951)*20)+100) #1 "spritescale meson ";z #1 "spritexy meson ";x;" ";y #1 "drawsprites" counter=counter+1 if counter>=100 then timer 0 : goto [done] wait
[done] t=(time$("ms")-st)/100 print n,t
next timer 0 print "Now we run untimed simply looping back"
counter=0 st=time$("ms")
[loopback] pos=pos+1 if pos>600 then pos=0 degreex=degreex+incrementx if degreex>359 then degreex=0 y=Int((sin(degreex/57.29577951)*100)+200) degreey=degreey+incrementy if degreey>359 then degreey=0 x=Int((sin(degreey/57.29577951)*20)+pos) degreez=degreez+incrementz if degreez>359 then degreez=0 z=Int((sin(degreey/57.29577951)*20)+100) #1, "spritescale meson ";z #1, "spritexy meson ";x;" ";y #1,"drawsprites" counter=counter+1 if counter>100 then goto [doneit] goto [loopback]
[doneit] t=(time$("ms")-st)/100 print "loopback ms ";t
print "Now the error loopback" counter=0 st=time$("ms")
[errorback] pos=pos+1 if pos>600 then pos=0 degreex=degreex+incrementx if degreex>359 then degreex=0 y=Int((sin(degreex/57.29577951)*100)+200) degreey=degreey+incrementy if degreey>359 then degreey=0 x=Int((sin(degreey/57.29577951)*20)+pos) degreez=degreez+incrementz if degreez>359 then degreez=0 z=Int((sin(degreey/57.29577951)*20)+100) #1, "spritescale meson ";z #1, "spritexy meson ";x;" ";y #1,"drawsprites" counter=counter+1 if counter>100 then goto [doneitagain] on error goto [errorback] #1,"removesprite fakeSPRITE";test;" fakeSPRITE" : wait ' here we remoove a fake sprite to have a error and jump
[doneitagain] t=(time$("ms")-st)/100 print "errorback ms ";t wait
[quit] timer 0 close #1 end
|
|
|
Post by atomose on Aug 2, 2022 5:34:37 GMT -5
hi rod,
have you try this ? (funny ^^)
(thx Chris for explanation)
'''''''''''''''''''''' if counter>100 then goto [doneitagain] '''''' dont put it on error goto [errorback] #1,"removesprite fakeSPRITE";test;" fakeSPRITE" ' here we remoove a fake sprite to have a error and jump wait
''''''''''' dont put this part [doneitagain] t=(time$("ms")-st)/100 print "errorback ms ";t wait
|
|
|
Post by Rod on Aug 2, 2022 6:02:35 GMT -5
Well both loops still run pretty much the same speed. Here they run for longer. Yes looping back is much much faster than a timed loop. But it is unusable is it not?
I have tried to look at your code but even if I insert a goto [endLEVEL] just ahead of your on error code the code wont loop and stops on pass$="1" so I have not been able to test loop changes on your code. If it is a straightforward loop I should be able to loop to [endLEVEL] with goto or a timer but neither will run. So not sure what is going on.
Bottom line for me is that drawing code runs at drawing code speed which is fast. You can have drawing code that takes longer than you wish but I doubt you can loop before it is finished or without missing code. Possibly you could be missing out a lot of unwinding if then case if nesting but doing so must surely kill the code.
I think you need to code us a simpler example.
'nomainwin WindowWidth = 600 WindowHeight = 400 open "Meson" for graphics_nsb_nf as #1 #1, "trapclose [quit]"
' make meson sprite and save to memory #1, "down" #1, "color white; backcolor white" #1, "place 0 0" #1, "boxfilled 30 30" #1, "color black; backcolor black" #1, "Place 0 30" #1, "boxfilled 30 60" #1, "color pink; backcolor pink" #1, "place 15 45; circlefilled 12" #1, "color black; backcolor black" #1, "place 15 15; circlefilled 12" #1, "getbmp meson 0 0 30 60"
' make simple background and set up sprite #1, "fill white" #1, "getbmp bg 0 0 600 400" #1, "background bg" #1, "addsprite meson meson" #1, "spritexy meson 0 200"
' draw the sprite #1, "drawsprites"
degreex=-4 incrementx=4 x=0 degreey=-8 incrementy=8 degreez=-8 incrementz=8
print "Now we run untimed simply looping back"
counter=0 st=time$("ms")
[loopback] pos=pos+1 if pos>600 then pos=0 degreex=degreex+incrementx if degreex>359 then degreex=0 y=Int((sin(degreex/57.29577951)*100)+200) degreey=degreey+incrementy if degreey>359 then degreey=0 x=Int((sin(degreey/57.29577951)*20)+pos) degreez=degreez+incrementz if degreez>359 then degreez=0 z=Int((sin(degreey/57.29577951)*20)+100) #1, "spritescale meson ";z #1, "spritexy meson ";x;" ";y #1,"drawsprites" counter=counter+1 if counter>10000 then goto [doneit] goto [loopback]
[doneit] t=(time$("ms")-st)/10000 print "loopback ms ";t
print "Now the error loopback" counter=0 st=time$("ms")
[errorback] pos=pos+1 if pos>600 then pos=0 degreex=degreex+incrementx if degreex>359 then degreex=0 y=Int((sin(degreex/57.29577951)*100)+200) degreey=degreey+incrementy if degreey>359 then degreey=0 x=Int((sin(degreey/57.29577951)*20)+pos) degreez=degreez+incrementz if degreez>359 then degreez=0 z=Int((sin(degreey/57.29577951)*20)+100) #1, "spritescale meson ";z #1, "spritexy meson ";x;" ";y #1,"drawsprites" counter=counter+1 if counter>10000 then goto [doneitagain] on error goto [errorback] #1,"removesprite fakeSPRITE";test;" fakeSPRITE" : wait ' here we remoove a fake sprite to have a error and jump
[doneitagain] t=(time$("ms")-st)/10000 print "errorback ms ";t wait
[quit] timer 0 close #1 end
|
|
|
Post by Rod on Aug 2, 2022 6:16:51 GMT -5
Ok I bypassed pass$ and managed to change the loop. I just used goto [endLEVEL]. I also timed a single pass through the loop. Amazingly all that code computes in 16ms or so. That's the code speed and that defines the loop speed. Your loop executes at 16ms intervals using GOTO and at 16ms intervals using ON ERROR so I am finding no difference. Unless you can show differently.
|
|
|
Post by atomose on Aug 2, 2022 12:46:25 GMT -5
I just redid the test and indeed the "goto" seems to work as fast as the error on the code I gave above. I noticed the difference on my main code (I gave you an example of 1800 lines whereas the real code is more than 10000) so it is possible that the size of the loop impacts the performance, or that the error remove part of the loop (I'll review it more closely) ... As for the "timer", no doubt, whatever the code size, it is extremely slow. i will come back with more informations about the "big code" optimisation ^^.
|
|
|
Post by Rod on Aug 2, 2022 13:26:00 GMT -5
The timer has nothing to do with it. It introduces a small overhead and paces code at the fastest, 16ms. If your code takes longer to execute you need to set the timer to a larger increment of 16ms. 32ms or 48ms
If 2000 lines of code takes 16ms then 10000 lines is going to take five times as long and the timer needs set at 100ms or so.
So you probably need to loop rather than time and you need to start looking at optimising your code.
Time a single iteration of your code to see what the realistic repetition rate is. If it is too long you need to think about running some code every second or third or fifth cycle.
To be clear, the timer is not slow, the length of code dictates the cycle time.
|
|