Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Seltsame Berechnung mit <sizeOf> (https://www.delphipraxis.net/28171-seltsame-berechnung-mit-sizeof.html)

Dannyboy 20. Aug 2004 12:39


Seltsame Berechnung mit <sizeOf>
 
Hallo Freunde des kleinen Ein-Mal-Eins,
wenn ich mir ansehe, dass laut der Funktion <sizeOf>
8 + 2 zu dem Resultat 16 kommt, dann frage ich mich,
ob ich bisher im Themengebiet der Mathematik etwas
verpasst habe. Ich dachte immer, ich hätte das kleine
Ein-Mal-Eins drauf :mrgreen:
Folgendes Problem:
Delphi-Quellcode:
  var b : byte;
//...
  b:= SizeOf(int64); // b = 8;
  b:= SizeOf(word); // b = 2;
// Bis hier hin is' alles cool, aber ...
  type TLevelSize = record
                      width : int64; // 8 Bytes
                      height : word; // 2 Bytes
                    end;
//...
b:= SizeOf(TLevelSize) // b = 16 // hääääää??
Das möge man mir bitte erklären. :gruebel:

Dani 20. Aug 2004 12:41

Re: Seltsame Berechnung mit <sizeOf>
 
Hi,

probier statt record den packed record

Zitat:

Zitat von Onlinehilfe
Per Voreinstellung sind die Werte in einem strukturierten Typ in einem Word- oder Double-Word-Raster ausgerichtet, um den Zugriff zu beschleunigen. Wenn Sie einen strukturierten Typ deklarieren, können Sie das reservierte Wort packed einfügen, um die Daten in komprimierter Form zu speichern:


NicoDE 20. Aug 2004 12:43

Re: Seltsame Berechnung mit <sizeOf>
 
Delphi-Quellcode:
type
  TLevelSize = record
    Width : Int64; // 8 Bytes
    Height: Word; // 8 Bytes
  end;
Die Ausrichtung findet anhand des größten Members statt. Die Ausrichtung wirkt sich (beim Delphi-Compiler) auch auf das 'Ende' des Records aus.

Dannyboy 20. Aug 2004 13:04

Re: Seltsame Berechnung mit <sizeOf>
 
Hi Dani, hi NicoDe,
seltsamerweise speichert er die 16 Bytes dann auch
in der Datei! Das gefällt mir nicht so.
Wenn ich einen Packed Record verwende, hoffe ich,
dass die Performance nicht darunter leidet. Weil dann wäre
das alles umsonst. Was meint ihr?

NicoDE 20. Aug 2004 13:08

Re: Seltsame Berechnung mit <sizeOf>
 
Zitat:

Zitat von Dannyboy
dass die Performance nicht darunter leidet.

Auf einem x86 wird es nicht auffallen. Auf Alpha/PPC (Windows NT 4.0) wird der Zugriff auf ein array of TFoo langsamer sein. Auf einem AMD64 (Windows x64) gibt es das gleiche Problem wie beim Alpha und PPC.
Das Schreiben der Records ist davon nicht betroffen.

ps: als Anhaltspunkt für Windows x64 (AMD64/EMT64), die Performance könnte im ungünstigen Fall auf ca. die Hälfte sinken.

nailor 20. Aug 2004 13:08

Re: Seltsame Berechnung mit <sizeOf>
 
es wird voraussichtlich langsamer. aber nicht so schrecklich viel.

edit:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TLevelSize = record
    Width : Int64; // 8 Bytes
    Height: Word; // 8 Bytes
  end;

  type
  TLevelSize2 = packed record
    Width : Int64; // 8 Bytes
    Height: Word; // 8 Bytes
  end;

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
const max = 10000;
var i,j: integer;  t: cardinal; a: array[0..max] of tlevelsize; b: array[0..max] of tlevelsize2;
begin
{$O-}
t:= gettickcount;
for i := 0 to max do
begin
for j := 0 to max do begin
a[i].Width := 0;
a[i].Height := 0;
end;                     end;
showmessage(inttostr(gettickcount - t));
t:= gettickcount;
for i := 0 to max do
for j := 0 to max do begin
begin
b[i].Width := 0;
b[i].Height := 0;
end;    end;
showmessage(inttostr(gettickcount - t));
end;

end.
sorry für scheiss formatierung. aber in dem fall sinds ca 30% verlust. wenn man die arrays wegmacht, und immer auf dem gleichen record rumschreibt, dann gehts in der packed version sogar schneller.

Dannyboy 20. Aug 2004 13:15

Re: Seltsame Berechnung mit <sizeOf>
 
Igitt !!! :kotz:
Nö, bei Performanceverlust werde ich auf den Record verzichten und die Daten eher sequentiell ein - und auslesen, ergo erst <width>, dann <height>. So einfach ist das! :evil:

Luckie 20. Aug 2004 13:15

Re: Seltsame Berechnung mit <sizeOf>
 
Zitat:

Zitat von Dannyboy
Hi Dani, hi NicoDe,
seltsamerweise speichert er die 16 Bytes dann auch
in der Datei! Das gefällt mir nicht so.

Äh, wie meinen? Wie speicherst du denn das bitte? Dass der Datensatz 16 byte groß ist? Ist ja auch irgendwie logisch oder?

nailor 20. Aug 2004 13:16

Re: Seltsame Berechnung mit <sizeOf>
 
siehe mein edit oben

Dannyboy 20. Aug 2004 13:26

Re: Seltsame Berechnung mit <sizeOf>
 
Zitat:

Zitat von Luckie
Äh, wie meinen? Wie speicherst du denn das bitte? Dass der Datensatz 16 byte groß ist? Ist ja auch irgendwie logisch oder?

Moin Luckie,
logisch erscheint mir eher, dass int64 (8 Bytes) + word (2 bytes) insgesamt 10 Bytes ergeben.
Delphi-Quellcode:
var lSize : TLevelSize;
//...
Filestream.write(lSize, sizeOf(TLevelSize)); // 16 Bytes
//...
Wie gesagt, ich werde die Daten jetzt einzeln ein - und einzeln auslesen. Spricht was für
einen anderen Vorschlag? :gruebel:

Luckie 20. Aug 2004 13:30

Re: Seltsame Berechnung mit <sizeOf>
 
Zitat:

Zitat von Dannyboy
Moin Luckie,
logisch erscheint mir eher, dass int64 (8 Bytes) + word (2 bytes) insgesamt 10 Bytes ergeben.

Warum das nicht so ist, wurde dir oben erklärt. Und wenn du das gelesen hast, weißt du auch wie du den Record deklarieren musst, damit er dir nur die 10 Byte in die Datei schreibt.

Dannyboy 20. Aug 2004 13:33

Re: Seltsame Berechnung mit <sizeOf>
 
Zitat:

Zitat von Luckie
Warum das nicht so ist, wurde dir oben erklärt. Und wenn du das gelesen hast, weißt du auch wie du den Record deklarieren musst, damit er dir nur die 10 Byte in die Datei schreibt.

... allerdings unter Performanceverlust, den ich, wie oben bereits erwähnt, nicht eingehen möchte. Mir scheint, die sequentielle Lösung (ohne Record) ist am Besten geeignet, oder? :gruebel:

Chewie 20. Aug 2004 13:33

Re: Seltsame Berechnung mit <sizeOf>
 
Jetzt mach dir nicht ins Hemd wg. den angeblichen Performance-Einbußen. Das Ansteuern des richtigen Sektors der Festplatte dauert 100mal länger als der Zugriff auf dein Record.

Luckie 20. Aug 2004 13:35

Re: Seltsame Berechnung mit <sizeOf>
 
Merkst du den unterschied zwischen 1000 und 5000 CPU Taktzyklen? Also ich nicht. :gruebel:

Dannyboy 20. Aug 2004 13:57

Re: Seltsame Berechnung mit <sizeOf>
 
Zitat:

Zitat von Luckie
Merkst du den unterschied zwischen 1000 und 5000 CPU Taktzyklen? Also ich nicht. :gruebel:

Um mich verstehen zu können, muss ich das ganze Projekt, aus dem das Problem hervorgeht, etwas näher beschreiben. Es geht nämlich nicht nur um das einmalige Lesen/Schreiben von 10 (bzw. 16) Bytes.
Listen up:
Es geht um einen Leveleditor, der unendlich (durch den Speicherplatz der Festplatte begrenzt) große Levels haben kann. Daher kommt auch dieser Thread von mir. Ich habe die logische Physik bereits fertig programmiert und getestet, ergo geht es nun um die Performance. Dieser Editor verwendet eine temporäre Auslagerungsdatei, da man nicht eine unendliche Menge an Informationen im RAM speichern kann. Nehmen wir mal an, jemand erstellt sich mit Hilfe des Editors eine Levelmap, die mehrere 100 MB einnimmt (an einem solchen Level würde man sein Leben lang zocken :love: ), dann muss in dieser Datei andauernd gelesen und geschrieben werden. Es werden immer <6000 * Höhe des Levels)> aktuelle Bytes aus der Datei geladen und wenn ich in dieser Datei (und für das Datenarray) generell <packed records> verwende, dann gehe ich davon aus (ich hab's bisher noch nicht testen können), dass ich zu sehr an Performance einbußen muss. Ich möchte noch mal erwähnen, dass eine solche Datei theoretisch riesig sein kann und ich habe dieses Projekt mit einer temporären Auslagerungsdatei realisiert, damit die Levels so riesig sein können. Andernfalls hätte ich das ganze Level auch komplett in ein RAM-fressendes, riesiges Array klatschen können.

Das Problem, das sich ergibt, ist, dass ich auf keinen Fall Performace verlieren möchte, aber die Level-Map-Dateien sollen auf keinen Fall größer werden als nötig.
Bin gern' für Vorschläge bereit. :zwinker:

NicoDE 20. Aug 2004 14:02

Re: Seltsame Berechnung mit <sizeOf>
 
Dann solltest Du eher darüber nachdenken, ob eine Weite von Low(Int64) bis High(Int64) überhaupt Sinn macht...

Dannyboy 20. Aug 2004 14:06

Re: Seltsame Berechnung mit <sizeOf>
 
Zitat:

Zitat von NicoDE
Dann solltest Du eher darüber nachdenken, ob eine Weite von Low(Int64) bis High(Int64) überhaupt Sinn macht...

Du meinst, weil die Levelbreite nicht größer als High(int64) sein kann?
Das sind schon einige GB, oder?
Damit lassen sich immerhin (2^64 DIV 2) Bytes (nur positiver Bereich) darstellen,
das sind 9.223.372.036.854.775.808 Bytes. Das langt mir oder meinst Du
etwas anderes? :gruebel:

NicoDE 20. Aug 2004 14:10

Re: Seltsame Berechnung mit <sizeOf>
 
Zitat:

Zitat von Dannyboy
Du meinst, weil die Levelbreite nicht größer als High(int64) sein kann?

Ich meine, dass negative Weiten keinen Sinn ergeben (spart ein Bit ;)) und, meiner bescheidenen Meinung nach, ein Word ausreichend ist.
(falls notwendig halt mit Multiplikator - sprich, man kann nur Weiten in 1024-er Schritten verwenden, etc pp)

Dannyboy 20. Aug 2004 14:17

Re: Seltsame Berechnung mit <sizeOf>
 
Zitat:

Zitat von NicoDE
Zitat:

Zitat von Dannyboy
Du meinst, weil die Levelbreite nicht größer als High(int64) sein kann?

Ich meine, dass negative Weiten keinen Sinn ergeben (spart ein Bit ;)) und, meiner bescheidenen Meinung nach, ein Word ausreichend ist.
(falls notwendig halt mit Multiplikator - sprich, man kann nur Weiten in 1024-er Schritten verwenden, etc pp)

Der int64-Wert steht ja nur ein einziges Mal in der Datei (im Header) und
die breite des Levels ist immer positiv.
Die Dateilänge auf 65536 (Word) zu begrenzen langt nicht.
Ein Level der Höhe 100 Einheiten hätte somit dann eine maximale Breite von 109 Einheiten.
Das ist viel zu wenig.

NicoDE 20. Aug 2004 14:24

Re: Seltsame Berechnung mit <sizeOf>
 
Zitat:

Zitat von Dannyboy
Der int64-Wert steht ja nur ein einziges Mal in der Datei (im Header)

Dann verstehe ich das Performance-'Problem' nicht, da es nur beim Zugriff auf nicht ausgerichtete Member und/oder nicht ausgerichtete (packed) Arrays auftritt...

negaH 20. Aug 2004 14:29

Re: Seltsame Berechnung mit <sizeOf>
 
Nimm packed record und speichere diesen direkt.
Das hat die Vorteile
1.) weniger RAM Verbrauch deiner riesigen Levels
2.) vieleinfachere Speicher/Laderoutinen.


Performancetechnisch unterscheidet sich das garnicht, denn selbst wenn du ausgerichtete Records benutzen würdest so würde DEIN obiger Record KEINERLEI Performanceeinbussen haben. Das liegt daran das beide Felder an 8 Bytes Grenze ausgerichtet sind, und nur das zweite Feld eben nur 2 Bytes groß ist. Somit ist der Zugriff auf beide Felder immer an 8 Bytes ausgerichtet. Ein ausgerichteter Record würde nur noch zusätzlich 6 Bytes am Ende des Records verwalten der in jedem falle Performance irrelevant ist.
Heutige CPU's haben KEIN problem nur 1,2,4,8 Bytes zu laden, das geht alles gleich schnell/langsam. Sie haben nur das Problem wenn diese Daten NICHT an eienr Speicheradresse stehen die nicht an 4 bzw. 8 Bytes Grenze ausgerichtet wurde. Dann entstehen zusätzliche Taktzyklen innerhalb der CPU, aber im Grunde irrelevant für uns, da das unverhältnismäßig kleiner ist als die vielen anderen Flaschenhälse der Hardware (Festplatten, Threads, Tasksswitsches, Interrupts etc pp.)

Gruß Hagen

Dannyboy 20. Aug 2004 14:30

Re: Seltsame Berechnung mit <sizeOf>
 
Zitat:

Zitat von NicoDE
Dann verstehe ich das Performance-'Problem' nicht, da es nur beim Zugriff auf nicht ausgerichtete Member und/oder nicht ausgerichtete (packed) Arrays auftritt...

Das Level selbst steht auch in der Datei drin. Eine Levelzelle besteht auch aus einem
Record (Byte, Integer, real und Word).

NicoDE 20. Aug 2004 14:34

Re: Seltsame Berechnung mit <sizeOf>
 
Hi Hagen,

Ich meinte oben den speziellen Fall 'Foo[i>0].Bar'. Der Zugriff wäre in seinem Falle nicht an 8-Byte-Grenzen ausgerichtet (sondern 'nur' 4-Byte) ... was aber auf den aktuellen CPUs (was Windows betrifft) kein Problem ist :)

Gruber_Hans_12345 20. Aug 2004 14:37

Re: Seltsame Berechnung mit <sizeOf>
 
Zitat:

Zitat von negaH
Nimm packed record und speichere diesen direkt.
Das hat die Vorteile
1.) weniger RAM Verbrauch deiner riesigen Levels
2.) vieleinfachere Speicher/Laderoutinen.


Performancetechnisch unterscheidet sich das garnicht, denn selbst wenn du ausgerichtete Records benutzen würdest so würde DEIN obiger Record KEINERLEI Performanceeinbussen haben. Das liegt daran das beide Felder an 8 Bytes Grenze ausgerichtet sind, und nur das zweite Feld eben nur 2 Bytes groß ist. Somit ist der Zugriff auf beide Felder immer an 8 Bytes ausgerichtet. Ein ausgerichteter Record würde nur noch zusätzlich 6 Bytes am Ende des Records verwalten der in jedem falle Performance irrelevant ist.
Heutige CPU's haben KEIN problem nur 1,2,4,8 Bytes zu laden, das geht alles gleich schnell/langsam. Sie haben nur das Problem wenn diese Daten NICHT an eienr Speicheradresse stehen die nicht an 4 bzw. 8 Bytes Grenze ausgerichtet wurde. Dann entstehen zusätzliche Taktzyklen innerhalb der CPU, aber im Grunde irrelevant für uns, da das unverhältnismäßig kleiner ist als die vielen anderen Flaschenhälse der Hardware (Festplatten, Threads, Tasksswitsches, Interrupts etc pp.)

Gruß Hagen

Was passiert dann wenn aber 10 solcher Records in einem Array hintereinander stehen ? dann fängt das 2. record nicht an einer "geraden" Adresse an oder ?
Ist es beim kopieren von solchen Array's trotzdem nicht schneller, wenn 2mal 8 Bytes kopiert werden wie wenn einmal 8 und einmal 2 Bytes (oder 5m al 2 Bytes) kopiert werden müssen ?


Abgesehen davon würde ich auch packed records verwenden, da ich auch glaube, das der Performacne Gewinn im Vergleich zum schöneren und übersichtlichern / wartbaren Code einfach zu maginal ist.

Gruss
Hans

w3seek 20. Aug 2004 15:12

Re: Seltsame Berechnung mit <sizeOf>
 
Wie bereits mehrfach gesagt wurde ist der performanceverlust wirklich derart gering dass es normalerweise (vor allem nicht bei den derzeitigen CPUs) bemerkbar ist. Sowas macht sich hoechstens bei extremst rechenintensiven Code bemerkbar wie, hauptsaechlich im kernel bereich wie z.b. der scheduler. Da macht sich so ein performanceverlust schon deutlich bemerkbar. Wenn du allerdings "nur" einen Level-Editor hast macht das nicht sehr viel sinn. Zumal die Beeintraechtigung der Performance doch idr viel staerker durch andere prozesse oder Threads beeintraechtigt wird. Abgesehen davon wenn du so extrem optimieren willst dann wuerde ich auch eine andere Sprache vorziehen, der delphi codeoptimierer koennte auch um einiges besseren code erzeugen...

negaH 20. Aug 2004 16:40

Re: Seltsame Berechnung mit <sizeOf>
 
In einem Array[] of RecordXY würde nun der zweite Eintrag nur noch an 2 Bytes Grenze ausgerichtet sein. Dies ist aber nur halb so wild da das auf heutigen CPUs nur 1 Taktzyklus mehr beim Zugriff bedeutet. Die Piplines und der Cache der CPUs sind auf solche Daten optimiert. Der 1 Taktzyklus entsteht nur noch innerhalb der CPU die die 32Bit Daten in 16Bit runterbrechen muß.

Beim Kopieren ist es wiederum irrelevant das man clevererweise mit Move(Source[0], Dest[0], Count * SizeOf(Source[0])); kopieren wird. In diesem Moment behandelt die CPU die kompletten Daten als ein an 4/8 Bytes Grenzen ausgerichteten Datenblock. Das kopieren wäre sogar effizienter mit packed records da viel weniger unnötige Daten kopiert werden müssen.

Nimm immer packed Records kann ich nur sagen, und konzentiere dich darauf deine Algorithmen zu verbessern falls du mehr Speed brauchst. Der Unterschied zwischen packed und unpacked Records würde erst relevant wenn man den Rest des gesammten Codes schonn in handmade Assembler codiert hat, nur dann würde eine Ausrichtung der Daten zum Verhältnis des zeitlichen Programmieraufwandes stehen.

Wenn du wirklich was optimieren willst dann vermeide den Int64 und erhöhe das Word auf Cardinal.
Beim Int64 produziert der Compiler wesentlich inperformanteren Code der sehr oft in die RTL spingen muß, als für Cardinals, und nur beim Zugriff auf 16 Bit oder 8 Bit Daten wird eine 32Bit CPU ausgebremst, somit mache aus dem Word ein Cardinal und alles ist ok.
Das schlimme mit 8/16Bit Daten ist sogar das dieser Flaschenhals innerhalb der CPU die voherigen und nachfolgenden 32Bit CPU Befehle zusätzlich ausbremst, es entshene sogenannte Stalls.

Gruß Hagen


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:23 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