Page 3 of 6 FirstFirst 12345 ... LastLast
Results 21 to 30 of 52

Thread: Gettickcount and the rest...

  1. #21

    Gettickcount and the rest...

    Add:
    [pascal]timeBeginPeriod(1); // this could be at start of program
    .....
    { here should be your high precision code with timeGetTime calls }
    .....
    timeEndPeriod(1); // this could be at the end of program[/pascal]
    There are only 10 types of people in this world; those who understand binary and those who don't.

  2. #22

    Gettickcount and the rest...

    BREAKTHROUGH UNITED

    THANKYOU CLOOTIE! That seems to have done it also sorts out normal timers that I had issues with, like dxtimer and threadedtimer

    What was the problem? Why didn't it work before?

    Logically it should work without that code?

    Do tell

    btw: 18th July was my birthday, so I guess after around 2 years of this problem, it is my present

  3. #23

    Gettickcount and the rest...



    timeBeginPeriod() increases internal precision of Windows timer. From default of 10-20 (? - I cant't recall this without documentation) to values you passed to it. One of the side-effects: Windows start to switch concurrently running threads with precision of timeBeginPeriod too (technicaly this means that tBP sets threads time-slice).
    There are only 10 types of people in this world; those who understand binary and those who don't.

  4. #24

    Gettickcount and the rest...

    would you go about doing loops any differently? Or would you, like me, be forced to use timebeginperiod?

  5. #25

    Gettickcount and the rest...

    I prefer to use QueryPerfomanceCounter / QueryPerformancefrequency.
    And by the way: DX9 invokes timeBeginPeriod(1) automaticaly (at the initialization)...
    There are only 10 types of people in this world; those who understand binary and those who don't.

  6. #26

    Gettickcount and the rest...

    hmmm I hear that on certain machines, there is a bug which can propell the timer a certain no of secs into the future (no i meant a no of seconds are added on...skipped, its just I have been revising paradox theory and back to the future haha) using that method.

    In any case when you said DX9, you are referring to my DXDIAG question? And by that, I also take it msn must also, somewhere invoke Timenbeginperiod(1)?

  7. #27

    Gettickcount and the rest...

    "Jumping" behaviour of QPC AFAIK is happens only on really old motherboards of Pentium1 era. But in this thread fraggle already posted link stating other (more modern) bug in QPC implementations on different platforms: http://www.virtualdub.org/blog/pivot/entry.php?id=106


    By DX9 I mean any application that initializes Direct3D9. And calling timeBeginPeriod has system level influence.
    There are only 10 types of people in this world; those who understand binary and those who don't.

  8. #28

    Gettickcount and the rest...

    well little more to say except, thanks for making my birthday and I think your signiture is pretty witty 2 kinds of people....1 and 0...yes very witty

  9. #29

    Gettickcount and the rest...

    The fix for multiple CPUs is easy. Call SetThreadAffinity() to force your process thread to run on one CPU. Then you will not get the effect of the TSC or QPC jumping back and forth due to the thread being switched from one CPU to the other.

    Here is the code for a better timer class derived from a C++ class that I found a few years back. It uses both the QPC and timeGetTime to solve the problem of inaccurate QPC clocks.
    Code:
    // Original C++ source by Oleg Pudeyev
    // Converted from original C++ source by Steve 'Sly' Williams
    // Converted to use ticks internally instead of seconds for greater accuracy
    //
    // Original comments:
    // I took timer and frame rate code from DXUtil.h/cpp (common DX sample code).
    // You can find it in DXSDK\Samples\Multimedia\Common\Include and Src.
    // Instead of using a single function with static data, I organized the code into
    // classes, which allows for additional flexibility.
    // Initialization (mmtime/performance frequency selection) is now performed on startup,
    // in a dedicated class. I also added timeBeginPeriod/timeEndPeriod calls.
    // CFrameRateCounterEx is my own creation.
    //
    
    // This code fixes the "feature" described in Q274323,
    // "Performance Counter Value May Unexpectedly Leap Forward":
    // http://support.microsoft.com/default.aspx?scid=kb;en-us;Q274323
    
    unit BetterTimer;
    
    interface
    
    type
      TBetterTimer = class
      private
        // Time elapsed before last pause, or 0 if the timer was never paused
        m_ElapsedTime: Int64;
        // Time in 'timer time' (seconds) when this timer was last resumed
        m_ResumedTimeStamp: Int64;
        // Time in QueryPerformanceTimer-counts converted to seconds
        // when this timer was last resumed
        m_LastTimeStampQPC: Int64;
        // The same time in milliseconds as obtained from timeGetTime
        m_LastTimeStampMMT: Cardinal;
        // A counter indicating whether the counter is active.
        // If it is greater than zero, the counter is running, otherwise it is paused
        m_Running: Integer;
      public
        constructor Create;
        function GetTime: Single;
        procedure Pause;
        procedure Reset;
        procedure Resume;
      end;
    
    implementation
    
    uses
      Windows, MMSystem, SysUtils;
    
    // The maximum deviation from timeGetTime reading that we will tolerate, in milliseconds
    const
      PerfCounterTolerance = 1000;
    
    var
      // This variable is TRUE if performance counter is available
      gs_HavePerformanceCounter: Boolean = False;
      // If performance counter is available, this variable contains 1/its resolution -- number of seconds in each count.
      // It's a floating point value mostly for convenience.
      gs_CountsPerSecond: Int64;
    
    { TBetterTimer }
    
    constructor TBetterTimer.Create;
    begin
      inherited;
      // Start and reset the timer
      m_Running := 1;
      Reset();
    end;
    
    function TBetterTimer.GetTime: Single;
    var
      QPCTime, DeltaQPC, TimeDelta: Int64;
      MMTTime, DeltaMMT, DeltaQPCinMS: DWORD;
    begin
      Result := m_ElapsedTime / gs_CountsPerSecond;
    
      // If the timer is paused, no time has passed since the pause time
      // and all passed time is stored in elapsed time variable, so return that
      if m_Running <= 0 then
        Exit;
    
      // Otherwise, retrieve current time, subtract last resumed time from it, add
      // elapsed time, and return the result adjusted for possible QPC leaps
      if gs_HavePerformanceCounter then
      begin
        // The code is the same as in Pause function
        // Get current time in ticks
        QueryPerformanceCounter&#40;QPCTime&#41;;
        // Determine the time difference between this and previous QPC query
        DeltaQPC &#58;= QPCTime - m_LastTimeStampQPC;
        // Get current mmtimer time
        MMTTime &#58;= timeGetTime&#40;&#41;;
        // And the difference between currnent and previous mmtimer query
        DeltaMMT &#58;= MMTTime - m_LastTimeStampMMT;
        // Check if the performance counter leaped forward,
        // which is when difference in values returned by QPC and mmtimer is more than
        // the predefined PerfCounterTolerance value
        // Since all times are returned as unsigned variables, care must be taken when subtracting
        // because we don't want leap adjustment to be applied in case mmtimer is lagging behind QPC
        DeltaQPCinMS &#58;= DeltaQPC * 1000 div gs_CountsPerSecond;
        if &#40;DeltaQPCinMS > DeltaMMT&#41; and &#40;DeltaQPCinMS - DeltaMMT > PerfCounterTolerance&#41; then
        begin
          // Performance counter leaped forward
          // Adjust the elapsed time by the difference between QPC and mmtimer delta times
          m_ElapsedTime &#58;= m_ElapsedTime - DeltaQPC - DeltaMMT;
        end;
        // Calculate total delta time since timer was reset
        TimeDelta &#58;= QPCTime - m_ResumedTimeStamp + m_ElapsedTime;
        // Update current timer timestamps
        m_LastTimeStampQPC &#58;= QPCTime;
        m_LastTimeStampMMT &#58;= MMTTime;
        // Return calculated delta
        Result &#58;= TimeDelta / gs_CountsPerSecond;
      end
      else
      begin
        // If we're using mmtimer, just return the time passed since last resume
        // plus the elapsed time that passed before last resume
        // No adjustments are necessary
        Result &#58;= &#40;timeGetTime&#40;&#41; - m_ElapsedTime + m_ResumedTimeStamp&#41; / gs_CountsPerSecond;
      end;
    end;
    
    procedure TBetterTimer.Pause;
    var
      QPCTime, DeltaQPC&#58; Int64;
      MMTTime, DeltaMMT, DeltaQPCinMS&#58; DWORD;
    begin
      Dec&#40;m_Running&#41;;
      // Allow for nested pause/resume calls.
      // Only pause if active count reaches zero
      if m_Running <> 0 then
        Exit;
    
      // Update the elapsed time
      if gs_HavePerformanceCounter then
      begin
        // Get current time in ticks
        QueryPerformanceCounter&#40;QPCTime&#41;;
        // Determine the time difference between this and previous QPC query
        DeltaQPC &#58;= QPCTime - m_LastTimeStampQPC;
        // Get current mmtimer time
        MMTTime &#58;= timeGetTime&#40;&#41;;
        // And the difference between currnent and previous mmtimer query
        DeltaMMT &#58;= MMTTime - m_LastTimeStampMMT;
        // Check if the performance counter leaped forward,
        // which is when difference in values returned by QPC and mmtimer is more than
        // the predefined PerfCounterTolerance value
        // Since all times are returned as unsigned variables, care must be taken when subtracting
        // because we don't want leap adjustment to be applied in case mmtimer is lagging behind QPC
        DeltaQPCinMS &#58;= DeltaQPC * 1000 div gs_CountsPerSecond;
        if &#40;DeltaQPCinMS > DeltaMMT&#41; and &#40;DeltaQPCinMS - DeltaMMT > PerfCounterTolerance&#41; then
        begin
          // Performance counter leaped forward
          // Adjust the elapsed time by the difference between QPC and mmtimer delta times
          m_ElapsedTime &#58;= m_ElapsedTime - DeltaQPC - DeltaMMT;
        end;
        // Add the time passed since last resume to the elapsed time variable
        m_ElapsedTime &#58;= m_ElapsedTime + QPCTime - m_ResumedTimeStamp;
        // Don't update last polled time stamps for QPC and mmtimer
        // since they will be updated in Resume method
      end
      else
      begin
        // If we are using mmtimer, just add the time passed since last resume time
        // to the elapsed time variable
        m_ElapsedTime &#58;= m_ElapsedTime + timeGetTime&#40;&#41; + m_ResumedTimeStamp;
      end;
      // The timer is now paused
    end;
    
    procedure TBetterTimer.Reset;
    begin
      // This function initializes or resets the timer
      if gs_HavePerformanceCounter then
      begin
        // Retrieve the last resumed time stamp
        QueryPerformanceCounter&#40;m_ResumedTimeStamp&#41;;
        m_LastTimeStampQPC &#58;= m_ResumedTimeStamp;
        // To correct for unexpected leaps, retrieve the same time from the multimedia timer
        m_LastTimeStampMMT &#58;= timeGetTime&#40;&#41;;
      end
      else
      begin
        // There are no issues with multimedia timer, so just get the current value
        // and write it to the last resumed stamp
        m_ResumedTimeStamp &#58;= timeGetTime&#40;&#41;;
      end;
    
      // Timer hasn't been paused, so set elapsed time to zero
      m_ElapsedTime &#58;= 0;
    end;
    
    procedure TBetterTimer.Resume;
    begin
      Inc&#40;m_Running&#41;;
      // Allow for nested pause/resume calls.
      // Only resume if active count reaches one
      if m_Running <> 1 then
        Exit;
    
      // Update the last resumed time stamp
      if gs_HavePerformanceCounter then
      begin
        // Get current time in ticks
        QueryPerformanceCounter&#40;m_ResumedTimeStamp&#41;;
        m_LastTimeStampQPC &#58;= m_ResumedTimeStamp;
        // Get the current time from mmtimer as well for QPC adjustments
        m_LastTimeStampMMT &#58;= timeGetTime&#40;&#41;;
      end
      else
      begin
        // For mmtimer, just retrieve the current time
        m_ResumedTimeStamp &#58;= timeGetTime&#40;&#41;;
      end;
    end;
    
    var
      // Set the highest resolution for the multimedia timer
      tc&#58; TIMECAPS;
    
    initialization
      // QueryPerformanceFrequency returns a BOOL value indicating if a performance counter is available
      gs_HavePerformanceCounter &#58;= QueryPerformanceFrequency&#40;gs_CountsPerSecond&#41;;
      if not gs_HavePerformanceCounter then
        gs_CountsPerSecond &#58;= 1000;
      // Retrieve timer caps, which contain resolution range
      timeGetDevCaps&#40;@tc, SizeOf&#40;tc&#41;&#41;;
      // Set resolution with this call
      timeBeginPeriod&#40;tc.wPeriodMin&#41;;
    
    finalization
      // Don't retrieve the caps again to be absolutely sure we restore the same value that we set
      // Restore old resolution
      timeEndPeriod&#40;tc.wPeriodMin&#41;;
    
    end.

  10. #30

    Gettickcount and the rest...

    This same problem can occur on a HyperThreading processor as well. Try placing SetThreadAffinityMask(GetCurrentThread(), 1); in your application initialization code (NOT FORM CODE, APP CODE).

    Sorry, some how I overlooked this thread till now . As the post above said, that typically fixes any issues, personally I've modified my timer units to have this in their initialization.

Page 3 of 6 FirstFirst 12345 ... LastLast

Bookmarks

Posting Permissions

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