Reducing CPU usage in Enet thread
I want to check for new packets every 0.1ms or less, but not consume more then 10% of the CPU core. How can this be done?
Non-blocking I/O isn't really needed if you're using UDP and dedicating a thread to reding the socket.
Just have that thread block on receiving datagrams from the socket.
Anyway, your question of latency is interesting.
If you get data "right away" in the receive thread, what would the rest of your program do with it?
If you have another thread that does simulation, the data you receive would have to wait for that thread to simulate response anyway.
And if that's the case, why wouldn't you just poll the network in the simulation thread, right before taking a simulation step?
When I used to use Enet, I did just as hplus0603 suggested, run & update Enet in the main thread as part of the rest of the frame loop.
If I was also rendering, the rendering would naturally limit the framerate & CPU usage, especially if vsync was used.
In case of a headless server, the main loop could sleep to avoid spinning at 100% rate, when it doesn't have simulation work to do. Getting the sleep accurate may be a problem depending on the OS.
Github: https://github.com/cadaver C64 development: http://covertbitops.c64.org/
Well, polling on the main thread might work if you manage to guarantee that it is done every 5seconds or less, or else the connection breaks. I don't really want a hiccup on the main thread to cause network issues.
Also, as AgentC said, the server side loop spinning makes the server core be at 100% usage unless I put in delays, which I don't want. So either accept 100% core usage or put in Sleep()?
Why would the connection break if you call enet_host_service() (or whatever the name was) every frame? Enet uses its own internal throttling to manage the network data flow. Calling the service function should have very little impact on your program if there is no data available on the wire.
Yes, 5 sec could be exceeded in situations like loading a new map.
Some solutions I can see:
- Divide any long operations into smaller chunks of time, e.g. when loading a map, load new entities into it only until a certain amount of ms has been exceeded, then continue on the next frame
- Increase the ENet timeout
- Keep the ENet thread, and implement sleeping on it instead. However I don't think you will consistently achieve 0.1ms response time and low CPU usage, at least not on Windows, due to less than 1ms "sleeps" having to be implemented with spin-waiting instead, but you can use timeBeginPeriod(1) to get the timer (and thus sleep) granularity down to 1ms.
Github: https://github.com/cadaver C64 development: http://covertbitops.c64.org/
No, if I don't call enet_host_service() for 5 sec it breaks.
Yeah, that is why I suggested you call it every frame. BTW, you can adjust the timeout interval if 5 secs is not what you want.
EDIT: Just read AgentC's post. What I do in cases like loading screens is chop up the loading into as small tasks as possible so the network always gets its share of processing, ie. don't do all loading at once but instead lay it out over several frames. In practice this is crucial for MP titles. What I do in my own engine is hand off the Enet host to a background thread whenever it needs to do something that might potentially block the main thread for a long time (several hundred ms), eg. connection and disconnection are done in a background thread. However, all game state sync and simulation is done in the main loop.
Any reason why blocking reads won't work?
You could have one read-thread and one write-thread for the network..