Frame skips? Frame pacing?

Now before you scream “Garbage Collector!” hear me out.

I know garbage collection uses a lot of recources for the moment when it decides to dispose all that trash. Yes, that was a problem for my game, too, but I am not sure it’s the root cause of my current issue. As a matter of fact, calling the GC more often helped with the issue. I monitor GC memory and when it disposes etc. and it does not seem to be correlated with my frame skip problem now.

Ok so here’s the deal:

It appears the game will sometimes draw 2 frames right behind each other and later have one frame be double the length of a normal one. Frame pacing. And all of this is happening more of than garbage disposal.

This is not an issue if my game runs at 300Hz and I manually set IsFixedTimeStep = true. → 60Hz
aka like this

if (GameSettings.LockedFps)
            {
                _graphics.SynchronizeWithVerticalRetrace = false;
                //this.TargetElapsedTime = TimeSpan.FromTicks(16666); //is 60 by default anyways
                IsFixedTimeStep = true;
            }

The game will appear to run smoothly, however I should note that when using VerticalRetrace==true aka Vsync it will sometimes (every second or two) still register a frame drop and set the speed to 30 for a few milliseconds.

However, if I increase graphical complexity, for example by using SuperSampling, I can easily push the framerate to go below 60 Hz without a limiter.
And now it’s really janky, every half second or two it will skip a frame, if I run at 50 ms it will go
50 50 2 100 50 50
and sometimes
50 50 2 50 50 100 50 2 50 50 100
although I am not sure maybe I am recording that in a wrong manner somehow.

Now comes the part that initially made me think it’s GC.

I set up a StopWatch around the functions to try to understand what’s so janky exactly.
I calculate an avg. time over 100 frames, the average offset/variance over 100 frames and a maximum offset/variance.

Turns out EVERY SINGLE FUNCTION has a maximum offset several times the average time.
So if my function takes 100 ticks, and i have an avg. epsilon of 20 ticks i have a maximum eps of 400 or so.

These offset frame times, looking at a single function, correspond with the frame peaks but will peak so extremely only once every 10 seconds or so, which leads me to believe it’s another thing that’s stalling the CPU.

Ideas?

Just to add, I have a pretty bad multithreading culture going on, where the physics thread writes to the same position values the draw method in the main thread has to read and i just hope it works and somehow it does. But could it be something with that?
I don’t use any threadcontrol aka stalling or anything

maybe some of you find this useful in that regard, recorded with Intel GPA.
The game is basically stopped once every second or so


<screaming> Garbage Collector! </screaming>

Sorry, couldn’t resist XD

Read your post. Sadly I cannot think of anything besides the GC (which is triggered every few seconds, as one may observe in VS2015 (free community edition) while debugging, regardless if there are large objects to dispose or not. You’d have to go out of your way in terms of programming style in order to prevent that completely. An actual stall would be actual garbage collecting big objects).
Here is a screenshot of the GC behavior in Throbax TD (We have profiled a lot in order to get rid of any object-disposing; Everything’s pooled):

We don’t experience any lags at all. That’s because the amount of garbage is very small.

To me it looks like your CPU is stalling, leaving the GPU without work to do every 10 seconds.
Of course there could be other stuff piling up.

As to your physics thread… I think you have those access-points locked. Besides that I think that couldn’t be the problem since it really looks like a piling-up - disposal problem from the outside and I cannot imagine anything piling up with your thread-setup.

To get the GC out of your debugging completely, you could have a look at the timings like here:

It shows that it was a Generation1 GC run lasting for .7ms…

Sorry that I couldn’t be of more help.

what profiler do you use? (VS2013?)

Nope. Like I said: Plain standard free VS2015 Community Edition.

I use vs2k13. They seem to have changed the style as i did not recognize the profiler too.

I wouldn’t be too sure this isn’t a threading problem.

It appears the game will sometimes draw 2 frames right behind each
other and later have one frame be double the length of a normal one.
Frame pacing. And all of this is happening more of than garbage
disposal.

If the gc is collecting large amounts of memory i would think you would be skipping draws not updates.
You shouldn’t be getting skipped updates unless you have present.Interval = Interval.Two

This is not an issue if my game runs at 300Hz and I manually set IsFixedTimeStep = true. → 60Hz
aka like this

if (GameSettings.LockedFps)
{
_graphics.SynchronizeWithVerticalRetrace = false;
//this.TargetElapsedTime = TimeSpan.FromTicks(16666); //is 60 by default anyways
IsFixedTimeStep = true;

        }

When you set target elapsed time to true you are running at 60hz
Vsync takes milliseconds to execute its merely a fraction of your entire frames time slice. If anything if the sync occurs at the end of your time slice, you would miss a draw, not a update, if a IsRunningSlowly occured.

For the most part xna and monogame are single threaded and threading if you don’t know exactly what your doing, and even when you do, it can be tricky and weird stuff like this can occur. This does sound more like something else then your settings or gc

On the other hand running the gc a lot will reduce the size of a collection that would increase the frequency or number of skips for draws but even them out to make them overall smaller smother it shouldn’t for updates make them skip at all.

to me it sounds very strange.

did you run the clr profiler on it.

what happens when you turn off vsync and fixed timestep to false;

Additionally when im not sure what is going on with my calls.
You can use System.Diagnostics to manually call a stacktrace at a specific time or on some event log it or set a breakpoint after it and look right thru the stack then and there yourself.

something like this.

    /// <summary>
    /// quick get of the stack frames
    /// </summary>
    /// <returns></returns>
    public static string GetStackInfoFrames()
    {
        string s = "\n Stack Frames Info : " + GetTimeString(); 
        StackTrace st = new StackTrace(true);
        int whatframe = 0;
        while (whatframe < st.FrameCount)
        {
            StackFrame sf = st.GetFrame(whatframe);
            s += "\n StackFrame[" + whatframe + "]" + " " + BxPathing.GetFileNameFromPath(sf.GetFileName()) + "." + sf.GetMethod() + " Line" + sf.GetFileLineNumber();
            whatframe++;
        }
        return s;
    }
}

You could also use the profiler from Ants (free for 15 days if i remember well) it will tell how much time is spent, and with how much time/calls to each line of code.
Very handy to find bottlenecks in c# code. If it is a threading problem you will see it.

interestingly the game runs much, MUCH better on Windows 10. I have no idea why exactly, but the frame time just doesn’t jump to 6x it’s original value any more.

Same settings, everything bumped to supersample and most effects possible, running at ~30/40 fps.

You can still see the bumps, but this is not even comparable.

I think this is a solid point from which I can look into optimizing garbage creation.

Another thing which is nice about Windows 10, is that the profiles Throbax uses (aka the memory profiler) is available, so I can see where GC happens. This was simply not a feature that worked below win8 I reckon, like so many other default VS2013 profilers. I guess the upgrade has already payed off, at least in terms of Visual studio / game improvements.

What version of Windows were you on before 10? And did you ever find out what the problem was?

win 7, the problem is still the same, but just a little bit less problematic.

Did you get a chance to use a profiler like ANTS, dotTrace or NProfiler? Some of these (or maybe even all of them) are available for a trial period.

the problem is persistent it seems, I’ve rebuilds my debug view to record all frametimes over the last second (possible thousands, depending of framerate) to get min/max frametimes.

Turns out that even if my program runs with several thousand frames per second there will be at least one frame with around 16 ms (60 fps) in there over the course of one second.

Not great obviously. I generate no significant garbage (only mouse movement creates garbage behind the scenes, can’t do anything about that) so it’s not the GC for sure.

Any ideas?

I have not read the entire thread, however from what I have read, two things spring to mind…

  • Shader lag? Possibly?

  • If you are on Windows 10, did you enable GameDVR for the application? is GameDVR enabled?

I might read the whole thread at some point…

? what is that supposed to be

Maybe it’s related to this issue?

I presumed you were using a shader effect which may be expensive and causing random delays?