Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling TriggerUpdate() with a loop that's faster than 1ms causes timeouts to happen much earlier #521

Open
TomTheFurry opened this issue Jun 9, 2023 · 1 comment

Comments

@TomTheFurry
Copy link

TomTheFurry commented Jun 9, 2023

The TriggerUpdate() method is added to (I presume?) resolve the issue where in Windows, the Thread.sleep(...) method has quite a large minimal sleep time. Therefore, the doc as said here suggests using TriggerUpdate() for faster update time.

However, the underlying code that keep tracks of time elapsed uses millisecond integer, with the delta time between each actual update set with the minimum of 1 ms, seen here:

ProcessDelayedPackets();
int elapsed = (int)stopwatch.ElapsedMilliseconds;
elapsed = elapsed <= 0 ? 1 : elapsed;
stopwatch.Restart();

Additionally, the use of casting stopwatch milliseconds into integer caps the accuracy of the stopwatch to 1 millisecond, even if the underlying stopwatch implementation supports higher accuracy.

This wasn't (much) of an issue normally, where the default update time is set to 15 ms. (Note however even with default time, the timeout would still drift a bit and not be that accurate. But that's not really a real problem.) However, when TriggerUpdate() is added, user of the lib can now drive the update loop to as fast as it can goes, bypassing the previous bottleneck of Thread.sleep(). This includes driving the loop to faster than 1 ms, by a lot.

In our team's use case, we have an issue where tons of packets are sent (to localhost server), and the lib cannot keep up with processing all the packets. To 'patch' this issue, I changed from using the update time parameter to directly calling TriggerUpdate() on the main uncapped loop, with speed sometimes up to 100th of a millisecond. We however noticed that seemingly on random, the server kicked the client for timeout, even though around 5 packets are sent every 50 millisecond, and that our timeout setting is 5000, or 5 seconds.

After some investigation, I discovered that because the server is calling the TriggerUpdate() as fast as possible, the timeout is reached in much less than a millisecond, due to the above mentioned issue. This causes erroneous timeouts of the client.

Library version: 1.0.0-rc3, but can confirm issue still exists with latest commit (47d5721).

Framework: C# .NET with custom in-house game engine

OS: Tested on Windows

Suggestion: The proper fix is to change all time variable to 'float ms' or 'long ns'. However, if the library does not wish to support high-frequency updates, either proper documentation should be added to TriggerUpdate() warning against less-than 1 ms calls, or that the function should itself skips updating if the elapsed <= 0.

@RevenantX
Copy link
Owner

@TomTheFurry TriggerUpdate() is mostly used to send packets after game logic generated them (so it's mostly called like at 30-60 FPS rate), that's why this situation isn't checked. I will look what i can do with this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants