Search Unity

Capping framerate... or stopping 100% CPU utilisation

Discussion in 'Editor & General Support' started by seon, Mar 22, 2008.

  1. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    Ok, I would like to know peoples thoughts on best ways to cap frame-rates and stop unbounded 100% cpu utilization.

    What do we need to look for if this is happening, and what is best practice for making sure this doesnt happen in future games?

    Does keeping things in Updates mean that faster machines will just keep processing these things faster, chewing up more CPU cycles that needed?
     
  2. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    So, here is a perfect example of the problem.

    Its just a camera with a guitexture. nothing else.. no scripts, nada...

    Sits between 32-50% CPU usage in Activity monitor on my Pennryn 2.5Ghz 17" MBP. That's insane! It's not doing anything.... why is it taking so many cycles?

    This has got to be looked into by UT as we have had complaints for customers saying our games are running their CPU's at close to 100% and thats not surprising considering that an App doing nothing is sitting at up to 50% !

    I have included the project and UB app.

    I would love to hear what others are getting this running and on what hardware
     

    Attached Files:

  3. jeffcraighead

    jeffcraighead

    Joined:
    Nov 15, 2006
    Posts:
    740
    This C# script was posted a while ago and works quite well to reduce the CPU usage. Just attach it to your main controller object so that it persists across levels.


    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Threading;
    5.  
    6. public class FPSCap : MonoBehaviour {
    7.    float oldTime = 0.0F;
    8.    float theDeltaTime= 0.0F;
    9.    float curTime= 0.0F;
    10.    float timeTaken = 0.0F;
    11.    public int frameRate = 30;
    12.    
    13.    // Use this for initialization
    14.    void Start () {
    15.    theDeltaTime = (1.0F /frameRate);
    16.       oldTime = Time.realtimeSinceStartup;
    17.    }
    18.    
    19.    
    20.    // Update is called once per frame
    21.    void LateUpdate () {
    22.    curTime = Time.realtimeSinceStartup;
    23.    timeTaken = (curTime - oldTime);
    24.    if(timeTaken < theDeltaTime){
    25.       Thread.Sleep((int)(1000*(theDeltaTime - timeTaken)));
    26.    }
    27.    
    28.    
    29.    oldTime = Time.realtimeSinceStartup;
    30.    }
    31. }
    32.  
     
  4. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    I had been wondering about this, too - especially because it "happened" on my game server which is also my Web server. But then I assumed that it's simply something about "how game engines are working". After all, there's a game loop that always gets executed "as often as possible". So, aside from looking a little "weird", I don't see this 100% CPU utilization being an issue.

    On my server, the problem is not at all the game consuming 100% - the problem is more that the Webserver and SQL server take those 100% immediately away from the game whenever a request comes in. So, it seems that Unity does take as much from the processor as it gets - but when anyone else wants something, Unity doesn't hold its hands on it (a.k.a. low priority ;-) ).

    Sunny regards,
    Jashan
     
  5. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Because it's redrawing the screen as fast as it can... :)

    If you want to cap the frame count, use a script like jeffcraighead suggested.
     
  6. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    Thanks Jeff Aras,

    Exactly what I was looking for.

    This should really be a setting in the Time Project settings as it is something that should be considered/set by everyone when designing a game.
     
  7. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    Might be a really naive question, but: Why?

    I would assume that in most cases, when I have a game running this should be the only application that's running, and I would like to use all of my CPU to give me the best playing experience that's possible with my machine. Of course, with dashboard widgets and Web players, this is a bit of a different story, as the user might not even be aware he's actually "playing a game" (and maybe he really is not ;-) ).

    It might be useful for testing how the game behaves on slow machines, but my feeling is that this would be quite misleading (putting the Thread to sleep is simply something different than performing actual calculations).

    But maybe I need to learn something new ;-)

    Sunny regards,
    Jashan
     
  8. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    Ok, so if you have a game that plays fine at around 150-200 fps, which on a Mac Pro, 2.88 would sit at around 30% of CPU... why would you want your game to go to 400fps and have a Mac Pro sit at 100%? The wattage alone when running the Mac Pro at 100% is hue.. it chews energy and power consumption.

    This is from a disgruntled customer...

    I tend to agree, so would have thought that a way of truly capping performance for those machines that don't need it would be a basic thing to have in the Time settings in the project settings.
     
  9. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    Ok, this script is causing problems with my collisions.

    Not all of my OnCollisionEnter functions are firing... and yes, the game works perfectly without the script. All I do is attach it to my main game manager GO (which is persistent) and set it to 200 FPS.

    So, can someone explain to me exactly what this script is doing? By sleeping the thread for the difference of time to reduce CPU, does that mean the collider calls etc wont happen during that time? What exactly sleeps?
     
  10. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    You can always turn vsync on...that will cap the framerate.

    --Eric
     
  11. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    Turn it on where Eric? What exactly is vsync and where do I find out more about it please?
     
  12. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    That's in the quality settings: Sync to VBL. That way the framerate is capped to the screen refresh rate, which varies depending on the user's display, but is usually 60Hz for LCD screens. Also has the benefit of getting rid of screen tearing, but will reduce the framerate significantly if it drops below the refresh rate. i.e., a game normally getting 55fps on a 60Hz monitor will drop to 30fps with vsync on.

    --Eric
     
  13. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    Ok, yeah, I just experimented with that... it's no good for what I am trying to achieve. But thanks for the explanation :)
     
  14. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    Ok, that's a good point, of course... Thanks for the "update" ;-) ... Concerning the collisions: I guess the "art" is balancing the "maximum framerate" with the exactness (is that an English word?) of the collision detection, i.e. you might have to go for 50 or 100 or maybe even 150 FPS for the collision detection to work properly. Depending on your game, of course... one solution could be making the colliders bigger, if the game logic permits that without starting too look "buggy" - with TRaceON, I started with very thin walls and very small colliders, then I made everything a bit bigger and that made the collision detection much more reliable.

    Sunny regards,
    Jashan
     
  15. jeffcraighead

    jeffcraighead

    Joined:
    Nov 15, 2006
    Posts:
    740
    I'm not sure, I just tried using the script to lower my frame rate to 5 FPS in a simulation where I use OnTriggerEnter for a buoyant surface and everything worked fine, FixedUpdate seems to run in a separate thread (as would be expected) so the Thread.Sleep should only affect the number of time the drawing calls are made (which run in the Update thread). One of the UT guys will have to shed more light on how OnCollision and OnTrigger are called since I thought that those were handled in the FixedUpdate thread.

    On another note, capping at 200fps? Why so high? Unless someone has a really beefy system that cap isn't going to do much. I would think 100fps would be fine for a game. I cap at 30 for a simulation.
     
  16. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    Yes, I lowered my cap to 100 and things are working better. I chose 200 initially because I was just interested in capping for the higher end machines.

    What I have done now is set it to 100 and put it in as a game option so people can turn it on/off if they want.

    Thanks everyone for their help and feedback on this :)
     
  17. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    Hey, thanks for asking that question ;-)

    I've now added an "idle mode" to my server which goes at 10 FPS when no players are connected. As soon as players are connected, I remove the cap to get the best performance possible. I think this is very nice and I wouldn't have thought of it if I hadn't read about this issue in this thread :)

    Sunny regards,
    Jashan
     
  18. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    Glad you found it useful :)
     
  19. Brian-Kehrer

    Brian-Kehrer

    Joined:
    Nov 7, 2006
    Posts:
    411
    Doesn't sync to VBL clamp framerate to monitor refresh? Does this reduce CPU usage as well? I haven't tested it out.

    I assume internally there is some sort of busy waiting...

    I turn this on a lot to stop the screen tearing I get on these large displays.

    EDIT: I meant busy-sleep, but good to know they might busy wait, yikes.
     
  20. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Depends on the driver. At least on Windows, some drivers do busy-wait, because then they can get tiny score increases in benchmarks.
     
  21. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    So is there anyway of slowing down how many times OnGUI gets called per frame? I know it gets called a lot to make GUI stuff smooth, but it would be great to be able to slow it when we know we can, or pause it completely if we know we can. Nicholas?
     
  22. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    Not really - the GUI gets drawn on screen, so whenever there has been rendering, we need to also get the GUI in there
     
  23. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    Collision isnt' happening correctly because Aegia physics world is running full steam while your visual world is running at a capped frame rate. The thread sleep just pauses the thread but the next time the thread updates the collision is beyond the collidable object. You need to compinsate for this yourself. Unless somewhere (and yes I have not looked) there is a way to cap the physics cycles to match the visual cycles if that makes any sense at all. Just because your visual world is choppy doesn't mean your physics world is.
     
  24. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    Well, capping the game at 100 FPS is not making choppy at all, and the game runs very smoothly.

    I wasn't talking about the object going through a collider visually... I was referring to it not triggering the event, which would go against your theory because the physics should be running at normal speed?

    Ultimately I am looking for a way to reduce the unbounded CPU utilisation for those of my customers that are concerned about it.

    For instance, on my Mac Pro (8 core 2.88) our games can run at 80+ % CPU utilization. Why? Because it can. Is that good? I don't think so.
     
  25. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    For it to trigger the event, the object must acknowledge the collision (entry or what ever) to the other object, thus object overley. If the object has passed one other, you no longer have a trigger, you are out of bounds. Smooth looking yes, out of sync yes. There is no other way for me to describe what I am talking about, bottom line, your game objects are now out of sync. thread.sleep has (IMO ONLY from personal experience ONLY) just frozen the thread but the simulation continues (only from my point of view period), at the end of the day, the objects are out of sync between what shows the object and what says the object is where it is, then you loose your collision state, you loose your connection between the triggers etc. Anyway, I can never describe what I am trying to say properly and only in my minds eye.

    reduce your sleep duration until such time as your objects start to trigger better increase your sleep duration to see a loss of triggers, it all scales, the more sleep you use, the further out of sync your triggers and collisions become, the lower you reduce your sleep, the less likely you will miss a trigger and miss a collision
     
  26. AngryAnt

    AngryAnt

    Keyboard Operator

    Joined:
    Oct 25, 2005
    Posts:
    3,045
    How does that even make sense? As you said the physics thread is unaffected so how would slowing down the rendering thread affect collision in any way?
     
  27. jeffcraighead

    jeffcraighead

    Joined:
    Nov 15, 2006
    Posts:
    740
    Ant, that's what I was thinking too. :D
     
  28. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    Just try it and it will make sense.
    Ball is at 100,100,100, sleep is at 30 seconds, at the end of the sleep ball appears to be at 101,100,100, but physics motion has ball at 200,100,100, just because you pause the acutal visual ball doesn't mean the collision model is frozen in place. Same goes with triggers, one object must enter or touch another object in the same space to be considered a trigger, when you are outside of the bounds of that trigger, the event does not occur. Anyway, it is my chaos, doesn't have to make sense, it just is what it is. If it wasn't what it is then there would be zero issue with collision and triggers. Anyway at the end of the day it doesn't solve the problem other than reducing the sleep duration.

    Here is the whole issue and solution in a nutshell.
    The speed of the simulation is taking up CPU cycles where it shouldn't be. AKA issue. Frame rate needs a cap, AKA solution, sleep is not the solution period.

    The solution is to keep the simulation world in sync with the visual game world, aka new issue.

    Begining of the GO, you set a global time:
    startTime = timeGetTime()

    Do your game stuff for the game cycle loop you are in then render the scene (which is automatically controlled by UNITY)

    fps = scene.RenderScene()

    NOW we need to adjust our Physics world to our current playing field:

    This is our current time subtract our start time divide this by our target frames per second.
    fAdjust = (timeGetTime() - startTime) / fTarget

    Now it is simple, set our Physics and triggers timer to that of the current adjusted frame speed:
    PhysicsUpdate(World,fAdjust)

    You see, what everyone is overlooking is that the world is in motion and needs to have its physics cycle kept in sync with the visual world, they are NOT the same thing, they are NOT on the same thread.

    Unity handles the generation of the 2 worlds (or more) itself, out of our control, now the docs might go into how to sync up the simulation worlds (aka many simulation worlds can be ran at a time with Ageia)

    Then as I stated, you are sleeping your VISUAL world thread, you are not sleeping your PHYSICS world thread for the same duration. Different threads, different speeds.

    If this doesn't make sense, go to http://www.ageia.com/
    Register as a developer, download the SDK, read the documentation on physics worlds vs game world and setup a simulation outside of Unity. Now in your simulation, use Sleep on your game world thread and leave the simulation world running, make sure you have objects in motion, then check on collision states when the visual world continues.

    This is about all I can really explain on this, but to fix the FPS issue, sleep both the regular game thread and the physics thread and what ever thread Unity uses for triggers, that will have it all as close to sync as you can get.
     
  29. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Actually you'd never see that happening; the ball would appear to be at 200,100,100. Whatever you see on the screen is whatever the internal representation is at that exact moment. Like a series of snapshots of the game world. But the game world does not only run once every 30 seconds. There is nothing that is getting "out of sync", nor is that even possible.

    Exactly. :) This is why you shouldn't get any issues with collisions no matter what the frame rate is. Only lowering the physics frame rate would cause issues. The visuals don't matter at all with regards to collisions.

    Except that it isn't. ;) I'm not sure why Seon is having any issues; I did some testing with a couple of my games, and no matter what I set the fps cap to, OnCollisionEnter and OnTriggerEnter still always fire perfectly.

    --Eric
     
  30. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    Eric... Seon is having issues because Seon is an idiot sometimes and tries to adhere to Occam's razor, that the simplest/most obvious cause of a problem is often the reason.

    I only saw this bug after introducing the FPS Capper... so assumed that was the cause. Guess what? It aint ;) Though what it is still eludes me!
     
  31. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Ah, well...solve one mystery, and you just get another in its place. ;) Still, I guess that's progress....

    --Eric
     
  32. David-Helgason

    David-Helgason

    Moderator

    Joined:
    Mar 29, 2005
    Posts:
    1,104
    Occam is wrong at least 66% of the time :)

    d.