2012-12-18 8 views
10

Ich muss ein einfaches Leistungs-Benchmarking in Free Pascal implementieren. In Delphi verwende ich TStopWatch Datensatz von der Diagnose-Einheit, was kann ich in Free Pascal/Lazarus verwenden? HierWas ist das Free Pascal-Pendant zu Delphi's TStopWatch?

+0

Je nach Ihren Anforderungen haben Sie möglicherweise genug, indem Sie QueryPerformanceFrequency/QueryPerformanceCounter in Windows aufrufen. – jachguate

+0

Sicher kann ich meinen eigenen Wrapper für QueryPerformanceXXX API schreiben, vielleicht hat Free Pascal seine eigene plattformübergreifende Lösung. – kludg

+0

Ich bin nicht an Freepascal gewöhnt. Diese http://code.google.com/p/phocis/source/browse/trunk/lib/StopWatch.pas?r=34 ist "Früh Beta: Verschiedene Freepascal Funktionen und" Stuff "" – bummi

Antwort

6

ist eine Implementierung nach dem Vorbild Delphi Online-doc:

{  High frequency stop watch implemntation. 
     Copyright (c) 2012 by Inoussa OUEDRAOGO 

     This source code is distributed under the Library GNU General Public License 
     with the following modification: 

      - object files and libraries linked into an application may be 
       distributed without source code. 

     This program is distributed in the hope that it will be useful, 
     but WITHOUT ANY WARRANTY; without even the implied warranty of 
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

    **********************************************************************} 

{$IFDEF FPC} 
    {$mode objfpc}{$H+} 
    {$modeswitch advancedrecords} 
{$ENDIF} 

{$IFDEF MSWINDOWS} 
    {$IFNDEF WINDOWS} 
     {$DEFINE WINDOWS} 
    {$ENDIF WINDOWS} 
{$ENDIF MSWINDOWS} 

unit stopwatch; 

interface 
uses 
    SysUtils 
    {$IFDEF LINUX} 
    ,unixtype, linux 
    {$ENDIF LINUX} 
    ; 

type 

    { TStopWatch } 

    TStopWatch = record 
    private 
    const 
     C_THOUSAND = 1000; 
     C_MILLION = C_THOUSAND * C_THOUSAND; 
     C_BILLION = C_THOUSAND * C_THOUSAND * C_THOUSAND; 
     TicksPerNanoSecond = 100; 
     TicksPerMilliSecond = 10000; 
     TicksPerSecond  = C_BILLION div 100; 
    Type 
     TBaseMesure = 
     {$IFDEF WINDOWS} 
      Int64; 
     {$ENDIF WINDOWS} 
     {$IFDEF LINUX} 
      TTimeSpec; 
     {$ENDIF LINUX} 
    strict private 
    class var FFrequency : Int64; 
    class var FIsHighResolution : Boolean; 
    strict private 
    FElapsed : Int64; 
    FRunning : Boolean; 
    FStartPosition : TBaseMesure; 
    strict private 
    procedure CheckInitialization();inline; 
    function GetElapsedMilliseconds: Int64; 
    function GetElapsedTicks: Int64; 
    public 
    class function Create() : TStopWatch;static; 
    class function StartNew() : TStopWatch;static; 
    class property Frequency : Int64 read FFrequency; 
    class property IsHighResolution : Boolean read FIsHighResolution; 
    procedure Reset(); 
    procedure Start(); 
    procedure Stop(); 
    property ElapsedMilliseconds : Int64 read GetElapsedMilliseconds; 
    property ElapsedTicks : Int64 read GetElapsedTicks; 
    property IsRunning : Boolean read FRunning; 
    end; 

resourcestring 
    sStopWatchNotInitialized = 'The StopWatch is not initialized.'; 

implementation 
{$IFDEF WINDOWS} 
uses 
    Windows; 
{$ENDIF WINDOWS} 

{ TStopWatch } 

class function TStopWatch.Create(): TStopWatch; 
{$IFDEF LINUX} 
var 
    r : TBaseMesure; 
{$ENDIF LINUX} 
begin 
    if (FFrequency = 0) then begin 
{$IFDEF WINDOWS} 
    FIsHighResolution := QueryPerformanceFrequency(FFrequency); 
{$ENDIF WINDOWS} 
{$IFDEF LINUX} 
    FIsHighResolution := (clock_getres(CLOCK_MONOTONIC,@r) = 0); 
    FIsHighResolution := FIsHighResolution and (r.tv_nsec <> 0); 
    if (r.tv_nsec <> 0) then 
     FFrequency := C_BILLION div r.tv_nsec; 
{$ENDIF LINUX} 
    end; 
    FillChar(Result,SizeOf(Result),0); 
end; 

class function TStopWatch.StartNew() : TStopWatch; 
begin 
    Result := TStopWatch.Create(); 
    Result.Start(); 
end; 

procedure TStopWatch.CheckInitialization(); 
begin 
    if (FFrequency = 0) then 
    raise Exception.Create(sStopWatchNotInitialized); 
end; 

function TStopWatch.GetElapsedMilliseconds: Int64; 
begin 
    {$IFDEF WINDOWS} 
    Result := ElapsedTicks * TicksPerMilliSecond; 
    {$ENDIF WINDOWS} 
    {$IFDEF LINUX} 
    Result := FElapsed div C_MILLION; 
    {$ENDIF LINUX} 
end; 

function TStopWatch.GetElapsedTicks: Int64; 
begin 
    CheckInitialization(); 
{$IFDEF WINDOWS} 
    Result := (FElapsed * TicksPerSecond) div FFrequency; 
{$ENDIF WINDOWS} 
{$IFDEF LINUX} 
    Result := FElapsed div TicksPerNanoSecond; 
{$ENDIF LINUX} 
end; 

procedure TStopWatch.Reset(); 
begin 
    Stop(); 
    FElapsed := 0; 
    FillChar(FStartPosition,SizeOf(FStartPosition),0); 
end; 

procedure TStopWatch.Start(); 
begin 
    if FRunning then 
    exit; 
    FRunning := True; 
{$IFDEF WINDOWS} 
    QueryPerformanceCounter(FStartPosition); 
{$ENDIF WINDOWS} 
{$IFDEF LINUX} 
    clock_gettime(CLOCK_MONOTONIC,@FStartPosition); 
{$ENDIF LINUX} 
end; 

procedure TStopWatch.Stop(); 
var 
    locEnd : TBaseMesure; 
    s, n : Int64; 
begin 
    if not FRunning then 
    exit; 
    FRunning := False; 
{$IFDEF WINDOWS} 
    QueryPerformanceCounter(locEnd); 
    FElapsed := FElapsed + (UInt64(locEnd) - UInt64(FStartPosition)); 
{$ENDIF WINDOWS} 
{$IFDEF LINUX} 
    clock_gettime(CLOCK_MONOTONIC,@locEnd); 
    if (locEnd.tv_nsec < FStartPosition.tv_nsec) then begin 
    s := locEnd.tv_sec - FStartPosition.tv_sec - 1; 
    n := C_BILLION + locEnd.tv_nsec - FStartPosition.tv_nsec; 
    end else begin 
    s := locEnd.tv_sec - FStartPosition.tv_sec; 
    n := locEnd.tv_nsec - FStartPosition.tv_nsec; 
    end; 
    FElapsed := FElapsed + (s * C_BILLION) + n; 
{$ENDIF LINUX} 
end; 

end. 
+2

Es funktioniert nicht unter Windows. Die verstrichene Zeit kann nicht gelesen werden, bevor die Stoppuhr gestoppt wurde und die resultierenden Werte zeigen nichts Brauchbares. – Wosi

4

Werfen Sie einen Blick auf TJclCounter von Projekt Jedi. Die Implementierung ist noch ausgeklügelter als Delphis TStopwatch, indem der Aufruf-Overhead von QueryPerformanceCounter berücksichtigt wird.