CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 18
  1. #1
    Join Date
    Feb 2004
    Location
    Texas, USA
    Posts
    1,206

    Creating a reliable timer

    This question concerns how to create a timer; This timer is used in the topic of a game program, but no gaming knowledge is necessary to answer.

    In the case of a small direct draw game, 30 FPS doesn't require 100% CPU on a really powerful system.

    The problem I'm having is that my 'game loop' (which is simply my message loop + my game functions) consumes 100% CPU because I use PeekMessage and while() to wait for 33ms to go by so that I can begin the next iteration. This ensures that I loop 30 times per second (at most)

    The thing is, this while loop consumes 100% CPU while it is waiting for 33ms to go by. I don't like this. Here is my loop:

    Code:
            while(true)
            {
                Timer = GetTickCount();
    
                if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
                {
                    if(msg.message == WM_QUIT)
                        break;
    
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
    
                if(AllowGame)
                {
                    GameInput();
                    GameAI();
                    GameRender();
                }
    
                while(GetTickCount() - Timer < (unsigned)1000 / FPS);
            }
    Now, if I used Sleep(), the CPU would barely use 20%, because Sleep doesn't hog the CPU like while() does. The thing is, Sleep() isn't as accurate by the millisecond as GetTickCount is.

    I need a way to be able to limit my iterations as efficiently as possible by milliseconds, but WITHOUT consuming more CPU that needed.

    Any suggestions?

  2. #2
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652

    Re: Creating a reliable timer

    Take a look at waitable timers...for additional information you might take a look at this article. It is a very comprehensive timer tutorial.

  3. #3
    Join Date
    Feb 2004
    Location
    Texas, USA
    Posts
    1,206

    Re: Creating a reliable timer

    Thanks Andreas! Wow I've never seen you not able to answer a question... how long have you been a programmer? You seem to know it all

  4. #4
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652

    Re: Creating a reliable timer

    You are welcome...yes, I am doing this for quite some time now...but believe me, there are far more question that I cannot answer than the other way round...

  5. #5
    Join Date
    Feb 2004
    Location
    Texas, USA
    Posts
    1,206

    Re: Creating a reliable timer

    Hmm, well I read the link and I actually attempted to do this myself, but there is a bit of confusion with the parameters. I made the following function in my class:

    Code:
    void DirectX_Utils::FrameTimer(int ms)
    {
        DueTime.QuadPart = ((int)ms * 10000);
        SetWaitableTimer(hTimer, &DueTime, 0, NULL, NULL, FALSE);
    }
    You submit a time in miliseconds, and the function blocks for that many miliseconds and returns. Kind of like sleep, but more efficient by the milisecond. The thing is, I don't understand the difference between the second and third parameters. I ran through debug with 1000 miliseconds, and it does NOTHING.

    DueTime is a LARGE_INTEGER structure, and hTimer is a HANDLE. I declare these elsewhere in the class.

  6. #6
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652

    Re: Creating a reliable timer

    Well...haven't used waitable timers for a long time...so, let's see whether I get this straight...

    The second parameter is the due time of the timer. The thits parameter is the interval the timer will be signaled.

    The due time can be either specified as an absolute (positive) or relative (negative) value. Since it is internally based on the FILETIME you would need to take this into account. In your example, you are setting an absolute value, however, this value is way in the past due to the underlying FILETIME which represents the number of 100-nanosecond intervals since January 1, 1601 (UTC).

    So...in order to work with absolute values, you would first need to get the actual time and add the number of 100-nanosecond intervals of your waiting time.

    Using a relative value is much easier...in your example...
    Code:
    void DirectX_Utils::FrameTimer(int ms)
    {
        DueTime.QuadPart = -((int)ms * 10000);
        SetWaitableTimer(hTimer, &DueTime, 0, NULL, NULL, FALSE);
    }
    should work...

  7. #7
    Join Date
    Feb 2004
    Location
    Texas, USA
    Posts
    1,206

    Re: Creating a reliable timer

    What is the difference between absolute and relative timings?

  8. #8
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652

    Re: Creating a reliable timer

    At 10 PM is absolute...in 10 minutes is relative...

  9. #9
    Join Date
    Feb 2004
    Location
    Texas, USA
    Posts
    1,206

    Re: Creating a reliable timer

    Hmm, adding the - didn't help....

    Here, I'll paste more code:

    Code:
    // Class function which does the actual waiting
    
    
    void DirectX_Utils::Sleep(int ms)
    {
        DueTime.QuadPart = -((int)ms * 10000);
        SetWaitableTimer(hTimer, &DueTime, 0, NULL, NULL, FALSE);
    }
    Code:
    // My message loop (prepares the timing)
    
            while(true)
            {
                Timer = (int)GetTickCount();
    
                if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
                {
                    if(msg.message == WM_QUIT)
                        break;
    
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
    
                if(AllowGame)
                {
                    GameInput();
                    GameAI();
                    GameRender();
                }
    
                if((Timer = 1000 / FPS - ((signed)GetTickCount() - Timer)) > 0)
                    dxlib->Sleep(Timer);
            }
    I'm confused... no worky

  10. #10
    Join Date
    Mar 2004
    Location
    (Upper-) Austria
    Posts
    2,899

    Re: Creating a reliable timer

    I haven't read the entire thread but there is something that confuses me:

    Code:
    if((Timer = 1000 / FPS - ((signed)GetTickCount() - Timer)) > 0)
    This assignment opertor, didn't you mean the comparision operator ==? Because otherwise this peace of code would be useless:

    Code:
    Timer = (int)GetTickCount();
    I am not offering technical guidiance via email or IM
    Come on share your photo with us! CG members photo album!
    Use the Code Tags!

  11. #11
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652

    Re: Creating a reliable timer

    Well...how do you know it is not working...I mean where are you actually waiting on the timer to get notified about it? Take a look at the following example:
    Code:
    #include <iostream>
    #include <windows.h>
    #include <conio.h>
    
    int main()
    {
      HANDLE hTimer = 0;
      LARGE_INTEGER liTime;
    
      liTime.QuadPart=-100000000;
    
      // Create a waitable timer.
      hTimer = ::CreateWaitableTimer(0, TRUE, "WaitableTimer");
      if(!hTimer)
      {
        std::cout << "Could not create waitable timer (Error "
                  << ::GetLastError() << ")" << std::endl;
        ::Sleep(5000);
        return -1;
      }
    
      std::cout << "Wait for 10 seconds..." << std::endl;
    
      // Set timer
      if(!::SetWaitableTimer(hTimer, &liTime, 0, 0, 0, FALSE))
      {
        std::cout << "Could not set waitable timer (Error "
                  << ::GetLastError() << std::endl;
        ::Sleep(5000);
        return -1;
      }
    
      // Wait for timer
      if(::WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0)
        std::cout << "Could not wait for timer object (Error "
                  << ::GetLastError() << std::endl;
      else
        std::cout << "Time elapsed" << std::endl;
    
      // Wait for keystroke
      _getch();
    
      return 0;
    }

  12. #12
    Join Date
    Feb 2004
    Location
    Texas, USA
    Posts
    1,206

    Re: Creating a reliable timer

    I know its not working because I look at my CPU usage during program execution. It should not be 100%!!

    When I test my timer, my game functions are commented out (because I do not need them) so the entire loop completes in less than or equal to 33 ms. So this means it should WAIT 33 ms, but it doesn't.


    NoHero:

    Let me explain to you how it works....

    Code:
    // Lets assume, in this case, GetTickCount() will return 4456 and Timer is 4455
    
    // First we simplify what is in the parenthesis
    // This will give us how much time has passed since the last call to GetTickCount()
    if((Timer = 1000 / FPS - ((signed)GetTickCount() - Timer)) > 0)
    
    // Now, we want our loop to execute 30 frames per second.
    // There are 1000 ms in 1 second, so to get 30 frames a second
    // we divide 1000 by 30. (FPS = 30)
    // By subtracting 1 from 33.33, we get how much more time 
    // we must wait before 1 frame can be allowed to pass.
    // Total execution time took 1 ms, so now 32 more ms must wait.
    if((Timer = 1000 / 30 - 1) > 0)
    if((Timer = 33.333 - 1) > 0)
    if((Timer = 32.333) > 0)
    
    // Now, we somehow have to send the amount of time to wait to
    // the Sleep function. We do this by over-riding the value in Timer with
    // how much time we must wait. This saves from having to declare an
    // extra variable.
    // We want to make sure the time we have to wait is between 33.33 and 0.
    // If it is less than 0, then the frame took as long or longer than it should have.
    // We will not tell our function to sleep if our time to wait is less than or equal to 0.
    
    // So, timer is now equal to 32, which is greater than 0.
    // So this IF statement evaluates true. We now tell our game
    // how long to sleep:
    
    dxlib->Sleep(Timer); (or, technically: dxlib->Sleep(32);)

  13. #13
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652

    Re: Creating a reliable timer

    I will repeat myself....where are you actually waiting for the timer to be triggered? You are not passing a callback neither did you mention any call to 'WaitForSingleObject()'...take a look again at the example in my previous post...

  14. #14
    Join Date
    Feb 2004
    Location
    Texas, USA
    Posts
    1,206

    Re: Creating a reliable timer

    Oh, ****... I didn't know you had to wait on it

    I thought the function did the waiting. But okay, it works now! Thank you!

  15. #15
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652

    Re: Creating a reliable timer

    Quote Originally Posted by MrDoomMaster
    I thought the function did the waiting. But okay, it works now! Thank you!
    No problem...you are welcome...

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured