为什么QueryperformanceCounter的时间与挂钟不同?

Pau*_*l L 5 delphi performancecounter

您好我使用QueryperformanceCounter来计算Delphi中的代码块.出于某种原因,使用QueryPerformanceCounter获得的毫秒数与使用秒表的挂钟时间完全不同.例如,秒表给了我大约33秒,这似乎是正确的,如果不准确,但使用QueryPerofomanceCounter将给我一个像500毫秒的数字.

通过我的代码,我可以看到QueryPerformanceFrequency给我正确的CPU CPU频率,CoreG E6600的2.4G.因此,如果刻度号是正确的,(tick number / Freq) * 1000应该给我正确的代码执行时间,但为什么不呢?

我知道,对于我想要计时的代码,QeuryPerformanceCounter可能过度杀死,因为花了几秒而不是百万秒,但我更感兴趣的是了解挂钟和QueryPerormanceCounter之间时差的原因.

我的硬件是E6600 Core2,操作系统是Windows 7 X64,如果它是相关的.

unit PerformanceTimer;

interface

uses Windows, SysUtils, DateUtils;

type TPerformanceTimer = class
  private
    fFrequency : TLargeInteger;
    fIsRunning: boolean;
    fIsHighResolution: boolean;
    fStartCount, FstopCount : TLargeInteger;
    procedure SetTickStamp(var lInt : TLargeInteger) ;
    function GetElapsedTicks: TLargeInteger;
    function GetElapsedMiliseconds: TLargeInteger;
  public
    constructor Create(const startOnCreate : boolean = false) ;
    procedure Start;
    procedure Stop;
    property IsHighResolution : boolean read fIsHighResolution;
    property ElapsedTicks : TLargeInteger read GetElapsedTicks;
    property ElapsedMiliseconds : TLargeInteger read GetElapsedMiliseconds;
    property IsRunning : boolean read fIsRunning;
end;

implementation

constructor TPerformanceTimer.Create(const startOnCreate : boolean = false) ;
begin
  inherited Create;

  fIsRunning := false;

  fIsHighResolution := QueryPerformanceFrequency(fFrequency) ;
  if NOT fIsHighResolution then
    fFrequency := MSecsPerSec;

  if startOnCreate then
    Start;
end;

function TPerformanceTimer.GetElapsedTicks: TLargeInteger;
begin
  result := fStopCount - fStartCount;
end;

procedure TPerformanceTimer.SetTickStamp(var lInt : TLargeInteger) ;
begin
  if fIsHighResolution then
    QueryPerformanceCounter(lInt)
  else
    lInt := MilliSecondOf(Now) ;
end;

function TPerformanceTimer.GetElapsedMiliseconds: TLargeInteger;
begin
  result := (MSecsPerSec * (fStopCount - fStartCount)) div fFrequency;
end;

procedure TPerformanceTimer.Start;
begin
  SetTickStamp(fStartCount) ;
  fIsRunning := true;
end;

procedure TPerformanceTimer.Stop;
begin
  SetTickStamp(fStopCount) ;
  fIsRunning := false;
end;

end.
Run Code Online (Sandbox Code Playgroud)

And*_*dré 5

这段代码只适合我,也许你可以尝试一下:

  var
    ifrequency, icount1, icount2: Int64;
    fmsec: Double;
  begin
    QueryPerformanceFrequency(ifrequency);
    QueryPerformanceCounter(icount1);
    Sleep(500);
    QueryPerformanceCounter(icount2);
    fmsec := 1000 * ((icount2 - icount1) / ifrequency);
  end;
Run Code Online (Sandbox Code Playgroud)

fmsec 约为 499.6 或类似的值。

注意:对于小数字,不要依赖 Now 或 TickCount:它们的间隔约为 10 毫秒(取决于 Windows 版本)!因此,如果您使用 Now 和 DateUtils.MillisecondsBetween,“sleep(10)”的持续时间可能会给出 0ms

注 2:不要长时间依赖 QueryPerformanceCounter,因为一天中时间可能会慢慢消失(每分钟大约 1 毫秒差异)


Dar*_*ler 2

您应该发布一个代码片段来说明问题......但我会假设您有一个错误:

Milliseconds := 1000 * ((StopCount - StartCount) / Frequency);
Run Code Online (Sandbox Code Playgroud)

如果您与秒表进行比较,您可能会采取更简单的路线,只需捕获前后的 TDateTime(通过使用Now()),然后使用 DateUtils MilliSecondSpan()方法来计算差值:

var
  MyStartDate:TDateTime;
  MyStopDate:TDateTime;
  MyTiming:Double;
begin
  MyStartDate := Now();
  DoSomethingYouWantTimed();
  MyStopDate := Now();
  MyTiming := MilliSecondSpan(MyStopDate, MyStartDate);
  DoSomethingWithTiming(MyTiming);
end;
Run Code Online (Sandbox Code Playgroud)