![]() |
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:
Das möge man mir bitte erklären. :gruebel:
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ääääää?? |
Re: Seltsame Berechnung mit <sizeOf>
Hi,
probier statt record den packed record Zitat:
|
Re: Seltsame Berechnung mit <sizeOf>
Delphi-Quellcode:
Die Ausrichtung findet anhand des größten Members statt. Die Ausrichtung wirkt sich (beim Delphi-Compiler) auch auf das 'Ende' des Records aus.
type
TLevelSize = record Width : Int64; // 8 Bytes Height: Word; // 8 Bytes end; |
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? |
Re: Seltsame Berechnung mit <sizeOf>
Zitat:
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. |
Re: Seltsame Berechnung mit <sizeOf>
es wird voraussichtlich langsamer. aber nicht so schrecklich viel.
edit:
Delphi-Quellcode:
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.
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. |
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: |
Re: Seltsame Berechnung mit <sizeOf>
Zitat:
|
Re: Seltsame Berechnung mit <sizeOf>
siehe mein edit oben
|
Re: Seltsame Berechnung mit <sizeOf>
Zitat:
logisch erscheint mir eher, dass int64 (8 Bytes) + word (2 bytes) insgesamt 10 Bytes ergeben.
Delphi-Quellcode:
Wie gesagt, ich werde die Daten jetzt einzeln ein - und einzeln auslesen. Spricht was für
var lSize : TLevelSize;
//... Filestream.write(lSize, sizeOf(TLevelSize)); // 16 Bytes //... einen anderen Vorschlag? :gruebel: |
Re: Seltsame Berechnung mit <sizeOf>
Zitat:
|
Re: Seltsame Berechnung mit <sizeOf>
Zitat:
|
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.
|
Re: Seltsame Berechnung mit <sizeOf>
Merkst du den unterschied zwischen 1000 und 5000 CPU Taktzyklen? Also ich nicht. :gruebel:
|
Re: Seltsame Berechnung mit <sizeOf>
Zitat:
Listen up: Es geht um einen Leveleditor, der unendlich (durch den Speicherplatz der Festplatte begrenzt) große Levels haben kann. Daher kommt auch ![]() 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: |
Re: Seltsame Berechnung mit <sizeOf>
Dann solltest Du eher darüber nachdenken, ob eine Weite von Low(Int64) bis High(Int64) überhaupt Sinn macht...
|
Re: Seltsame Berechnung mit <sizeOf>
Zitat:
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: |
Re: Seltsame Berechnung mit <sizeOf>
Zitat:
(falls notwendig halt mit Multiplikator - sprich, man kann nur Weiten in 1024-er Schritten verwenden, etc pp) |
Re: Seltsame Berechnung mit <sizeOf>
Zitat:
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. |
Re: Seltsame Berechnung mit <sizeOf>
Zitat:
|
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 |
Re: Seltsame Berechnung mit <sizeOf>
Zitat:
Record (Byte, Integer, real und Word). |
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 :) |
Re: Seltsame Berechnung mit <sizeOf>
Zitat:
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 |
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...
|
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