This is an oldish thread, but I'm not as regular here as I used to be so forgive me!
Kojack wrote:Unreliable frame timing can also be caused by multi-core cpu timing issues, jumping from one core to another (happens even if you aren't doing multithreaded) can mess up the timer because each cpu has it's own clock and they might not be in sync. Ogre has code to fix that (it's clock only ever runs on the first cpu core, it uses thread affinity), I'd assume unity does too.
We probably shouldn't be doing this any more. CPU's all have their own tick count, but they will all always have the same tick frequency, which means if you query from different threads you will be out by MAX +/-1 tick. Switching threads and setting affinity will likely take longer than one tick, which mean you will be getting less accurate timings if you try to context swap. Maybe the issue used to be on XP, but not even MS supports that anymore. We shouldn't either.
See this MS article:
Acquiring high-resolution time stamps
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
Onto the jittering
There are four main reasons people get jittering that you should be looking for:
Loading things in the main thread
This one is pretty straight forward. If you are streaming in assets in the main thread while you navigate the scene, you are at the mercy of the size of said assets. Large assets will cause large stalls. You may also be at the mercy of your hardware, that may exacerbate stalls
*cough* HDD *cough*. Move as much loading as possible to background threads and leave the main thread free as much as possible. The size of your assets can also be a source of stalls, but ill cover that next.
Asset transfer stalls
Your graphics drivers will only send Assets to the graphics card the first time they are needed for a frame. So for example, if you load your entire scene and are looking in the other direction, then quickly turn around, you will likely get jitters as all the needed data is sent to the graphics card. There are two main things you can do to help with this. The first is have smaller assets. Simple I know, but using DDS files that remain compressed on the graphics card, rather than other formats will save your band width. Also try reducing the resolution of your textures. And also get your artists to follow their size budgets for their meshes. You can also try using triangle strips and such, but I have never actually seen them used in practice. They are too much hassle and likely less effective than using smaller textures.
The second thing you can do it called Texture/mesh warming. Once you load all your resources invisibly render them to the screen one per frame (or more if they are small, use size as heuristic). Then after they are all warmed up, create the objects that use them. This will spread the transfer over multiple frames and reduce stutter.
Use GPUView (free windows tool). Direct X emits events into the windows log stream when a resource transfer begins and ends. GPU View will show you graphically where they are, and you can see if there is a correlation between long frames and resource transfers.
http://graphics.stanford.edu/~mdfisher/GPUView.html
Dual monitor setups
I once spent two weeks profiling and tweaking and measuring and debugging to try to find a jitter I was getting to no avail. Then, on some obscure forum post I found someone who said that graphics cards are only optimised to deliver the best performance possible to one monitor, the other will always have poorer performance. After reading that I booted my software on another monitor and boom, the issue was gone, or at least significantly reduced. So be wary of Dual monitor setups.
Resource contention
This is when you have a mutex that two threads are trying to get access to the second thread will simply have to wait until the mutex is released before it can continue processing. When that is the main thread you will get a stall. To get around this make sure anywhere you have mutex protected sections are as brief as possible. Also try boosting the priority of your main thread over the others. This will make it more likely that it will get the mutex first, and when it doesn't the process with the lock will get a priority boost until it releases the resource due to windows thread priority inversion.
Add this code to the start of your application:
Code: Select all
// Slightly boost the overal process priority
SetPriorityClass( GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS );
// Set the Multi Media Class Scheduler characteristics of the software. This will
// provide a priority boost to certain threads when the process has focus.
DWORD index = 0;
HANDLE handle = AvSetMmThreadCharacteristics( "Games", &index );
if( handle )
AvSetMmThreadPriority( handle, AVRT_PRIORITY_CRITICAL );
// This is needed to make sure that background work does not starve the main thread.
// This is only setting priority of this thread, not the whole process.
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
To see if there is resource contention you will need to do what is called wait analysis. You should be able to do this with your profiling tools. I use Windows Performance Analyser (another free windows tool).
Hope that helps.