robhagemans / pcbasic

PC-BASIC - A free, cross-platform emulator for the GW-BASIC family of interpreters
http://www.pc-basic.org
Other
393 stars 48 forks source link

About high cpu usage #169

Closed Danitegue closed 2 years ago

Danitegue commented 2 years ago

Hello Rob, I´m doing a few tests with the current pcbasic 2.0.4,

When I run the pcbasic alone, without any program, I can see it is not consuming too much resources from the CPU: image

When I run the pcbasic but loading the brewer instruments software: it grabs a baseline of around a 20% of CPU usage. ( intel i7-7700HQ with 8Gb RAM, Win10) image

This brewer software usually is not needing so many resources when running in GW. Obviously it is not the same to run in an interpreter, but I wonder if there is any endless loop at any part of the code creating this high cpu usage problem.

I have tried to run the software in "nobrew" mode (Serial port communications disabled), and also to remove the com ports in pcbasic, (so, removing the --com1=%COM_PORT_1% argument in the launcher), but it is still consuming a 20% of cpu usage in idle mode, (=when doing nothing more than updating the hour and the solar zenith angle in the main screen of the program). So it does not look that the serial communications are the problem.

image

I have tested different interfaces, (sdl2, pygame, graphical), and also to run without sound (--sound=none), but in all cases it gives me more or less the same CPU load.

I have also tested two different versions of python (2.7.18 and 3.8.10), and with python3 it is a bit worse (around 30% of CPU load).

By using the resource monitor, I can see that 2 of the 8 cores are quite busy (around 80%) when pcbasic is running with this brewer software loaded. (in the following image, the red line corresponds to the moment of closing pcbasic, with python 3.8.10, the cores 2 and 4 passes from 80% to near 5 or 0%).

image

A few questions: --Have you noticed this high CPU load, when using different programs? --It could be quite expensive to run this brewer software all day (energetically talking), do you know what could be the reason of this high CPU load, and if exist a way to reduce it? I remember that DosBox had an option to reduce the frame rate, but not sure if it is applicable to pcbasic, nor if it is the reason for the current CPU usage. I would appreciate any clue to research on it.

Best regards.

robhagemans commented 2 years ago

Just some thoughts

Danitegue commented 2 years ago

True. This CPU only has 4 real cores.

I tried now with --interface=text, but it gave me the same cpu load. (around 20%). with --interface none it is unusable, but it gave me a high cpu load as well (around 19%).

What I cannot understand is why the same exact BASIC code running in the original GW, in a Pentium II with windows 2000 and 256Mb RAM is taking 0% of CPU load when the software is idle... it does not look like a BASIC code loop problem. It looks more a pcbasic bug, but I don't know in which part of pcbasic should I look to research more about this problem. Could it be a pcbasic event being called in an endless loop too fast?

Best regards

robhagemans commented 2 years ago

Re running on the original GW, that's just a totally different proposition. GW BASIC is hand coded machine code optimised for 1980s computers. Bare metal on a Pentium, it's blazingly fast. If you then run that in DOSBox, that's compiled C code and again has had multiple contributors implementing decades of optimisation for running games. Meanwhile in PC-BASIC, if you have a tight loop waiting for input (say, 1000 A$=INKEY$: IF A$="" THEN 1000), that means reams of Python code get executed on repeat. You could build in more sleep statements and dramatically reduce CPU load, but it would also dramatically decrease the running speed of the emulation and hence make other users unhappy, who are already asking how can this emulator possibly be slower than the original GW-BASIC.

High CPU load is undesirable and inefficient, but that's not a bug in itself, more of a trade-off. There are undoubtedly many bugs in PC-BASIC; maybe there is one that if solved could reduce load in this case - I don't know. I have to try and optimise the little time I have available to spend on this project and for me, chasing this particular issue isn't necessarily a good way to find more bugs and improve the code. Interface issues have sucked up enormous amounts of time previously, changing one part may make one program work beautifully but just destroy performance on another. This is unlikely to be different.

I don't know where to start looking either, unfortunately, but the start would be to identify what part of the BASIC code is looping when CPU load is high and then reproduce that in a shorter, simpler piece of code. (I guarantee you there is a loop in the BASIC code; given that machine code subroutines are out of the question there is no other way to wait for user input.) You can then find out what bits of PC-BASIC run those statements by text search in the source code.

Speed and CPU load may improve in future versions but I can't give any guarantees as I'm unsure whether it's a solvable issue or just a consequence of using Python. Frankly when starting this project I never expected Python to be fast enough in the first place and I am still surprised it is not simply crawling ahead with 100% CPU load all the time.

Have you tried adjusting your BASIC code with pauses? It may not be the root cause but if you intend to use PC-BASIC for this and are concerned about energy usage, it may at least work around that issue.

Danitegue commented 2 years ago

Ok, thanks for your input. Effectively when the software is idle, it is waiting for user input. So it is probable that this is the main BASIC loop that is creating the high cpu load. I will try to add the pauses as you suggested to see if it improves.

I will also try your example in GW, to see what happens to the cpu when an endless loop is executed: 1000 A$=INKEY$: IF A$="" THEN 1000 (I wonder how the hell they implemented the machine code to avoid a high cpu load when executing this... )

El lun., 22 nov. 2021 8:42, Rob Hagemans @.***> escribió:

Re running on the original GW, that's just a totally different proposition. GW BASIC is hand coded machine code optimised for 1980s computers. Bare metal on a Pentium, it's blazingly fast. If you then run that in DOSBox, that's compiled C code and again has had multiple contributors implementing decades of optimisation for running games. Meanwhile in PC-BASIC, if you have a tight loop waiting for input (say, 1000 A$=INKEY$: IF A$="" THEN 1000), that means reams of Python code get executed on repeat. You could build in more sleep statements and dramatically reduce CPU load, but it would also dramatically decrease the running speed of the emulation and hence make other users unhappy, who are already asking how can this emulator possibly be slower than the original GW-BASIC.

High CPU load is undesirable and inefficient, but that's not a bug in itself, more of a trade-off. There are undoubtedly many bugs in PC-BASIC; maybe there is one that if solved could reduce load in this case - I don't know. I have to try and optimise the little time I have available to spend on this project and for me, chasing this particular issue isn't necessarily a good way to find more bugs and improve the code. Interface issues have sucked up enormous amounts of time previously, changing one part may make one program work beautifully but just destroy performance on another. This is unlikely to be different.

I don't know where to start looking either, unfortunately, but the start would be to identify what part of the BASIC code is looping when CPU load is high and then reproduce that in a shorter, simpler piece of code. (I guarantee you there is a loop in the BASIC code; given that machine code subroutines are out of the question there is no other way to wait for user input.) You can then find out what bits of PC-BASIC run those statements by text search in the source code.

Speed and CPU load may improve in future versions but I can't give any guarantees as I'm unsure whether it's a solvable issue or just a consequence of using Python. Frankly when starting this project I never expected Python to be fast enough in the first place and I am still surprised it is not simply crawling ahead with 100% CPU load all the time.

Have you tried adjusting your BASIC code with pauses? It may not be the root cause but if you intend to use PC-BASIC for this and are concerned about energy usage, it may at least work around that issue.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/robhagemans/pcbasic/issues/169#issuecomment-975279308, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGF22GAAJ4GOGKHHU7XR4YDUNH7BFANCNFSM5IPJB2NA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

Marrin commented 2 years ago

(I wonder how the hell they implemented the machine code to avoid a high cpu load when executing this... )

They didn't avoid high CPU load and they didn't have to. It's DOS — no one cares about the single program doing busy waiting and using 100% of the only CPU all the time. There are hardware and timer interrupts for DOS and memory resident programs/drivers to deal with hardware, stealing a little CPU time from the running program, but the running program uses all the CPU it gets, always.