Vsync messing with my job system

Started by
33 comments, last by Ryan_001 7 years, 1 month ago

Hey guys,

I have been investigating a weird slowdown in my project that turned out to be Vsync causing my job system to perform poorly. I am not sure why this is happening though, so I ask for ideas.

I have a simulation running where particle systems are updated on the job system. The job system is fairly standard, it uses a pool of threads and gives those threads jobs to do. In addition, you can add dependencies to a job and have the main thread wait until the job is complete. In the case with the particle systems causing problems, each particle system's update function is thrown on the job system and the main thread waits for all of the update jobs to complete before continuing. In practice this is implemented with Win32 events and the main thread is using WaitForSingleObject() to wait for the depencency linked to all the update jobs.

This works fine when the frame rate is unlocked, and it even works fine when the main thread is limiting the framerate through code (by spinning in the beginning of the frame until the desired delta time has been reached). However, when turning on VScync to limit the framerate (in this case to 60FPS) the WaitForSingleObject() call starts taking anywhere between 1ms-500ms. With VSync off I can happily throw hundreds of particle systems on the job system and it performs fine. With VSync on the multithreaded update of particle systems causes the framerate to vary wildly (as previously mentioned). However, if I update the particle systems serially on the main thread the system works farily ok (although a bit slower since it does not benefit from the job system) even with VSync on.

So in short, having Vsync on makes the job system dependency waiting perform very poorly. Any idea what might cause this? Literally the only different in my engine between having VSync on/off is passing 1 or 0 as the first parameter to IDXGISwapChain::Present(). I am using DX11 for rendering and the swap effect has been set to DXGI_SWAP_EFFECT_DISCARD. The tests have been done in window mode. With VSync on I presume the call to Present() sleeps until it is time to present the content on screen. Is it possible that the machine does some weird context switching because of this, causing my threads to jump around and cause this behavior?

Thanks!

Advertisement

You can throttle your frames or you can enable v-sync. Don't do both or you'll get drawing issues. Also, if it's causing lag then you're throttling incorrectly.

You really don't need to throttle the drawing in any case. Throttle your logic updates (search: "fix your timestep") but just draw as often as the machine can and just interpolate forward based on the time elapsed since the last logic update. You can enable v-sync in that case and it should work perfectly.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

Thanks for the tips, however, they don't help me in this case.

First of all I obviously don't have VSync and the manual frame rate limiter on at the same time, it's an either-or. In my tech there are good reasons for limiting the actual drawing rate, eg. in the level editor which is a WinForms app I am using the native engine to draw straight into a .net panel control using the raw handle and on many slightly older machines the WinForms app message pump gets flooded unless I limit the frame rate to 30 or 60.

I am using a fixed time step for the updates (two actually, a physics update rate and a tick rate for server gameplay and network logic). This is all fine and dandy, and besides the point I think.

Any idea why enabling VSync would mess up the WaitForSingleObject() duration?

Have you asked in the Hand made hero forums?

I have no experience in using that function, but have you tried to check if there was any error when vsync is active?

Are the jobs themselves doing anything that would have to wait for the next presentation interval?

I would try to find a thread profiler to see if you can spot anything obvious. AMD CodeXL might work, but I haven't actually used it for thread profiling yet.

No they are running a method full of math functions, basically only updating the particle systems and not touching any other engine subsystems such as the renderer.

I am currently rewriting some dodgy parts of the job system (something I have put off for years already) to be able to debug it more easily. I don't particularly count on it fixing the problem though, so keep the suggestions coming!

Have you tried to make the minimum program that behaves like that?
I mean, create only one thread, have vsync active and check if WaitForSingleObject does that weird thing.

Have you tried in another window version?

How do you propose having only one thread but still using WaitForSingleObject()? I am using the function explicitly for thread synchronization.

As for the windows version, the behavior is the same on Win7 and Win10.

Sorry, I meant 'create' one thread
I see, sorry. Yes, I have tried with only one worker thread and it did seem like the wait duration did not vary as much as with the normal six worker thread setup.

I should have the job system refactor done later today or tomorrow and I should be able to debug it better. Cheers!

This topic is closed to new replies.

Advertisement