zeth/inputs

High CPU consumption from game-pad demo

Closed this issue · 15 comments

When running this simple game-pad demo provided in the docs the program consumes ~30% CPU on my computer using an intel i7 6500u, even if the console output is commented out. I tried adding a delay within the infinite loop, but this causes the events to lag behind the actual controller (xbox one) inputs.

Any thoughts? The CPU usage seems excessive for only receiving game-pad input.

Same issue here

I wrote my own xinput wrapper for game controllers on windows that doesn't block and roughly tries to emulate how this library is used for game controllers. It's usable right now but I plan to add directinput support as well and change variable names to follow PEP8. I am considering making a pull request but internally my wrapper works quite different to how zeth has done it. Internally it asks windows to call a function at 1ms intervals. how you use it is something like xinputmanager.get_events() which will return a list. His implementation has some kind of character device with time delays which I think is a bit unnecessarily over complicated. This I think causes the issues with time.sleep causing input to lag behind. get_gamepad also blocks in zeths library which can cause your main program to freeze until your game controller gets a new event. This caused my program to go from 3800 fps to 200 fps with numerous latency spikes that could be more then 1/10th of a second which was incredibly noticeable.
My cpu usage is under 3% with almost no packets from the controller being missed and should support all 4 xinput devices but I don't have extra controllers to test.

if there is an interest I can try to dedicate some of my time to integrate it with this input library.

Same issue. Controller plugged and detected. gamepad.read() blocks and stays at 17% CPU for it.

I tracked the code, seeing that it just does next(iter(self)), which in turn goes into a While loop that keeps reading from the device and returning None, until any input comes in. I don't have a good guess at why the piping overloads the cpu like this.

@zeth please respond.

UPDATE: Adding time.sleep(0.001) to _do_iter() before line 2497 (just before the Return None) in my C:\Users\%USERNAME%\AppData\Local\Programs\Python\Python37\Lib\site-packages\inputs.py solves this issue.

While loops in Python should not run unchecked - common issue. 1ms = 0.001s. This should be fast enough to cause no visible lag with input.

(I got curious, so I checked. My i-5 CPU does about 50 Billion instructions per second. No wonder even a millisecond of sleep makes such a difference lol.)

Here is a basic xinput wrapper I did for windows that tries to work in place of inputs without too many changes, it also hooks into the windows multimedia timer api to get 1ms timer intervals and a small callback function called roughly every 1ms internally to get the latest state for event processing. https://gist.github.com/Sartek/ebe71fea3afeabcb6ec897d39e09d0e0 You will need to handle disconnect/reconnect yourself I think it raises an exception and you can decide what to do yourself.

I don't think I added timestamps on events yet but I might have.

@phuein Your solution fixes the problem. Thank you so much!

zeth commented

Is everyone that is finding this an issue using the Windows operating system?

I'm on windows, I could either run it without time.sleep in my program and fill a whole cpu core, have time.sleep(1/60) or make windows have a higher multimedia timer so I could do up to time.sleep(0.001) the problem with time.sleep is it lowered CPU usage but controller input started to lag massively as if it was playing back from a buffer with a huge delay. I tried messing around with inputs.py to fix that issue but it seems like a large portion needs to be restructured. The blocking and high CPU usage made it unusable for my use case on windows, it might be fine on Linux but I haven't tried yet.

zeth commented

Thanks for this response. Do you find the issue with keyboard and mouse too or only with the gamepad?

zeth commented

(If it doesn't display the problem with the mouse and keyboard then I know an easy solution, if not then I will need to study it more).

I don't think it's related to mouse and keyboard, I think it's how it emulates events from an xinput state on windows, it requires a new state before it returns back to the program loop, this can be a problem as the xinput state packet number only changes when an input value changes, this can cause a freeze for multiple seconds. It then seems to emulate some kind of buffer with timestamps that it then reads back as events, time.sleep seemed to mess that up on my system. I can try with a mouse and keyboard in the future.

zeth commented

With the mouse and keyboard, I am using a subprocess to buffer them which seems to help here. The Gamepad support which I wrote earlier does not have this yet.

Yup, windows 10 pro.

@zeth friendly ping

Hi!

I have this issue on windows... I've tried the sleep work-around, but it cause weird lag. (it's strange.. sometimes it's ok, sometimes input lags about a second, sometimes press is ok, but release lag for 500-1000ms)

Let me know if I can help with testing! Or if you have any suggestion!
PS: I've installed with pip yesterday, so if you have any branch that I can try let me know!

I found a solution for myself...
I moved the sleep function to line 2685 just around here:

    def __iter__(self):
        while True:
            time.sleep(.001)
            if WIN:

And no lag at all...
(It's cause a fixed 1000/sec polling rate, but it's more than enough for the 'snake game' I'm making for my daughter. :) )