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/)
-   -   TFileTime addieren (https://www.delphipraxis.net/97167-tfiletime-addieren.html)

Luckie 6. Aug 2007 09:15


TFileTime addieren
 
Wie addiere ich zwei TFileTime-Werte?
Delphi-Quellcode:
CPUTime.dwLowDateTime := ProcList.Items[i].KernelTime.dwLowDateTime + ProcList.Items[i].UserTime.dwLowDateTime;
CPUTime.dwHighDateTime := ProcList.Items[i].KernelTime.dwHighDateTime + ProcList.Items[i].UserTime.dwHighDateTime;
Das stimmt irgendwie nicht. Denn wenn ich das in eine Zeit umwandele,
Delphi-Quellcode:
FileTimeToLocalFileTime(CPUTime, lft);
FileTimeToSystemTime(lft, st);
GetTimeFormatW(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, @st, nil, TimeStr, SizeOf(TimeStr));
kommt ein falscher Wert dabei raus.

mirage228 6. Aug 2007 09:22

Re: TFileTime addieren
 
Wozu addierst Du die Werte denn bzw. was soll dabei rauskommen?

mfG
mirage228

Luckie 6. Aug 2007 09:24

Re: TFileTime addieren
 
Die CPU Zeit eines Prozesses setzt sich zusammen aus der zeit, die er im Kernel-Mode und User-Mode war. Deswegen muss ich sie addieren.

mirage228 6. Aug 2007 09:27

Re: TFileTime addieren
 
Hi,

Also in meiner D7 W32-SDK Hilfe steht zu FileTime
Zitat:

It is not recommended that you add and subtract values from the FILETIME structure to obtain relative times. Instead, you should
· Copy the resulting FILETIME structure to a LARGE_INTEGER structure.
· Use normal 64-bit arithmetic on the LARGE_INTEGER value.
Vielleicht hilft Dir das weiter.

mfG
mirage228

Luckie 6. Aug 2007 09:35

Re: TFileTime addieren
 
Hm, und wie kopiere ich das in eine LARGE_INTEGER Struktur? Und wie bekomme ich davon dann wieder die Zeit?

sirius 6. Aug 2007 09:52

Re: TFileTime addieren
 
Wie wärs z.B. damit:
Delphi-Quellcode:
type TLargeTime=record
       case boolean of
         True: (DWlo:cardinal;DWHi:cardinal);
         False: (QW:int64);
end;
//kein Ahnung ob lo oder hi zuerst kommt, aber da wir bei little endian sind....
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var a,b,c:TLargeTime;
begin
  a.DWlo:=5;
  a.DWHi:=0;
  memo1.lines.add('A: '+inttostr(a.qw));

  b.DWlo:=0;
  b.DWHi:=6;
  memo1.lines.add('B: '+inttostr(b.qw));

  c.qw:=a.qw+b.qw;

  memo1.lines.add('C: '+inttostr(c.qw));
end;
Edit: Wichtig ist, dass in ASM bei der Addtion der Hi DWords ein "adc" statt eines "add" genommen wird, um den Übertrag aus der zuvor erfolgten Addition (hier reicht add) der Lo DWords mitzunehmen.

Edit2: Was die Unit Windows nicht so alles bietet :mrgreen:
Delphi-Quellcode:
_LARGE_INTEGER = record
    case Integer of
    0: (
      LowPart: DWORD;
      HighPart: Longint);
    1: (
      QuadPart: LONGLONG);
  end;
PS: Irgendwie beist sich bei der Bezeichnung doch was:
1. DateTime -normalerweise double
2. dw* -steht eher für DWORD
3. Was ist dann DW*DATETIME?

Leonard 6. Aug 2007 09:53

Re: TFileTime addieren
 
Zitat:

Zitat von Luckie
Hm, und wie kopiere ich das in eine LARGE_INTEGER Struktur? Und wie bekomme ich davon dann wieder die Zeit?

Hi,
hier http://www.swissdelphicenter.ch/torr...ode.php?id=969 wird mit LARGER_INTEGER rumgerechnet. Ich denke, da könnte auch das passende für dich dabei sein.

mfg Leonard

Luckie 6. Aug 2007 10:05

Re: TFileTime addieren
 
Danke für den Link:

Delphi-Quellcode:
        CPUTime64.LowPart := ProcList.Items[i].KernelTime.dwLowDateTime + ProcList.Items[i].UserTime.dwLowDateTime;
        CPUTime64.HighPart := ProcList.Items[i].KernelTime.dwHighDateTime + ProcList.Items[i].UserTime.dwHighDateTime;
        CPUTimeft.dwLowDateTime := CPUTime64.LowPart;
        CPUTimeft.dwHighDateTime := CPUTime64.HighPart;
        //CPUTime := (ProcList.Items[i].KernelTime.dwLowDateTime shl 32) + ProcList.Items[i].UserTime.dwHighDateTime;
        FileTimeToSystemTime(lft, st);
        GetTimeFormatW(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, @st, nil, TimeStr, SizeOf(TimeStr));
PS: Man sollte bei der CPU-Zeit auch nicht die Zeitzone berücksichtigen. :mrgreen:

Hawkeye219 6. Aug 2007 10:32

Re: TFileTime addieren
 
Hallo Michael,

du hast Sirius' Ergänzung offenbar überlesen:

Zitat:

Zitat von sirius
Edit: Wichtig ist, dass in ASM bei der Addtion der Hi DWords ein "adc" statt eines "add" genommen wird, um den Übertrag aus der zuvor erfolgten Addition (hier reicht add) der Lo DWords mitzunehmen.

Es reicht nicht, Lo- und Hi-Teil getrennt zu addieren, weil dabei ein eventueller Übertrag unterschlagen wird. Du mußt eigentlich nur so vorgehen wie bei der schriftliche Addition von Dezimalzahlen - oder so, wie sirius es zuvor gezeigt hat.

Das hier

Zitat:

Delphi-Quellcode:
//CPUTime := (ProcList.Items[i].KernelTime.dwLowDateTime shl 32) + ProcList.Items[i].UserTime.dwHighDateTime;

ist zwar auskommentiert, beinhaltet aber einige Fehler, die möglicherweise auch an anderen Stellen in deinem Quelltext vorkommen. Zunächst werden zwei Teile aus unterschiedlichen Strukturen (KernelTime und UserTime) verheiratet, wahrscheinlich ist das nur ein Schreibfehler. Dann wird der niederwertige Anteil verschoben - richtig wäre der höherwertige Anteil. Der letzte Fehler: bei einer Verschiebung um 32 Bits passiert nichts, wenn das Argument nicht zuvor nach Int64 gecastet wird.

Gruß Hawkeye

Luckie 6. Aug 2007 11:06

Re: TFileTime addieren
 
Zitat:

Zitat von Hawkeye219
oder so, wie sirius es zuvor gezeigt hat.

Leder kann ich die QuadParts nicht addieren, da TFileTime dies nicht besitzt, deswegen hatte ich es einzeln addiert.

sirius 6. Aug 2007 11:44

Re: TFileTime addieren
 
Deswegen musst du ja auch die einzelnen Teile den DWORD-Parts zuweisen und addierst dann die QWORD, so wie in meinem Beispiel.

Luckie 6. Aug 2007 11:51

Re: TFileTime addieren
 
Also so:
Delphi-Quellcode:
        KernelTime64.LowPart := ProcList.Items[i].KernelTime.dwLowDateTime;
        KernelTime64.HighPart := ProcList.Items[i].KernelTime.dwHighDateTime;
        UserTime64.LowPart := ProcList.Items[i].KernelTime.dwLowDateTime;
        UserTime64.HighPart := ProcList.Items[i].KernelTime.dwHighDateTime;
        CPUTime64.QuadPart := KernelTime64.QuadPart + UserTime64.QuadPart;
        CPUTimeft.dwLowDateTime := CPUTime64.LowPart;
        CPUTimeft.dwHighDateTime := CPUTime64.HighPart;
        FileTimeToSystemTime(CPUTimeft, st);
        GetTimeFormatW(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, @st, nil, TimeStr, SizeOf(TimeStr));

Hawkeye219 6. Aug 2007 12:03

Re: TFileTime addieren
 
Wenn du den "Copy&Paste"-Fehler noch korrigierst, könnte es was werden:

Delphi-Quellcode:
//UserTime64.LowPart := ProcList.Items[i].KernelTime.dwLowDateTime;
//UserTime64.HighPart := ProcList.Items[i].KernelTime.dwHighDateTime;
UserTime64.LowPart := ProcList.Items[i].UserTime.dwLowDateTime;
UserTime64.HighPart := ProcList.Items[i].UserTime.dwHighDateTime;
Gruß Hawkeye

Luckie 6. Aug 2007 12:07

Re: TFileTime addieren
 
:oops:

Gausi 18. Feb 2008 14:04

Re: TFileTime addieren
 
Ich häng mich hier mal hintendran, weil ich dasselbe Problem habe, und gerade damit nicht weiterkomme. Ich möchte bestimmen, wieviel Zeit eine Berechnung benötigt, und QueryPerformanceCounter scheint nicht auszureichen (da gibts manchmal Ausreißer, die ich mir nur dadurch erklären kann, dass ein anderer Prozess gerade rumgewerkelt hat). Mein Code sieht so aus:

Delphi-Quellcode:
function GetUsageTime: Int64;
var
  fCreationTime, fExitTime: TFileTime;
  fKernelTime, fUserTime: TFileTime;
  UserTime64, KernelTime64: _Large_Integer;
begin
  GetProcessTimes(GetCurrentProcess, fCreationTime, fExitTime, fKernelTime, fUserTime);

  KernelTime64.LowPart := fKernelTime.dwLowDateTime;
  KernelTime64.HighPart := fKernelTime.dwHighDateTime;
  UserTime64.LowPart := fUserTime.dwLowDateTime;
  UserTime64.HighPart := fUserTime.dwHighDateTime;

  result := KernelTime64.QuadPart + UserTime64.QuadPart;
end;


Function GetAlgorithmTime: Int64;
var s,e: Int64;
begin
      s := GetUsageTime;  // Zeit nehmen
      DoAlgorithm;        // Berechnung ausführen
      e := GetUsageTime;  // Zeit nehmen
      result := e-s;      // Differenz ist das Ergbnis
end;
Aber dabei kommen unsinnige Werte bei raus - sehr oft 0, und ab und zu andere Werte, aber dann recht oft derselbe (oder sogar immer). Irgendwas ist also falsch. Oder geh ich die Sache komplett falsch an?

marabu 18. Feb 2008 16:06

Re: TFileTime addieren
 
Hi,

wenn du ab und zu 0 als Ergebnis erhältst, dann könnte das daran liegen, dass sich die Laufzeit von DoAlgorithm nahe der Zeitauflösung (10 ms) bewegt. Um "einigermaßen verlässliche" Ergebnisse zu erzielen, wirst du wohl minimal 2 * 10 ms messen müssen. Ansonsten halte ich das mehrmalige Auftreten desselben Ergebnisses nicht unbedingt für einen Fehler. Bei geeigneten Testfällen wirst du bemerken, dass du durchaus variierende Zeiten erhältst - aus ähnlichen Gründen wie bei der Verwendung von QueryPerformanceCounter.

Delphi-Quellcode:
function GetUsageTime: TFileTime;
var
  ftDummy: TFileTime;
  ftKernelTime, ftUserTime: TFileTime;
begin
  GetProcessTimes(GetCurrentProcess, ftDummy, ftDummy, ftKernelTime, ftUserTime);
  Result := TFileTime(Int64(ftKernelTime) + Int64(ftUserTime));
end;
Wenn dein System gelegentlich eine Zeitsynchronisierung durchführt, dann sind die Ergebnisse natürlich verfälscht.

Freundliche Grüße

Gausi 18. Feb 2008 17:19

Re: TFileTime addieren
 
Ist die Auflösung bei dem Ding nicht 100ns, also Zehntel Mikro-Sekunden? :gruebel:

Wenn ich deinen Code so abändere, also ohne die abschließende Konvertierung nach TFileTime
Delphi-Quellcode:
function GetUsageTime: Int64;
var
  ftDummy: TFileTime;
  ftKernelTime, ftUserTime: TFileTime;
begin
  GetProcessTimes(GetCurrentProcess, ftDummy, ftDummy, ftKernelTime, ftUserTime);
  Result := (Int64(ftKernelTime) + Int64(ftUserTime));
end;
, dann erhalte ich wieder unsinnige Werte. Das heißt in 80-90% Null, und in den anderen Fällen 31200. Und das kann nicht sein.

Ja, die Algorithmen sind recht schnell, mit QueryPerformanceCounter krieg ich raus, dass die je nach Eingabe nur wenige Dutzend µs brauchen - daher schlägt es ja auch durch, wenn Vista während eines Durchlaufs mal kurz guckt, was sonst noch so zu tun ist. Da sind dann halt ab und zu Ausreißer von ein paar hundert µs dabei, und die machen das Bild kaputt - auch wenn man über mehrere Durchläufe mittelt.

marabu 18. Feb 2008 17:38

Re: TFileTime addieren
 
Die Zeiteinheit von FileTime ist 100 ns - die Auflösung von GetProcessTimes() ist 10 ms, wie bei allen Windows Time Funktionen. Nur die High Precision Timer sind genauer.

Gausi 18. Feb 2008 17:47

Re: TFileTime addieren
 
...mit anderen Worten: Das Ding bringt mir gar nichts. Auch gut - dann muss ich die Ausreißer halt rausdiskutieren.

marabu 18. Feb 2008 18:10

Re: TFileTime addieren
 
Vielleicht solltest du noch nach einer Erklärung für den Wert 31200 suchen.

Gausi 19. Feb 2008 09:28

Re: TFileTime addieren
 
Gegenfrage: Sind die 10ms ein verlässlicher konstanter Wert oder nur eine grobe Richtlinie? Gestern abend wurden aus den 31200 mal 78000, heute morgen sind es mal wieder 156001 und sporadisch 312002 (also genau das doppelte). Diese Werte mal 100 sind dann 3.120.000ns bis 15.600.100ns, also 3-15ms - das könnte dann die Timerauflösung sein.
Wenn der Algorithmus in einem Zeitfenster durchläuft, ist die Zeit 0, ansonsten ein Vielfaches des Timerintervalls. Klingt doch vernünftig, oder?

himitsu 19. Feb 2008 09:56

Re: TFileTime addieren
 
10ms - halbwegs verlßlich, aber auch grobe Richtlinie.


wenn die Zeit kurz vor umschalten der Zeit ermittelt wird, dann sind es bis zum umschalten keine 10ms mehr, obwohl dieses angezeigt/errechnet wird.



Code:
10ms      20ms      30ms      40ms
*          *          *          *

         |   |            > 20-10=10ms
  |   |                   > 10-10=0ms

|                     |   > 30-10=20ms
|                    |    > 20-10=10ms


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:35 Uhr.

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