INKEY$ is extremely slow on Linux
Jolmberg opened this issue · 9 comments
QB64 info (please complete the following information):
The issue is present in the latest release as well as in the current development build (b6705f2), on Linux. It is not present on Mac and I am unable to test on Windows.
Describe the bug
Calls to INKEY$ are about 100 times slower on Linux than on Mac.
To Reproduce
Run the following to count the number of INKEY$ calls that can be achieved in a second:
i = 0
t = Timer
While Timer - t < 1
a$ = InKey$
i = i + 1
Wend
Print i
On my Mac I get about 1,700,000. On Linux just 18,000.
Expected behavior
I would expect the numbers to be similar.
Additional context
Clearly it can be argued that 18,000 keypresses a second ought to be enough for anybody. If you need more you probably designed your program incorrectly, but there is code out there that does this and as you can probably imagine based on the numbers above, the performance penalty on Linux is brutal.
Is this Linux a virtual machine? What are the specs of the Linux vs Mac?
Is this Linux a virtual machine? What are the specs of the Linux vs Mac?
They're both physical laptops. It's a 2017 MacBook Pro versus a brand new Dell XPS core i7, so if anything the Dell machine should be slightly faster. I'm seeing the same problem on my 10 year old Linux desktop too. The Dell runs Ubuntu, my desktop runs Debian.
Well with one of my Windows 10 desktops I get 7,550,473. I'm not sure what causes the speed difference in Linux. I can try running this on my beefier Windows 10 machine and my Linux virtual and see what I get.
I can confirm that on my Linux virtual I only get 10,765. Pretty slow in comparison
I get 18,839 on my machine (DELL Optiplex 990 with Ubuntu 20.04)
I had a quick look at the source and noticed the line "Sleep(0)" in the qbs_inkey function, so I decided to put together a quick test:
#include <unistd.h>
int main(void)
{
for (int x = 0; x < 18000; x++) {
sleep(0);
}
return 0;
}
Timing this gives some pretty telling results. On Linux:
real 0m1.000s
user 0m0.000s
sys 0m0.084s
On Mac:
real 0m0.035s
user 0m0.011s
sys 0m0.021s
It's not quite a factor 100, but 30 is still a remarkable difference. I assume the point of sleep(0) is to yield to another process. I really don't know much about the internals on each platform here, but my guess as to what is happening would be that on Linux a yield does occur every time, but on Mac it doesn't (18k context switches per second sounds reasonable, 500k sounds excessive). Anyway, is yielding in every inkey$ call really necessary?
I removed the sleep and unsurprisingly that fixed the problem. I can now do 4.5 million inkey$ calls per second on my really old desktop. Nothing broke in any obvious way, but I'll have to leave it to you guys to decide whether this is safe (and worth doing).
@flukiluke thoughts?
I don't see any reason to include the sleep call. A quick check of the git history shows this line used to be a conditional:
if (cloud_app)
Sleep(20);
else
Sleep(0);
but I believe it's safe to remove the line altogether.