Menu

Performance differences between major releases.

Theruler76
2021-08-07
2021-09-07
  • Theruler76

    Theruler76 - 2021-08-07

    I'd like to know the technical details. I already read about deprecated libraries like pygame.
    The fact is that 1.2.14 is far faster then 2.0 branch.
    As example, paste a 60KB program into 1.2 happens almost instantly, in 2.0 it takes one minute or so.

    It is neither an issue nor a complaint, I use both versions depending on needs, just curious.

    Keep up the good work
    regards
    Stefano

     
  • Rob Hagemans

    Rob Hagemans - 2021-08-11

    Hi, thanks for your message. It's true that the 2.x branch is slower. The 1.x branch had become unmaintainable due to circular dependencies, in order to disentangle the code I have made large changes to the structure, including the use of threading to separate interface and engine. Unfortunately the code is not as highly optimised as the 1.x branch was.

     
  • Theruler76

    Theruler76 - 2021-08-12

    I know pygame and numpy are well known for their slowness (even if they have tricks to make some optimizations), so I would have expected the speed difference to be the opposite between the two branches, now I know why, thanks.
    I even noticed you compiled every .py files into pyc, that should make a slight speed increase, I do not know how much noticable is in a so complex program like yours (complexity that never stops to amazes me, sincerely).

    Could you enlight me on what circular dependencies actually caused to the programming flow of 1.2 branch?

    Do you have plans to migrate to Python 3.9? I see 2.0.x still uses 2.7 version, but I don't know if it would better benefit the code or not.

    Thank you for your patience.
    Stefano

     
    • Marc 'BlackJack' Rintsch

      2.0.x uses Python 2.7 if you install it for 2.7. Just install it for Python 3.

       
    • Rob Hagemans

      Rob Hagemans - 2021-08-12

      Actually, numpy is quite well optimized, and faster if you have the sort of task it is meant for - i.e. vectorised calculations. I removed it not so much for performance but to get rid of a large dependency (it was steadily ballooning and added something like 10 MiB to the package) and for maintainability - I want the basic functionality to be available using the python standard library only, but that meant having to maintain separate code for numpy and non-numpy installs and it was just not doable anymore. For similar reasons I'll get rid of the 1.x branch (i.e it'll become unsupported) and python 2.x - I just don't have the time to fix bugs and test on all different platforms. In the end, removing numpy didn't really hurt performance as loop comprehensions can be really fast, if well written. Re pygame, the bits I used were just an API on top of SDL so I removed the middle man. It was fine while it lasted but depended on an old SDL 1.2, and the SDL 2.0 version of pygame lacked some of the 8-bit features that I heavily used, so it wasn't worth migrating for me.

      The screen update speed is not CPU bound, it's slower because of the update cycle in the thread that the back-end now needs to wait for. You'll find e.g. in 1.x if you do a large listing it's nearly immediate, but you only seethe last few lines. In 2.x you will see it scrolling, which is closer to what GW-BASIC did.

      The dirty secret is that GW-BASIC under DOSbox is much faster than PC-BASIC, so if performance is your concern, you'd better use that. Python is just so much slower than compiled C.

      Re maintainability, 1.2 is just a total mess, seriously. You 'd notice once you try to make a change. The circular dependencies are just one example - this relates to module X importing module Y, while module Y in turn imports modules that depend on module X. That works, but as soon as you change something the import order can get changed and things may break, and it becomes horrible to debug.

      Including .pyc files only makes a difference on the first run, working from the source Python will produce .pyc files automatically and only rebuild them if there is a change to the source file.

      The 2.0 branch uses Python 3.x in the packages and if installed with pip3 - though I haven't yet tested on 3.9. I think 3.7 and 3.8 should work fine. 2.7 will be phased out at some point.

       
  • Justin R. Miller

    FWIW, though I didn't benchmark things, I've had good results using PyPy (https://www.pypy.org/) to run PC-BASIC with great speedups. Might be worth a shot depending upon needs.

     

    Last edit: Justin R. Miller 2021-08-12
    • Rob Hagemans

      Rob Hagemans - 2021-08-12

      Great tip, thanks! Did everything work or are there gaps? I seem to recall there used to be issues with ctypes under PyPy, but that was a while ago...

       
  • Theruler76

    Theruler76 - 2021-08-16

    Thanks Rob for your reply, much appreciated and clear.
    I tried your suggestion and used python 3.9; even if the program seemed to run a bit faster, there was a sort of lag. Something that should do with the way 3.9 handle the timings.

    Didn't tried pypy but if ctypes doesn't cause issues, integrate pypy libs into the windows package should help the project, I would say.

    I also noticed different memory management between 2.0 and 1.2.
    Same 600 lines/50KB program, with FRE(1) command, after RUN and CTRL-C , 2.0 reads 3215 (the exact same amount of GWBASIC v3.23), 1.2 reads 3034 Bytes free.

     
    • Rob Hagemans

      Rob Hagemans - 2021-08-17

      Thanks for checking, not sure what could cause the lag. Regarding the memory management - thanks for reporting, it's more or less expected that 1.2 performs differently. One of the big changes in the 2.0 branch is the way arrays and (in particular) strings are handled, in order to follow the behaviour of the original more closely. It's far from perfect though, some parts of how the memory allocation behaves in GW-BASIC I just haven't been able to understand so far.

       
  • Theruler76

    Theruler76 - 2021-08-26

    Just for fun I benchmarked three version with a simple FOR NEXT cycle, no math involved, just waits:

    10 FOR A=1 TO 10
    20 T1=TIMER
    30 FOR X=1 TO 100000:NEXT
    40 T2=TIMER
    50 T(A)=T2-T1:?T(A)
    60 NEXT:?"Average="(T(1)+T(2)+T(3)+T(4)+T(5)+T(6)+T(7)+T(8)+T(9)+T(10))/10

    Same hardware, win10 x64, i7-6700@3.4GHz - 16GB, ssd
    the average results are:

    v 1.2.14 win = 3.625 sec
    v 2.0.3 win = 4.234 sec
    v 2.0.3 python 3.9 x64 = 2.554 sec

    Unfortunately, I was not able to run it on PYPY, due to dependency fails with winsound. For the records:

    Traceback (most recent call last):
    File "d:\utility\pypy3.7-v7.3.5-win64\lib-python\3\runpy.py", line 196, in _run_module_as_main
    "main", mod_spec)
    File "d:\utility\pypy3.7-v7.3.5-win64\lib-python\3\runpy.py", line 85, in _run_code
    exec(code, run_globals)
    File "d:\utility\pypy3.7-v7.3.5-win64\Scripts\pcbasic.exe__main__.py", line 4, in <module>
    from pcbasic import main
    File "d:\utility\pypy3.7-v7.3.5-win64\site-packages\pcbasic__init__.py", line 18, in <module>
    from .main import run, main
    File "d:\utility\pypy3.7-v7.3.5-win64\site-packages\pcbasic\main.py", line 22, in <module>
    from .interface import Interface, InitFailed
    File "d:\utility\pypy3.7-v7.3.5-win64\site-packages\pcbasic\interface__init__.py", line 22, in <module>
    from .audio_beep import AudioBeep
    File "d:\utility\pypy3.7-v7.3.5-win64\site-packages\pcbasic\interface\audio_beep.py", line 18, in <module>
    import winsound # pylint: disable=import-error
    ModuleNotFoundError: No module named 'winsound'</module></module></module></module></module>

     

    Last edit: Theruler76 2021-08-26
  • Theruler76

    Theruler76 - 2021-08-26

    things chages a little bit when it comes to fill the screen with characters.
    Same machine same version under test but with this similar prog:

    10 FOR A=1 TO 10
    20 T1=TIMER
    30 FOR YD=1 TO 23:FOR XD=1 TO 80:LOCATE YD,XD:?CHR$(129+A);:NEXT:NEXT
    40 T2=TIMER
    50 T(A)=T2-T1
    60 NEXT:?"Average="(T(1)+T(2)+T(3)+T(4)+T(5)+T(6)+T(7)+T(8)+T(9)+T(10))/10

    v 1.2.14 win = 0.614 sec
    v 2.0.3 win = 1.256 sec
    v 2.0.3 python 3.9 x64 = 0.875 sec

    compiled version actually display the chars changing, but the pure python one outputs nothing and then gives the screen filled with last chars and the average result.

     
    • Everton da Silva Marques

      I experimented with compiling your bechmark code to native code with my toy compiler for basic: https://github.com/udhos/basgo

      Not filling the screen, your code took Average= 0.00011061930126743391
      Filling the screen, it took: Average= 0.1786323386011645

      Compiled to native executable, under Linux, x86_64, i7-8750H CPU @ 2.20GHz

       
  • Theruler76

    Theruler76 - 2021-08-30

    Hi Everton, I do not have experience with your compiler but knew it exists, and that's a great thing!
    It could be handy for some quick test i have to do.
    I am making some changes in a game I wrote in 2018 (MANOR 2, with permission of Leon Baradat, the 2.22 version is downloadable in his page https://peyre.x10.mx/GWBASIC/index.htm) namely a formula that calculate random natural events and determine how many grain you lose based to a parameter that mitigates the loss (SI).
    I test my formulas with most iterations I can get and it would be nice to have a compiled version to do millions in few seconds.
    At the moment 50000 iterations in pure python takes 155secs.
    Here is the test (with 1MIL for cycle I):

    5 RANDOMIZE TIMER:CLS:?"Statistical distribution of random natural events (SI=0 TO 4) ongoing...":ON ERROR GOTO 25
    6 ?:?" SI":?"  0%":?" 10%":?" 20%":?" 30%":?" 40%":?" 50%":?" 60%":?" 70%":?" 80%":?" 90%":?"100%"
    7 T1=TIMER:FOR SI=0 TO 4:G10=0:G20=0:G30=0:G40=0:G50=0:G60=0:G70=0:G80=0:G90=0:G100=0:FOR I=1 TO 1000000
    10 EV=INT(RND*5)+1:G=INT(RND*10000):RA=INT((RND*G/2)+(RND*EV*250))/((RND*SI)+1):PERC=RA*100/(G+0.1)
    11 IF PERC<=0 THEN G0=G0+1
    12 IF PERC>0 AND PERC<=10 THEN G10=G10+1
    13 IF PERC>10 AND PERC<=20 THEN G20=G20+1
    14 IF PERC>20 AND PERC<=30 THEN G30=G30+1
    15 IF PERC>30 AND PERC<=40 THEN G40=G40+1
    16 IF PERC>40 AND PERC<=50 THEN G50=G50+1
    17 IF PERC>50 AND PERC<=60 THEN G60=G60+1
    18 IF PERC>60 AND PERC<=70 THEN G70=G70+1
    19 IF PERC>70 AND PERC<=80 THEN G80=G80+1
    20 IF PERC>80 AND PERC<=90 THEN G90=G90+1
    21 IF PERC>90 AND PERC<=100 THEN G100=G100+1
    22 NEXT:LOCATE 3,(SI+1)*12:?SI:LOCATE 4,(SI+1)*12:?G0:LOCATE 5,(SI+1)*12:?G10:LOCATE 6,(SI+1)*12:?G20:LOCATE 7,(SI+1)*12:?G30:LOCATE 8,(SI+1)*12:?G40:LOCATE 9,(SI+1)*12:?G50
    23 LOCATE 10,(SI+1)*12:?G60:LOCATE 11,(SI+1)*12:?G70:LOCATE 12,(SI+1)*12:?G80:LOCATE 13,(SI+1)*12:?G90:LOCATE 14,(SI+1)*12:?G100:NEXT
    24 T2=TIMER:?"Execution time for"I*5"iterations: ";:?INT(T2-T1):END
    25 LOCATE 15+SI,1:?"SI="SI"  EV="EV"  G="G"  RA="RA"  PERC="PERC:RESUME NEXT
    
     

    Last edit: Theruler76 2021-08-31
    • Everton da Silva Marques

      Hi,

      Due to limitations in the compiler, I had to tweak the code in order to compile it.
      This is the final code I compiled.
      However I am afraid I broke the math in line 10 when inserting parenthesis for RND(). The compiler is unable to parse RNDnumber, it requires RND(number).
      I think I might have mistranslated RNDG/2, RNDEV250, and PERC=RA100/(G+0.1).
      Can you help me to fix properly line 10?

      1 screen 0
      5 RANDOMIZE TIMER:CLS:?"Statistical distribution of random natural events (SI=0 TO 4) ongoing...":'ON ERROR GOTO 25
      6 ?:?" SI":?" 0%%":?" 10%%":?" 20%%":?" 30%%":?" 40%%":?" 50%%":?" 60%%":?" 70%%":?" 80%%":?" 90%%":?"100%%"
      7 T1=TIMER:FOR SI=0 TO 4:G10=0:G20=0:G30=0:G40=0:G50=0:G60=0:G70=0:G80=0:G90=0:G100=0:FOR I=1 TO 1000000
      10 EV=INT(RND(5))+1:G=INT(RND(10000)):RA=INT((RND(G)/2)+(RND(EV)*250))/((RND(SI))+1):PERC=RA*100/(G+0.1)
      11 IF PERC<=0 THEN G0=G0+1
      12 IF PERC>0 AND PERC<=10 THEN G10=G10+1
      13 IF PERC>10 AND PERC<=20 THEN G20=G20+1
      14 IF PERC>20 AND PERC<=30 THEN G30=G30+1
      15 IF PERC>30 AND PERC<=40 THEN G40=G40+1
      16 IF PERC>40 AND PERC<=50 THEN G50=G50+1
      17 IF PERC>50 AND PERC<=60 THEN G60=G60+1
      18 IF PERC>60 AND PERC<=70 THEN G70=G70+1
      19 IF PERC>70 AND PERC<=80 THEN G80=G80+1
      20 IF PERC>80 AND PERC<=90 THEN G90=G90+1
      21 IF PERC>90 AND PERC<=100 THEN G100=G100+1
      22 NEXT:LOCATE 3,12:?SI:LOCATE 4,12:?G0:LOCATE 5,12:?G10:LOCATE 6,12:?G20:LOCATE 7,12:?G30:LOCATE 8,12:?G40:LOCATE 9,12:?G50
      23 LOCATE 10,12:?G60:LOCATE 11,12:?G70:LOCATE 12,12:?G80:LOCATE 13,12:?G90:LOCATE 14,12:?G100:NEXT
      24 T2=TIMER:?"Execution time for"I5"iterations: ";:?T2-T1
      25 while i$<>"q":?"hit q to exit":i$=input$(1):wend:END
      250 LOCATE 15+SI,1:?"SI="SI" EV="EV" G="G" RA="RA" PERC="PERC:RESUME NEXT
      

      This is the output:

      Statistical distribution of random natural events (SI=0 TO 4) ongoing...                                                                                                                                   
      
       SI         4                                                                                                                                                                                              
       0%         15004                                                                                                                                                                                          
       10%        0                                                                                                                                                                                              
       20%        0                                                                                                                                                                                              
       30%        0                                                                                                                                                                                              
       40%        0                                                                                                                                                                                              
       50%        0                                                                                                                                                                                              
       60%        0                                                                                                                                                                                              
       70%        0                                                                                                                                                                                              
       80%        0                                                                                                                                                                                              
       90%        0                                                                                                                                                                                              
      100%        0                                                                                                                                                                                              
      Execution time for 0 iterations:  0.26009053000598215                                                                                                                                                      
      hit q to exit
      

      Everton

       
  • Theruler76

    Theruler76 - 2021-08-31

    Yeah, sorry. I should have used codebox like you did. (I edited last post)
    there is a moltiplication symbol between RND ang G variable.

     
  • Everton da Silva Marques

    This is the output from compiled code:

    Statistical distribution of random natural events (SI=0 TO 4) ongoing...                                                                                                                                           
    
     SI         0           1           2           3           4                                                                                                                                                      
      0%        5           6           11          12          17                                                                                                                                                     
     10%        74698       146235      226351      310990      399003                                                                                                                                                 
     20%        148396      247962      341132      368015      345788                                                                                                                                                 
     30%        169462      260515      216470      160447      126812                                                                                                                                                 
     40%        178459      167264      100198      72203       56242                                                                                                                                                  
     50%        183660      78272       46347       33751       26450                                                                                                                                                  
     60%        111137      31370       19722       14612       11933                                                                                                                                                  
     70%        40257       15285       10293       7983        6535                                                                                                                                                   
     80%        20289       9289        6577        5206        4222                                                                                                                                                   
     90%        12719       6369        4604        3660        3150                                                                                                                                                   
    100%        8946        4710        3402        2757        2381                                                                                                                                                   
    Execution time for 5.000005e+06 iterations:  0.4774314090027474                                                                                                                                                    
    hit q to exit
    

    This is the code with minor changes:

    1 screen 0
    5 RANDOMIZE TIMER:CLS:?"Statistical distribution of random natural events (SI=0 TO 4) ongoing...":'ON ERROR GOTO 25
    6 ?:?" SI":?"  0%%":?" 10%%":?" 20%%":?" 30%%":?" 40%%":?" 50%%":?" 60%%":?" 70%%":?" 80%%":?" 90%%":?"100%%"
    7 T1=TIMER:FOR SI=0 TO 4:G10=0:G20=0:G30=0:G40=0:G50=0:G60=0:G70=0:G80=0:G90=0:G100=0:FOR I=1 TO 1000000
    10 EV=INT(RND*5)+1:G=INT(RND*10000):RA=INT((RND*G/2)+(RND*EV*250))/((RND*SI)+1):PERC=RA*100/(G+0.1)
    11 IF PERC<=0 THEN G0=G0+1
    12 IF PERC>0 AND PERC<=10 THEN G10=G10+1
    13 IF PERC>10 AND PERC<=20 THEN G20=G20+1
    14 IF PERC>20 AND PERC<=30 THEN G30=G30+1
    15 IF PERC>30 AND PERC<=40 THEN G40=G40+1
    16 IF PERC>40 AND PERC<=50 THEN G50=G50+1
    17 IF PERC>50 AND PERC<=60 THEN G60=G60+1
    18 IF PERC>60 AND PERC<=70 THEN G70=G70+1
    19 IF PERC>70 AND PERC<=80 THEN G80=G80+1
    20 IF PERC>80 AND PERC<=90 THEN G90=G90+1
    21 IF PERC>90 AND PERC<=100 THEN G100=G100+1
    22 NEXT:LOCATE 3,(SI+1)*12:?SI:LOCATE 4,(SI+1)*12:?G0:LOCATE 5,(SI+1)*12:?G10:LOCATE 6,(SI+1)*12:?G20:LOCATE 7,(SI+1)*12:?G30:LOCATE 8,(SI+1)*12:?G40:LOCATE 9,(SI+1)*12:?G50
    23 LOCATE 10,(SI+1)*12:?G60:LOCATE 11,(SI+1)*12:?G70:LOCATE 12,(SI+1)*12:?G80:LOCATE 13,(SI+1)*12:?G90:LOCATE 14,(SI+1)*12:?G100:NEXT
    24 T2=TIMER:?"Execution time for"I*5"iterations: ";:?T2-T1
    25 while i$<>"q":?"hit q to exit":i$=input$(1):wend:END
    26 LOCATE 15+SI,1:?"SI="SI"  EV="EV"  G="G"  RA="RA"  PERC="PERC:RESUME NEXT
    

    My Windows environment is temporarily broken. When it gets fixed, I will be able to send you the compiled code for Windows, or the directions to run the compiler on Windows by yourself.

    Everton

     
  • Theruler76

    Theruler76 - 2021-09-01

    It reads right? less then half a second? The power of machine code.
    Not a problem Everton, but thanks. I'd like to be able to compile myself.

    Cheers

     
    • Everton da Silva Marques

      Yes, it reads right.

      I have sketched this recipe for compiling in Windows:

      https://github.com/udhos/basgo/blob/master/README-windows.md

      If you face difficulties with the recipe, you can reach me at: everton.marques(at)gmail.com

      Everton

       
  • Theruler76

    Theruler76 - 2021-09-07

    Very comprehensive guide, Everton. thank you so much.

     
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.