KeyDown/KeyHit slow on Macs?

BlitzMax Forums/BlitzMax Programming/KeyDown/KeyHit slow on Macs?

Fry Crayola(Posted 2006) [#1]
I was having a bit of a frustrating time with Diablo's HighGui mod (it's not the mod's fault), which returned frame rates on my Intel Mac that were about a tenth of the rates of my PC.

After many tweaks and tests I located the problem, and it came from what I would consider an unlikely source: KeyHit and KeyDown (deep in the bowels of the HighGui code).

Commenting out the offending lines (all simple tests) saw my FPS rise from 72, to about 350, using an Diablo's Button example code (six gadgets on screen, adding more drags the performance down even further).

The PC isn't blighted in this way at all.

I carried out a search here on the forums, and found a similar thread from 11 months ago in the bug bin, basically saying the same thing. A thread in the bug bin usually indicates that the matter has been dealt with.

Which leads me to ask - is this a Mac issue that can't be resolved? Has anyone else experienced this?


Diordna(Posted 2006) [#2]
Never had a problem before.


Floyd(Posted 2006) [#3]
...saw my FPS rise from 72...


That makes me suspect the GUI code is synched with the screen refresh rate.

It's just a guess. I have neither Mac nor HighGui.


Fry Crayola(Posted 2006) [#4]
Unfortunately, I checked all that and there's no syncing being done - if there was, commenting out the short loop which tests 200 KeyDowns wouldn't see a rise to over 300FPS. The line 'Flip 0' in the code was also commented out just to be sure, the frame rate remained low.

Each frame, it tests all the keys to allow keyboard shortcuts in the GUI - as a last resort I could cut this from the Mac version but I'm reluctant to make sweeping changes if it's actually a fixable problem, rather than 'just the way Macs are'.



Diordna - can you try running a simple loop that checks a key and see how long it takes?

start = Millisecs()
for local count:int = 1 to 200
	keydown(KEY_ESCAPE)
next

print "Time: "+(Millisecs() - start)


This takes much longer on the Mac than on the PC, yet other code (bank accessing, maths, graphics etc.) runs just as fast.


Brucey(Posted 2006) [#5]
The problem could be in updateEvents() in system.macos.m which is called every time you call keydown()

I imagine it would be better to get updateEvents called once per iteration of your main loop (by calling PollSystem), and have KeyDown simply return true or false for the specified key (rather than Poll the system, which it does now, before it returns the key value)

but I'm sure there's a reason the core stuff is coded the way it is?? ;-)


You could always try changing polledinput.bmx from
Global autoPoll=True
to
Global autoPoll=False

and then call PollSystem in your main loop...

and see what breaks ;-)


ClaudeClaus(Posted 2006) [#6]
Fry, I runned your loop several times and I get values between 24 (once) and 38 (once) with the majority being 27. It's on a MacIntel, 10.4.7, 1GB RAM.
Hope this helps.
Klaus


Fry Crayola(Posted 2006) [#7]
With an average time of about 27ms, that means you could get about 37 frames in each second which is far from ideal.

Ok - it can be argued that testing every single key (pretty much) every frame isn't going to be necessary, but it's more the fact that its lightning quick on the PC and doggedly slow on the Mac that worries me.


Floyd(Posted 2006) [#8]
That is impressively slow!

I tried the test on a very old and slow PC, putting everyting inside another loop so it ran 25 times.

The times were always 0 or 1, most of them being 0.


Fry Crayola(Posted 2006) [#9]
...hence my concern. Even if I hacked at the code and removed or severely cut down the key testing to fewer keys (say, 10 instead of 200) I'm still losing time that I'd rather the processor spent doing other things.

The project I'm working on is fairly processor intensive, so "time wasted" needs to be kept to a minimum. If this problem was an inherent flaw in the Mac rather than BlitzMax, any Mac version I produce would be inferior to the PC one by a substantial amount.


Fry Crayola(Posted 2006) [#10]

You could always try changing polledinput.bmx from
Global autoPoll=True
to
Global autoPoll=False

and then call PollSystem in your main loop...

and see what breaks ;-)



Irritatingly, nothing broke. I tried it in the loop and I'm getting returns of 0 and 1 millisecs, which is of course great. In Diablo's HighGui, I'm getting much, much higher frame rates as a result.

But like you, I have a concern - that autopoll=true must be there for a reason, and I'd hate to be breaking something else. I'm not a fan of changing things that I don't really know much about.


Fry Crayola(Posted 2006) [#11]
Something worth sharing, I feel:

I ran a test on both Windows and OS X with the following code:

For Local a:Int = 1 To 25
     start = MilliSecs()
	 
     For Local count:Int = 1 To 1000000
	     KeyDown(KEY_ESC)
     Next

     Print "Time: "+(MilliSecs() - start)

Next


Basically, I wanted to test how fast KeyDown runs, with Debug turned off. Being lazy I never bothered to actually code in the bit which would calculate the speed of a single call but that's just me. I broke out the calculator.

Windows returned results averaging around 39ms, which works out at about 0.00000004 secs per call.

OS X returned just shy of 25 seconds (yup, it's that big a difference) working out at around 624 times slower.


Turning off the autoPoll and calling PollSystem once for each of the 25 runs, gave 4ms results. Obviously you can't compare the two but certainly I'm happy with the speed if that's the case.


Ideally, if someone in the know could confirm that turning off the autoPoll isn't about to break crucial parts of BlitzMax somewhere along the line, which I think should be the case as it would only ever be called when I explicitly ask anyway (via a KeyDown or similar), then I'm a very happy man and will be running with this solution.


Brucey(Posted 2006) [#12]
It really does sound like a bug on OS X...


Brucey(Posted 2006) [#13]
btw... you realize also that HighGUI calls lots of MouseX/MouseY etc throughout, as well as many, many TextWidth/Height calls... (certainly the MouseX/Y calls will have been polling too on OS X)

I've rewritten/reorganized a lot of the under-lying code while I've been trying it out on Linux, and I've seen boosts of 10-20+% in places. (for example, I got the combobox example up from 76fps to 109fps)
I also converted the code from includes to imports - changing the core structure - cuz I don't like includes...

Still want to do some more work on it, but I only tinker when I need a break from my other stuff.

I have to thank Diablo for having a good base to work from ;-)


Fry Crayola(Posted 2006) [#14]
Aye, the MouseHit/Down affected the speed too but on a much smaller scale (only 3 buttons to worry about, really, and a few axes). I wasn't aware that TextWidth/Height would suffer accordingly.


Brucey(Posted 2006) [#15]
well, everytime you call TextWidth, it has to go off and calculate the width of the given string for a specific font.

Sure, it doesn't take forever to calculate that (probably iterates over the glyphs and returns the total), but if you are doing that lots of times, it all adds up - especially if you could instead cache those values which aren't going to change anyway!

Anyhoo... that was just one of the optimizations I looked into.


Fry Crayola(Posted 2006) [#16]
Always worth a shot.

I'll look into optimising it after I've finished a nice little XML wrapper thingy (I have no idea about jargon) which can let me throw together GUI screens like I'd code HTML. I plan to use this in my game and hopefully keep it powerful enough to allow for some fairly good skinning.

That's assuming I'm any good.


Tachyon(Posted 2006) [#17]
Just got a new MacIntel. I noticed this topic, ran the sample code and get that same 27ms on 200 KeyDown calls. Crazy slow!

Mark/Skid hasn't commented here. Does this need to be posted in the Bug forum? Hacking BlitzMax isn't really what I expect to be a quality solution. :)


Fry Crayola(Posted 2006) [#18]
I posted the same topic in the bug section, and Mark replied that the "hack" will work if you call PollSystem "often enough". I call it every single frame, so that's going to be at least 60 times a second. I've noticed that the only issue if you don't call it (in addition to not getting to read key presses) is that the OS thinks the program has frozen up because it's not getting any responses from it.

I've noticed no other ill effects, so there's no harm in the minor hack.