Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Windows.GetTickCount64 auch unter Windows XP? (https://www.delphipraxis.net/194048-windows-gettickcount64-auch-unter-windows-xp.html)

Glados 11. Okt 2017 10:41

Windows.GetTickCount64 auch unter Windows XP?
 
Heute habe ich das erste mal von Windows.GetTickCount64 gehört. Kann man das auch unter Windows XP nutzen oder benötigt man für Windows XP diesen Workaround?
http://www.delphipraxis.net/711170-post5.html

himitsu 11. Okt 2017 11:18

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Was steht dort MSDN-Library durchsuchenGetTickCount64 in den "Requirements"? :zwinker:

Also ja, vor Windows 8 gibt es das nicht und man braucht was Anderes.

Glados 11. Okt 2017 11:47

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Heißt also das Andere ist dein Code da oben? :P

Braucht man denn irgendwelche Fallunterscheidungen je nach Betriebssystem oder kann man einfach die Unit oben nutzen?

Wenn ich das hier richtig verstehe sollte das doch schon als "Fallunterscheidung" reichen
Delphi-Quellcode:
GetTickCount64 := GetProcAddress(GetModuleHandle('Kernel32.dll'), 'GetTickCount64'); // Für alles ab Windows 8
if @GetTickCount64 = nil then // für alles vor Windows 8
 //

himitsu 11. Okt 2017 11:56

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Jupp, entweder die WinAPI oder wenn nicht existent, dann wird automatisch die Ersatzfunktion verwendet.

Zacherl 11. Okt 2017 12:05

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Hier gibt es dazu noch einen Artikel mit Workarounds:
http://terryto-blog.tumblr.com/post/...4-alternatives

Glados 11. Okt 2017 12:50

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Zacherl, dein Artikel hat mich neugierig gemacht und die Schnelligkeit von _GetTickCount64 geprüft.

bei 999.999 aufrufen dauert die Ausführung schon knapp 400ms. Windows.GetTickCount54 braucht nur knapp 25ms.

Zacherl 11. Okt 2017 13:30

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Welche der Versionen hast du denn verwendet? Die mit dem manuellen Overflow Check sollte die Performance nicht nennenswert verschlechtern (laut Artikel ist sie ja angablich sogar besser als die native MSDN-Library durchsuchenGetTickCount64 API).

Glados 11. Okt 2017 13:34

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Ich habe himitu's Version (Link erster Beitrag) verwendet. Mit den anderen kann ich nichts anfangen, da es kein Delphi-Code ist.

Mehr als das hier bekomme ich nicht hin und selbst das ist bestimmt noch falsch
Delphi-Quellcode:
var
 high, lastLow: Int64;
begin
 high := 0;
 low := GetTickCount();

 if lastLow > low then
  // high += 0x100000000I64; ...

 lastLow = low;

 // return high | (ULONGLONG)low;
end;

Zacherl 11. Okt 2017 13:44

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Sollte in etwa so aussehen:
Delphi-Quellcode:
threadvar
  High: UInt64;
  LastLow: Cardinal;

function _GetTickCount64: UInt64; inline;
var
  Low: Cardinal;
begin
  Low := GetTickCount;
  if (LastLow > Low) then
  begin
    High := High + $0000000100000000;
  end;
  LastLow := Low;
  Result := High or Low;
end;
Ist etwas weniger als halb so performant wie die native Funktion, aber immer noch deutlich schneller als mit MSDN-Library durchsuchenQueryPerformanceCounter. Wenn du garantiert nur einen Thread hast, kannst du das
Delphi-Quellcode:
threadvar
auch durch
Delphi-Quellcode:
var
ersetzen - dann ist die Funktion in etwa gleich schnell wie die native Variante.

Glados 11. Okt 2017 14:07

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Ich habe das jetzt so gelößt

Delphi-Quellcode:
unit uGetTickCount64;

interface

uses
 Winapi.Windows, System.SysUtils;

threadvar High: UInt64;
LastLow:
Cardinal;

type
 TGetTickCount = class
 public
  class function GetTickCount64: UInt64; inline;
 end;

implementation

class function TGetTickCount.GetTickCount64: UInt64;
var
 Low: Cardinal;
begin
 if System.SysUtils.TOSVersion.Major >= 6 then // alles ab Windows Vista
  Result := Winapi.Windows.GetTickCount64
 else // alles vor Windows Vista
  begin
   Low := GetTickCount;
   if (LastLow > Low) then
    High := High + $0000000100000000;

   LastLow := Low;
   Result := High or Low;
  end;
end;

end.

Neutral General 11. Okt 2017 14:11

AW: Windows.GetTickCount64 auch unter Windows XP?
 
PS: Klassen sind optional und nicht immer notwendig oder sinnvoll :duck:

Zacherl 11. Okt 2017 14:13

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Zitat:

Zitat von Neutral General (Beitrag 1383109)
PS: Klassen sind optional und nicht immer notwendig oder sinnvoll :duck:

:thumb: Würde stattdessen auch einfach eine freistehende Funktion (ggfls. in einer seperaten Unit) bevorzugen.

Wenn es doch umbedingt in einer "Klasse" sein soll, dann klatsch noch ein
Delphi-Quellcode:
static
vor das
Delphi-Quellcode:
inline
und mach das
Delphi-Quellcode:
class
zu
Delphi-Quellcode:
record
, dann sparst du dir noch ein (verstecktes) Funktionsargument und zusätzlich die (nicht benötigten) RTTI-Infos für die Klasse. Und dann kannst du auch die
Delphi-Quellcode:
threadvar
s direkt noch mit in den Record übernehmen.

Glados 11. Okt 2017 14:13

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Das weiß ich =)
Ich benutze sie sehr gerne und überall in meinen Units.

Wenn ich irgendwo im Code stehen habe
Delphi-Quellcode:
GetTickCount64
dann kann das von Winapi.Windows kommen oder aus der eigenen Unit - kommt ganz auf die Reihenfolge in den uses an.
Wenn ich aber
Delphi-Quellcode:
TGetTickCount.GetTickCount64
sehe weiß ich genau wo es herkommt.

Edit
Klar ich kann auch ohne Klasse arbeiten und schreibe
Delphi-Quellcode:
MeineUnit.GetTickCount64
aber dann bekomme ich ggf. Probleme wenn ich die Unit mal umbenennen will.

So?
Delphi-Quellcode:
type
 TGetTickCount = record
 public
  class function GetTickCount64: UInt64; static; inline;
 end;

Zacherl 11. Okt 2017 14:16

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Delphi-Quellcode:
type
  TTest = record
  strict private
    class threadvar High: UInt64;
    class threadvar LastLow: Cardinal;
  public
    class function GetTickCount64: UInt64; static; inline;
  end;

{ TTest }

class function TTest.GetTickCount64: UInt64;
begin
  // ...
end;

Dalai 11. Okt 2017 14:29

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Zitat:

Zitat von himitsu (Beitrag 1383089)
Also ja, vor Windows 8 gibt es das nicht [...]

Auch wenn im weiter oben geposteten Code schon die richtige
Delphi-Quellcode:
if
-Bedingung benutzt wird: GetTickCount64 gibt's ab Vista, nicht erst ab Win8. Vermutlich haben deine Augen der Angabe "Windows Phone 8" zuviel Aufmerksamkeit geschenkt ;).

Grüße
Dalai

Glados 11. Okt 2017 14:45

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Zitat:

dann sparst du dir noch ein (verstecktes) Funktionsargument und zusätzlich die (nicht benötigten) RTTI-Infos für die Klasse
Alles erledigt. Der Speicherverbrauch ist sogar etwas gesunken.

Durch die Änderung von class zu record habe ich sogar noch ein paar Compilerfehler bekommen an Stellen, wo ich static vergessen hatte hinzuzufügen.
Habe dann direkt auch mal alle packed records in records umgeschrieben.

Ich denke nun ist alles klar.

TRomano 13. Okt 2017 10:40

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Also habe ich das richtig verstanden, dass Du einfach nur die Ticks auslesen willst ? Wenn ja, wieso dann so kompliziert ?

Delphi-Quellcode:
function GetTicks : UInt64; register;
asm
  rdtsc
{$IFDEF WIN64} 
  shl rdx, 32
  or rax, rdx
{$ENDIF}
end;
Das sollte für rudimentäre Zwecke reichen. Willst Du ganz exaktes Messen veranstalten, da nimm doch die Routine von Agner Fog (Optimierungs Papst) :wink: :

Delphi-Quellcode:
function GetTicks : UInt64;
asm
{$IFDEF CPUX64}
  .NOFRAME
  // by Agner Fog
  push   rbx                   // ebx is modified by cpuid
  sub    rax, rax              // 0
  cpuid                         // serialize
  rdtsc                         // read time stamp counter into edx:eax
  shl    rdx, 32
  or     rax, rdx              // combine into 64 bit register      
  push   rax
  sub    eax, eax
  cpuid                         // serialize
  pop    rax                   // return value
  pop    rbx
  ret
{$ELSE}
  push   ebx                   // ebx is modified by cpuid
  sub    eax, eax              // 0
  cpuid                         // serialize
  rdtsc                         // read time stamp counter
  push   eax
  push   edx
  sub    eax, eax
  cpuid                         // serialize
  pop    edx
  pop    eax
  pop    ebx
  ret
{$ENDIF}
end;
Um auf das "Tick" genau zu sein, müsstest Du dann zusätzlich die Funktion hintereinander aufrufen und die Differenz bilden. Bei späteren Messungen ist diese Differenz (verursacht von dem Funktionsaufruf) abzuziehen.

Gruß Thomas

Sherlock 13. Okt 2017 11:01

AW: Windows.GetTickCount64 auch unter Windows XP?
 
...und weil Windows immer noch kein Echtzeitbetriebssystem ist, darf man sich langsam wundern, zu welchen Exzessen manche Entwickler bereit sind, nur um (in diesen zeitlichen Auflösungen) vermutlich falsche Zahlen zu bekommen.

Sherlock

Glados 13. Okt 2017 11:41

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Zitat:

...und weil Windows immer noch kein Echtzeitbetriebssystem ist, darf man sich langsam wundern, zu welchen Exzessen manche Entwickler bereit sind, nur um (in diesen zeitlichen Auflösungen) vermutlich falsche Zahlen zu bekommen.
Ist das jetzt Ironie? Verstehe es nicht. Ist der ASM-Code da oben also nicht gut?

Eins ist klar. Die obere der beiden ASM-Funktionen gibt Quark zurück.

GetTickCount64 gibt: 653.954.506
GetTick gibt zurück: 1.349.183.170.576.009

p80286 13. Okt 2017 12:04

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Naja "falsch" würde ich das nicht nennen. Das ist ungefär so, als würdest du eine Stopuhr für das Eierkochen nutzen. Je nachdem was, auf Deinem Rechner läuft, ist die Zeitspanne für ein und die selbe Routine immer unterschiedlich. Da erreichst Du eine Genauigkeit, die keine Aussagekraft besitzt. Unter Windows mußt Du immer mehrere Messungen durchführen um einen Trend zu erkennen. Eine Aussage wie "die Laufzeit ist 25 Timerticks" ist unter Windows schlicht Blödsinn.

Gruß
K-H

Rollo62 13. Okt 2017 12:22

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Ist vielleicht "Off-topic", aber das TStopwatch gäbe es auch noch.
Nehme ich mittlerweile lieber statt der GetTickCounts, ist auch CrossPlatform :stupid:

Rollo

Glados 13. Okt 2017 12:33

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Kann man demnach die oben genannten Routinen statt GetTickCount(64) verwenden oder eher nicht?

himitsu 13. Okt 2017 13:16

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Zitat:

Zitat von p80286 (Beitrag 1383227)
Naja "falsch" würde ich das nicht nennen. Das ist ungefär so, als würdest du eine Stopuhr für das Eierkochen nutzen. Je nachdem was, auf Deinem Rechner läuft, ist die Zeitspanne für ein und die selbe Routine immer unterschiedlich. Da erreichst Du eine Genauigkeit, die keine Aussagekraft besitzt. Unter Windows mußt Du immer mehrere Messungen durchführen um einen Trend zu erkennen. Eine Aussage wie "die Laufzeit ist 25 Timerticks" ist unter Windows schlicht Blödsinn.

Gruß
K-H

"vermutlich" :roll:

Früher (vielleicht auch teilweise noch heute) hatte jeder CPU-Kern seinen eigenen Tickcounter
* Problem: Windowsch schiebt standardmäßig die Programme umher, also wenn du den ersten TickCount nimmst und mit einem zweiten verrechnest (Differenz), dann kann da schnell Mist raus kommen, wenn zwischendurch dein Programm (der Thread) auf einen anderen Kern verschoben wurde.
Daher gingen viele CPU-Hersteller dazu über einen "virtuellen" globalen TickCount zu nehmen, der mit keinem der Kerne übereinstimmt.

Außerdem werden häufig die CPUs/Kerne zur Laufzeit lastabhängig getacktet.

Fazit: dieser der CPU-TickCount stimmt nicht mehr mit den Ticks (ausgeführten Aktionen auf dem Kern) der Kerne überein.


Und bezüglich Echtzeitsystem ... jupp, jede Anwendung/Thread hat einen TimeSlot und wirt zwischendurch immer mal wieder pausiert, während andere Prozesse/Threads auf dem Kern rechnen dürfen.

Zacherl 13. Okt 2017 15:46

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Zu RDTSC:
Zitat:

Zitat von MSDN
We strongly discourage using the RDTSC or RDTSCP processor instruction to directly query the TSC because you won't get reliable results on some versions of Windows, across live migrations of virtual machines, and on hardware systems without invariant or tightly synchronized TSCs. Instead, we encourage you to use QPC to leverage the abstraction, consistency, and portability that it offers.

Möglichst hohe Genauigkeit ist für normale Timer-Zwecke aber ja eh ziemlich irrelevant. So wie ich es verstanden habe, will der TE nur einen performanten Timer, welcher auch bei langen Laufzeiten nicht overflowt. Weitere Kriterien wurden ja nicht genannt. Zum Benchmarken ist unter Windows sicherlich MSDN-Library durchsuchenQueryPerformanceCounter die bessere Lösung. Außerdem sollte man dann die CPU Mask auf einen Kern fixieren und ggfls. noch die Prozess- und Thread-Priorität auf Maximum schrauben.

Daniel 14. Okt 2017 08:58

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Ich habe hier vier Beiträge gelöscht, die in einer völligen Entgleisung endeten.

Fukiszo 15. Jan 2018 21:18

AW: Windows.GetTickCount64 auch unter Windows XP?
 
ich nutz QueryPerformanceCounter immer wenn ich was benche, ich finde es sehr präzise.
Nur als vergleich gegen GetTickCount egal ob x86 oder x64.
Als alternative halt.
Ich hoffe der code ist mit neueren delphi versionen kompatibel.

Delphi-Quellcode:
{QueryPerformanceCounter uses the PC's clock counter just as GetTickCount, but it
reads the current value of the countdown register in the timer chip to gain more
accuracy -- down to 1.193MHz (about 800ns).

However, it takes 5 to 10us to call QueryPerformanceCounter, because it has to
do several port I/O instructions to read this value.

If you are running multiprocessor NT, QueryPerformanceCounter uses the Pentium
cycle counter.

You should not be using the raw value of QueryPerformanceCounter; you should
always divide by QueryPerformanceFrequency to convert to some known time base.
QueryPerformanceCounter doesn't run at the same rate on all machines.

The example below shows how to use it in Delphi 3/4:
}

type
  TInt64 = TLargeInteger;
var
  Frequency, lpPerformanceCount1, lpPerformanceCount2 : TLargeInteger;

begin
  QueryPerformanceCounter(TInt64((@lpPerformanceCount1)^));

  // activity to measure
  my_proc;

  QueryPerformanceCounter(TInt64((@lpPerformanceCount2)^));
  QueryPerformanceFrequency(TInt64((@Frequency)^));

  // this shows the time in ns
  ShowMessage(IntToStr(Round(1000000 * (lpPerformanceCount2.QuadPart -
                       lpPerformanceCount1.QuadPart) / Frequency.QuadPart)));
end;

hoika 15. Jan 2018 23:37

AW: Windows.GetTickCount64 auch unter Windows XP?
 
Hallo,
OK, Info zur Starter-Edition gelöscht.
Kennt ja wohl jeder mittlerweise.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:00 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz