Lag if update() takes longer than frametime

I’ve just started using monogame and fiddled around with the update method. I wanted to test what would happen should my update method take longer than the target frame time allows. So I’ve put a Thread.Sleep(15) inside the update method which works fine (15 < 16.66ms). If I increase the sleep time to 20ms I get 0-3fps and frametimes of > 500ms which seems really bad. Instead I would expect to get around 50fps since 1000ms/20ms = 50.

Platform is Windows and tested render backend is DirectX.

Hi @LsHallo Welcome to the forums.

Posting some code would help others help you faster.

Happy Coding!

Consider if draw had priority over update what would you expect to draw if you only updated 3 times per second. How long do you think it would take to get your mouse over the exit application button.
So ya Update should always have priority over Draw.

As you are purposely cpu binding the application 100xxx % and short circuiting the game loop.
I don’t see any framework problem here, it seems to be working exactly as you have designed it to.

I have some advice to fix this problem you created.
I recommend you don’t do that… as i think that would be very bad game design on your part.

Any questions ?

1 Like

Here is my Game1.cs. Program.cs is unmodified. FPS and Frametime was recorded using MSI Afterburner overlay.

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Threading;

namespace Example1
{
   public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            //60fps
            //Thread.Sleep(15);

            //0-3fps
            Thread.Sleep(20);
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            base.Draw(gameTime);
        }
    }
 }

I’m only stalling the application long enough to force something lower than 60fps which might occur on low end hardware even if the update loop just takes 2ms on my machine. The problem is that as soon as the execution time of update() exceeds the time in which a frame should be output (16.66ms for 60fps) the application drops to 0-3fps and not as expected to 50fps (for 20ms update() runtime). This seems to be a big problem if i’m not mistaken.

eh … thread.Sleep(20)

milliseconds to seconds = .02
at 60 frames PER second = .02 * 60 = ?

1.2 seconds.

thread.Sleep(1.2 seconds every second);
or 120% of the allotted time per frame is guaranteed to be in update.

If the users computer cannot finish a Update in the allotted frame slice how can you expect it to have any time left to draw. IsRunningSlowly is always being set here every frame so somehow it’s still drawing on emergency lifesupport.

2 Likes

Yes I am aware that I am sleeping too long for 60 updates per second. That is the whole point. I wanted to see what happens should my update method not finish in the scheduled 16.66ms for 60fps. I expected the fps to drop off a little bit to 50fps since 1000ms/20ms = 50. I did not expect my program to become totally unresponsive.
Every game I know handles update times > 16.66ms just fine and outputs less fps than 60. Not so for monogame. It chokes on something and outputs 0-3fps instead.

if you put the sleep in Draw() then you will see it drop to 30fps, skipping every other frame to give priority to update.
but you have the update taking all the time+more. In that case check gameTime.IsRuningSlowly and try to avoid low priority updates, (particles, animations, etc)

try this
Thread.Sleep(5); // simulate runing physics + input
if (!gameTime.IsRuningSlowly)
Thread.Sleep(20); // simulate updating billboards, shadows, particles.

to have a more realisting test, add a Thread.Sleep(10); in both Update() and Draw().

It’s ts choking on update because you have given it less then 0 time to draw.
.1666 is the amount of time alloted to both a update and a draw which is a Frame i.e. FrameTime or TimeStep the step is Update and Draw.

In the constructor you can undo that and set

        IsFixedTimeStep = false;
        graphics.SynchronizeWithVerticalRetrace = false;

^ provided the user doesn’t have vertical retrace forced on in his cards settings.

but then you have to handle timing things yourself which if you timed yourself 60 fps then all that would happen is both update and draw would run really slow as you would then only have 40% of the regular total time to do both a update and a draw since your Update to Draw ratio is i dunno even know but its a terrible ratio…

Which as stated initially, is worse then update doing 60 fps and draw doing 3
if you ever want your game to do any networking that is synced or have any UI that functions properly at all.

Having both equally slow update draw will just make your game have no clearly defined minimum specs and tons of angry people which you can’t even answer to say your computer is 12 years old and below minimum specs. Because you yourself wont even have a clue what minimum specs are.

Maybe that is the part that is Ancient Wisdom but that goes back years and years when the idea for the update and draw instead of just a render method for both was argued.

To say way way back you didn’t draw and update you just Rendered(){ … } and you got all sorts of horrible inherent problems with that design ideology so everyone grew out of it as you encountered those problems.

1 Like

Taking this Thread [See what I did there?] back on track, I would suggest instead of stalling your thread, how about you utilise smarter code to postpone the draw/update process.

Good Luck.

1 Like

When an Update loop takes too long to run (IsRunningSlow == true), MonoGame elects to skip draw calls in an attempt to “catch up”. This is very much by design. So, since every one of your frames is taking MUCH (~120%) too long endlessly, it can never catch up. Therefore, if you want an accurate “heavy load” test, I would suggest having most frames run at under 16.66ms and perhaps every 60th frame run with a higher wait or something like that. That would allow MonoGame to perform it’s draw-skipping, and still simulate the situation that would actually occur in a game that has a slow frame sometimes (drop the frame rate a bit).

Additionally, I would recommend looking at setting IsFixedTimeStep to false during your experiments. This releases the built-in waits that MonoGame performs on each Update call (to normally force it to run once each ~16.66ms, even when running faster than that).

Here are some good articles on the topic that you may find useful:
http://rbwhitaker.wikidot.com/time-steps
http://rbwhitaker.wikidot.com/cracking-the-game-time-problem

1 Like