Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Delphi 64 Speicherfragen (https://www.delphipraxis.net/178985-delphi-64-speicherfragen.html)

BigAl 6. Feb 2014 21:31

Delphi 64 Speicherfragen
 
Hallo zusammen,

derzeit entwickle ich ein Programm welches unter anderem Berechnungen mit großen Matrizen durchführen muss. Wenn ich groß sage, dann meine ich richtig groß. Im Endstadium werden die Teile bis ca. 400 GB groß. Derzeit lege ich kleiner Matrizen in den Speicher (TMemoryStream) und größere auf die Platte (TFileStream). Der Plattenzugriff ist natürlich trotz schneller SSDs wesentlich langsamer als der Speicherzugriff. Die Berechnungen mit den Matrizen laufen teilweise mehrere Tage... Mit Cache ist leider nicht, da ein nicht vorhersehbarer Zugriff auf die einzelnen Zellen stattfindet. Auch bringt mir natürlich bei intensiven Zugriffen das Multi-Threading nichts, da alles über einen zentralen Kanal laufen muss... Bei intensiven Berechnungen ist das was anderes...

Nun zu den eigentlichen Fragen:

1. Wie viel Speicher kann ich mit Delphi 64 (XE5) max. verwenden? Leider bin ich unterwegs und habe meiner aktuellen Maschine nur etwa 2,5 GB frei und kann daher nicht testen. Im Internet findet man auch widersprüchliche Aussagen. Schön wäre natürlich, wenn ich den TMemoryStream im Hauptspeicher mit mehreren 100 GB laufen lassen könnte. Zur Not auch auf mehrere Streams aufgeteilt. Aktuelle Windows-Versionen unterstützen ja bereits in den Pro-Varianten bis 512GB Hauptspeicher.

2. Meint ihr es bringt was mehrere Lese-Streams zu öffnen um damit im Multi-Thread-Betrieb zu lesen?

3. Hat jemand eine Idee wie sich die SSDs im Stripe verhalten? Kann man da evtl. pushen?

4. Falls alle Stricke reisen wäre vielleicht das Erstellen der Rechenmodule (diese laufen als externe Anwendungen) mit anderen Software-Werkzeugen eine Lösung?

Schön wäre natürlich eine positive Antwort zu Punkt 1.

Schon mal vielen Danke für eure (hoffentlich positiven) Antworten.

Alex

himitsu 6. Feb 2014 21:55

AW: Delphi 64 Speicherfragen
 
Du hast einen Adressraum von 64^2 (OK, teilweise auch etwas weniger), aber Real hast du maximal RAM + Auslagerungsdatei.

PS: Das hat man auch schon mit 32 Bit.

Es gibt da Adresswerweiterungen, aber praktisch kannst du das auch einfach mit MMFs (Memory Mapped Files) machen, was aber nicht unbedingt Dateien seien müssen,
aber bei 400 GB brauchst du sowieso eine Erweiterung.

MMFs kann man stückchenweise in den Speicher mappen und Windows sorgt da für das Cachen der Datei.


Wenn du einen zusammenhängenden "Stream" hast, dann brauchst du auch bei 64 Bit immenoch einen "zusammenhängenden" Speicherbereich, innerhalb des Virtuellen Speichers der Anwendung.
Vielleicht wäre es also eh besser, wenn du dir überlegst das in kleiner Stücke aufzuteilen.

zeras 6. Feb 2014 21:57

AW: Delphi 64 Speicherfragen
 
Da zapfe doch die NSA Server an. Die haben bestimmt noch ein wenig Kapazität frei, und die Laufzeiten sollten auch um einige schneller sein:lol:

BigAl 6. Feb 2014 22:07

AW: Delphi 64 Speicherfragen
 
Zitat:

Zitat von himitsu (Beitrag 1247015)
Du hast einen Adressraum von 64^2 (OK, teilweise auch etwas weniger), aber Real hast du maximal RAM + Auslagerungsdatei.

PS: Das hat man auch schon mit 32 Bit.

Es gibt da Adresswerweiterungen, aber praktisch kannst du das auch einfach mit MMFs (Memory Mapped Files) machen, was aber nicht unbedingt Dateien seien müssen, aber bei 400 GB brauchst du sowieso eine Erweiterung.

MMFs kann man stückchenweise in den Speicher mappen und Windows sorgt da für das Cachen der Datei.

Wenn du einen zusammenhängenden "Stream" hast, dann brauchst du auch bei 64 Bit immenoch einen "zusammenhängenden" Speicherbereich, innerhalb des Virtuellen Speichers der Anwendung.
Vielleicht wäre es also eh besser, wenn du dir überlegst das in kleiner Stücke aufzuteilen.

Vielen Dank für die schnelle Antwort. bei 64^2 meinst Du wahrscheinlich 2^64. Das mit dem RAM wäre kein Problem. Kommt halt die entsprechende Maschine her. Das Betriebssytem (z. B. Win 8 Pro) kann ja mit den Speichermengen umgehen...

Was genau meinst Du mit Memory Mapped Files? Geht das in Richtung RAM-Disk? Über sowas habe ich schon seit Jahren nicht mehr nachgedacht. Eleganter wäre natürlich der Memory-Stream... Wie gesagt: Es wäre kein Problem da eine Liste mit Streams zu erzeugen und dann halt den entsprechenden Stream zu berechnen den man gerade für den Zugriff benötigt. Hätte auch den Vorteil, dass man mit mehreren Threads gleichzeitig auf verschiedene Streams zugreifen kann... Man macht dann halt 2 GB Blöcke oder so. Bei 200 Stück sind das dan auch 400 GB... Die Frage ist halt nur ob Delphi da irgendwie motzt bzw. ober der Memeory-Manager von Delphi überhaupt in der Lage ist das zu verwalten...

Vielen Dank nochmal

Alex

BUG 6. Feb 2014 22:08

AW: Delphi 64 Speicherfragen
 
Der logische Adressraum eines 64bit Systems ist auch für 400GB groß genug. Die Auslagerungsdatei muss aber nicht so groß sein.
Ich schlage vor, dass du die Streams und die Delphi-Speicherverwaltung vergisst und es mit Memory Mapped Files implementierst.
Wenn man nicht selbst ein ausgefeiltes Caching umsetzten will, ist es am Besten, sich auf die Mechanismen den Betriebssystem zu verlassen ... und MMFs sind für solche Problemen das Mittel der Wahl.

jfheins 6. Feb 2014 22:14

AW: Delphi 64 Speicherfragen
 
Zitat:

Zitat von BigAl (Beitrag 1247018)
Was genau meinst Du mit Memory Mapped Files? Geht das in Richtung RAM-Disk? Über sowas habe ich schon seit Jahren nicht mehr nachgedacht. Eleganter wäre natürlich der Memory-Stream...

Eleganter wäre eigentlich schon die MMF. Dann sind vielleicht nicht mal die vollen 512GB nötig. (Kommt ein bisschen drauf an, wie "unvorhersehbar" die Zugriffe sind)

Zum SSD-Striping: Hilft eigentlich nicht viel weiter. Problem ist doch die Zugriffszeit/Latenz. Die ist bei der SSD knapp 10^6 mal so lang wie beim RAM. DAS ist das Problem ;-)

BigAl 6. Feb 2014 22:31

AW: Delphi 64 Speicherfragen
 
Hallo zusammen,

das mit den MMFs ist die Lösung. Habe gerade mal etwas gegoogelt. Scheint wie gemacht für diese Problem zu sein. Anstelle der Position im Stream rechne ich mir halt den Pointer aus... Brauche dann nur noch Funktionen zum Laden und speichern des MMFs auf Platte.

VIELEN DANK :thumb:

Alex

BigAl 6. Feb 2014 22:34

AW: Delphi 64 Speicherfragen
 
Hi Leute,

weiß jemand wie ich die "offene Frage" schließen kann??

Alex

himitsu 6. Feb 2014 22:54

AW: Delphi 64 Speicherfragen
 
Wenn du das, beim Erstellen, extra als offene Frage markiert hast, dann findest du beim "Antworten" (oder vielleicht auch beim Bearbeiten) wieder den Haken und kannst die Markierung wegmachen. (also meistens bei der "letzten" Antwort, wo man sich für alles bedankt :D)


MMF speichern brauchst du nicht, also wenn die eh schon direkt mit einer Datei verbunden war.

Furtbichler 7. Feb 2014 08:50

AW: Delphi 64 Speicherfragen
 
Zitat:

Zitat von BigAl (Beitrag 1247012)
Mit Cache ist leider nicht, da ein nicht vorhersehbarer Zugriff auf die einzelnen Zellen stattfindet.

Das ist ja gerade der Sinn eines Caches, das selbst zu optimieren.

Ich würde mal einen MRU (Most Recently Used) Cache ausprobieren. Der wächst bis zur maximalen Größe X und schmeisst dann die Elemente raus, die am längsten *nicht* benutzt werden, d.h. Du wirst schon einen Benefit haben, wenn einige Daten mehrfach angefordert werden.

Von der Implementierung her ist es sehr sehr einfach: Man nehme eine Dictionary und eine linked List. Die Dictionary enthält die Listenelemente zum schnellen Suchen
Wenn Du ein Element suchst, dann suchst Du in der Dictionary nach dem Listenelement und bringst das in der LL nach vorne.
Wenn Du das Element nicht findest, lädst Du es und packst es in der LL nach vorne.
Wenn die LL die Maximalgröße überschreitet, räumst Du von hinten her auf.

Wäre denkbar, das das was bringt.

BigAl 19. Feb 2014 20:59

AW: Delphi 64 Speicherfragen (Memory Mapped Files)
 
Hallo zusammen,

ich habe noch eine Frage zu dem Thema Memory Mapped Files. Ich habe mir ein Objekt gebaut, um die verschiedenen Matrizen im MMF zu bearbeiten. Das funktioniert echt super. Ich kann den Speicher von/zu Platte streamen und auf die diversen Elemente zugreifen. Ich möchte nun das Ganzen noch etwas tunen, da ich wie gesagt teilweise sehr viele Zugriffe habe. Speziell beim Lösen von linearen Gleichungssystem mittels Gauss finden extrem viele Zugriffe statt. Da werden aus jeder Nanosekunde gleich mehrere Minuten.

Folgende Zugriffe habe ich erstellt und möchte ich optimieren:

Delphi-Quellcode:
function TMatrixMMF<T>.GetValue(Y, X: Cardinal): T;
// Wert lesen
type
  P = ^T;
begin
  Result := P(UInt64(FMMFPtr) + (Y * FCountX + X) * SizeOf(T))^;
end;

procedure TMatrixMMF<T>.SetValue(Y, X: Cardinal; const Value: T);
// Wert schreiben
type
  P = ^T;
begin
  P(UInt64(FMMFPtr) + (Y * FCountX + X) * SizeOf(T))^ := Value;
end;
FMMPtr ist die Startadresse des MMF-Speichers. FCountX ist die Breite der Matrix.

Ich habe mir das Ganze mal im Assembler angeschaut und etwas potential entdeckt. Leider will Delphi XE5 keinen Inline-Assembler im 64-bit Code??? Meine Idee wäre folgende gewesen:

Nach jeder Teiloperation wird eine Bereichsprüfung auf die Variable durchgeführt. Auf diese würde ich gerne verzichten, da ein Überlauf eigentlich nicht möglich ist. Hat irgendwer vielleicht eine Idee wie man das sonst noch was rauskitzeln könnte? "inline" habe ich schon gemacht, bringt aber nicht viel...

Bin für jeden Tipp dankbar. :-D

So long

Alex

Aviator 19. Feb 2014 21:06

AW: Delphi 64 Speicherfragen
 
Kann man die Bereichsprüfung nicht in den Projektoptionen deaktivieren :?:

BigAl 19. Feb 2014 21:14

AW: Delphi 64 Speicherfragen
 
Zitat:

Zitat von Aviator (Beitrag 1248631)
Kann man die Bereichsprüfung nicht in den Projektoptionen deaktivieren :?:

Die sind natürlich deaktiviert ({$R-}). Das ändert aber nichts daran, dass der vom Compiler erzeugte Assembler-Code nach jeder Operation eine Prüfung durchführt:

Delphi-Quellcode:
glbMatrix.pas.126: P(UInt64(FMMFPtr) + (Y * FCountX + X) * SizeOf(T))^ := Value;
0000000000759DD8 488B4D30         mov rcx,[rbp+$30]
0000000000759DDC 488B5530         mov rdx,[rbp+$30]
0000000000759DE0 8B4538           mov eax,[rbp+$38]
0000000000759DE3 F76208           mul dword ptr [rdx+$08]
0000000000759DE6 7305             jnb {glbMatrix}TMatrixMMF<System.Double>.SetValue + $2D
0000000000759DE8 E87319CBFF      call @IntOver
0000000000759DED 034540           add eax,[rbp+$40]
0000000000759DF0 7305             jnb {glbMatrix}TMatrixMMF<System.Double>.SetValue + $37
0000000000759DF2 E86919CBFF      call @IntOver
0000000000759DF7 8BC0             mov eax,eax
0000000000759DF9 486BC008         imul rax,rax,$08
0000000000759DFD 7105             jno {glbMatrix}TMatrixMMF<System.Double>.SetValue + $44
0000000000759DFF E85C19CBFF      call @IntOver
0000000000759E04 488B4918         mov rcx,[rcx+$18]
0000000000759E08 4803C8           add rcx,rax
0000000000759E0B 7305             jnb {glbMatrix}TMatrixMMF<System.Double>.SetValue + $52
0000000000759E0D E84E19CBFF      call @IntOver
0000000000759E12 488B4548         mov rax,[rbp+$48]
0000000000759E16 488901           mov [rcx],rax
Die Idee wäre halt gewesen die jnbs etc. und calls zu entfernen...

Gruß
Alex

hathor 19. Feb 2014 21:34

AW: Delphi 64 Speicherfragen
 
Wenn man viel RAM und ein 64Bit-BS hat, kann man das Programm-Limit von 2GB höher setzen.
Das geht bei 32Bit- und 64Bit-EXE.

Zitat:
This program demonstrates how to use up to 2.5 GB of RAM on the 32bit versions of Windows XP Prof. and Server 2003 and up to 3.5 GB of RAM on the 64bit versions of Windows XP, Vista, Server 2003 and 2008. This is accomplished by instructing the Delphi linker to set the IMAGE_FILE_LARGE_ADDRESS_AWARE flag set in the EXE header of the 32bit app.
http://cc.embarcadero.com/Item/24309

Dafür braucht man nur eine Directive im .DPR-File:

Delphi-Quellcode:
program Project2;

uses
  Vcl.Forms,
  Unit2 in 'Unit2.pas' {Form2};

const
IMAGE_FILE_LARGE_ADDRESS_AWARE = $0020;
{$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm2, Form2);
  Application.Run;
end.

unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

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

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormCreate(Sender: TObject);
var
   p: Pointer;
   n: Int64;
begin
   p := Pointer($D0000000);
//= 3.489.660.928, Above the 2GB line; and the 3GB line!

   p := VirtualAlloc(p, 1024, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE);
   if p = nil then
      RaiseLastWin32Error;

   n := Cardinal(p);
   Label1.Caption:= IntToHex(n, 16);
end;

end.

BigAl 19. Feb 2014 21:42

AW: Delphi 64 Speicherfragen
 
Danke, aber das reicht leider nicht. Selbst meine Test-Matrizen haben schon 5 bis 6 GB... Im Endausbau sind die Teile schnell mal 100 oder mehr GB groß... Und ausgelagert dürfen die natürlich auch nicht werden, wegen dem Random-Access... Für den Start wird ist ein Rechne mit 64 GB Hauptspeicher geplant, der dann entsprechend den Anforderungen vergrößert wird. Win 8 kann ja bis 512 GB auf einer Maschine...

Gruß
Alex

BUG 19. Feb 2014 21:42

AW: Delphi 64 Speicherfragen
 
Zitat:

Zitat von BigAl (Beitrag 1248633)
Die sind natürlich deaktiviert ({$R-}) ...
Delphi-Quellcode:
//...
0000000000759DE8 E87319CBFF      call @IntOver
//...

Sieht aus, als ob das nicht die Bereichsprüfung, sondern die Integer-Overflow-Prüfung ist :gruebel:

BigAl 19. Feb 2014 21:47

AW: Delphi 64 Speicherfragen
 
Zitat:

Zitat von BUG (Beitrag 1248645)
Zitat:

Zitat von BigAl (Beitrag 1248633)
Die sind natürlich deaktiviert ({$R-}) ...
Delphi-Quellcode:
//...
0000000000759DE8 E87319CBFF      call @IntOver
//...

Sieht aus, als ob das nicht die Bereichsprüfung, sondern die Integer-Overflow-Prüfung ist :gruebel:

Guter Einwand :lol:. Danke, das war's.... Jetzt sieht das Ganze viel kompakter aus:

Delphi-Quellcode:
glbMatrix.pas.128: P(UInt64(FMMFPtr) + (Y * FCountX + X) * SizeOf(T))^ := Value;
0000000000759DA4 488B4510         mov rax,[rbp+$10]
0000000000759DA8 488B4018         mov rax,[rax+$18]
0000000000759DAC 488B4D10         mov rcx,[rbp+$10]
0000000000759DB0 8B5518           mov edx,[rbp+$18]
0000000000759DB3 0FAF5108         imul edx,[rcx+$08]
0000000000759DB7 035520           add edx,[rbp+$20]
0000000000759DBA 8BD2             mov edx,edx
0000000000759DBC 488B4D28         mov rcx,[rbp+$28]
0000000000759DC0 48890CD0         mov [rax+rdx*8],rcx
Hast Du noch so einen guten Tipp?

Vielen, vielen Dank!

Alex

BUG 19. Feb 2014 22:29

AW: Delphi 64 Speicherfragen
 
Zitat:

Zitat von BigAl (Beitrag 1248647)
Hast Du noch so einen guten Tipp?

So einen guten nicht :lol:

Was mir allerdings auffällt, ist dass du den Zeiger auf ein Element an verschiedenen Stellen berechnest.
Im Allgemeinen lagere ich die Adress-/Index-Berechnung in eine inline-Methode aus (DRY), so dass man immer konsistent auf das Feld zugreift.
Fehler an dieser Stelle sind ziemlich tückisch :mrgreen:

BigAl 19. Feb 2014 22:37

AW: Delphi 64 Speicherfragen
 
Zitat:

Zitat von BUG (Beitrag 1248652)
Zitat:

Zitat von BigAl (Beitrag 1248647)
Hast Du noch so einen guten Tipp?

So einen guten nicht :lol:

Was mir allerdings auffällt, ist dass du den Zeiger auf ein Element an verschiedenen Stellen berechnest.
Im Allgemeinen lagere ich die Adress-/Index-Berechnung in eine inline-Methode aus (DRY), so dass man immer konsistent auf das Feld zugreift.
Fehler an dieser Stelle sind ziemlich tückisch :mrgreen:

Hmm. Die Berechnung an sich ist ja recht simpel und ändert sich eigentlich auch nie... Man könnte diese natürlich entsprechend auslagern. Aber sie findet ja nur genau zweimal statt...

Trotzdem Danke!

Alex

jfheins 20. Feb 2014 00:34

AW: Delphi 64 Speicherfragen
 
Ich denke, dass du vor allem auf gute Lokalität achten musst. Bei der Lösung solltest du also eben nicht wild durch die Gegend dereferenzieren, sondern die Matrix in Teile teilen und dann lösen.
Vorteil vom Partitionieren siehe hier die blaue Kurve: http://stackoverflow.com/q/4300663
Was da mathematisch passiert: http://math.stackexchange.com/questi...ices-in-pieces

Falls es geht, solltest du eine aktuelle Intel-CPU hernehmen und die Intel-MKL einsetzen. Die Intel-MKL diskriminiert gegen AMD-CPUs, aber auf einer Intel-CPU macht die so ziemlich alles platt. Das gilt aber natürlich nur, falls die CPU nicht gerade auf die SSD werten muss. Bei dir spielt ja anscheinend nicht nur die Lokalität RAM<>Cache eine Rolle, sondern auch die (viel krassere) Latenz SSD<>RAM.
http://www.kerrywong.com/2009/03/07/...formance-in-c/

Soweit ich weiß, ist die Intel-MKL aber nur in C verfügbar. Vielleicht kannst du dir ja eine DLL mit Subroutinen erzeugen und in Delphi benutzen...


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