Wie kann ich einen beliebig großen Speicherbereich in read/write mappen?



  • Hallo,
    ich arbeite an einem Projekt, in dem per Assembler ein sehr langes Array angelegt werden soll. Die Größe ist nie dieselbe (je nach Bedarf einige MB bis einige GB lang. Ich möchte hier Assembler nutzen, um mit möglichst wenigen Speicher- und mehr Registeranweisungen arbeiten zu können). Dafür möchte ich einen Speicherbereich mit Read/Write-Permission freigeben, sodass ich mir keine Sorgen machen muss, dass auf ein bereits genutzter oder undefinierter Speicherbereich zugegriffen wird.

    Außerdem muss die Adresse des neu angelegten Speicherbereichs in eine Variable gespeichert werden. In etwa so:

    unsigned __int64 arrayStart = reinterpret_cast<__int64>(neuerSpeicher);
    

    Nur weiß ich nicht, wie ich überhaupt den Pointer des neu angelegten Speicherbereichts zuweisen lassen kann.

    Wäre klasse, wenn mir jemand helfen kann 🙂
    Danke



  • Und was hat das jetzt mit GUIs zu tun? @Mod: Bitte verschieben (keine Ahnung wohin genau ^^).

    Arbeitest du auf einer speziellen Plattform (z.B. Embedded Device) mit irgendwelchen Einschraenkungen? Ansonstent ergibt deine Begruendung warum du Assembler verwenden moechtest ueberhaupt keinen Sinn.

    Erklaer doch mal etwas genauer was du machen moechtest und auf welcher Plattform du arbeitest. Vielleicht verstehen wir dann besser was du machen moechtest.



  • Ich arbeite mit Qt. Habe noch nicht so ganz herausgefunden, wie ich mit Qt Assembler compilieren/assemblieren kann...

    Das Programm soll in RAM-Dumps nach Pointer suchen. Um den Prozess zu beschleunigen soll vor der ersten Suche erst mal alle potenziellen Pointer (die auf 0, 4, 8 oder 0xC enden) in ein Array gespeichert werden. Und solche Dumps können je nach Programm und Gerät/Spielekonsole einige GB groß sein.
    Eine Schleife soll daher in 4-Byte-Schritten jeden 4-Byte-Wert (8-Byte-Wert, wenn es ein Dump eines 64-Bit-Systems ist) überprüfen (ob Wert & 3 == 0) und dann in das Array ablegen. Schleifen, die sich so oft wiederholen schreibe ich lieber in Assembler, weil ein Compiler Code mit zu vielen Speicher- statt Registerzugriffen erzeugt.
    Die Größe des Arrays hängt also vom RAM-Dump ab.
    Die Funktion der eigentliche Suche nach den Pointer soll daher auch in Assembler geschrieben werden.



  • Was ist jetzt die Frage? (Was hat Assembler mit Qt zu tun?)

    Was generiert der Compiler denn genau? Vielleicht kann dir hier jemand helfen die C++-Variante zu optimieren.



  • Die C++ Frage ist, wie ich einen Speicherbereich von N Bytes mappen kann, sodass ich diesen sorgenlos nutzen kann.
    Der Assembler Code soll dort dann die Arrays generieren.

    Hier ein Beispiel, was ich an dem vom Compiler generierten Code sehr kontraproduktiv finde:

    unsigned __int64 i = 0;
    00007FF76574229B  mov         qword ptr ,0  
    	unsigned __int64 c = 0x200000000;
    00007FF7657422A3  mov         rax,200000000h  
    00007FF7657422AD  mov         qword ptr [c],rax  
    	while (i < c)
    00007FF7657422B1  mov         rax,qword ptr [c]  
    00007FF7657422B5  cmp         qword ptr [i],rax  
    00007FF7657422B9  jae         main+68h (07FF7657422C8h)  
    	{
    		i++;
    00007FF7657422BB  mov         rax,qword ptr [i]  
    00007FF7657422BF  inc         rax  
    00007FF7657422C2  mov         qword ptr [i],rax  
    	}
    

    In Assembler kann ich alle Variablen in Register packen. Der Zugriff auf Register ist sehr viel schneller:

    .data
    .code
    assembly proc
    
    mov rax, 0
    mov rbx, 0200000000h
    asdf:
    cmp rax, rbx
    inc rax
    jbe asdf
    
    ret
    xor rax, rax
    assembly endp
    
    end
    

    Die Schlife in Assembler kommt in einen Fünftel der Zeit zum Ende.
    Das Nutzen des [i]register* Befehls hat nichts gebracht.
    Um die sehr langen Arrays schnell abarbeiten zu können, möchte ich also die Adresse des Dump-Beginns im Speicher in r8 packen, die Addresse des neu verfügbaren Speichers, den Wert 3, um zu überprüfen, ob es sich um einen Potentiellen Pointer handelt und je nach dem, was sonst noch gebraucht wird. Die einzigsten Speicherzugriffen wären nur noch die, wenn auf dem Dump und in das Array zugegriffen wird.
    Daher fang ich erst gar nicht an diese so häufig repetierenden Schleifen in einer höheren Sprache zu schreiben.

    Es gibt bereits ein paar solcher Programme, die aber entweder in Java oder C# geschrieben wurden. Die Suche nach Pointern, die wieder auf Pointer verweisen dauert einfach zu lange.



  • Wie hast du getestet?
    Mit welchen Compiler und mit welchen Einstellungen?
    Mit aktiven Optimierungen oder ohne?



  • firefly schrieb:

    Wie hast du getestet?

    Da ich noch nicht so ganz herausgefunden habe, wie ich in Qt Assembler direkt compilieren oder eine .o Datei mit einbeziehen kann, habe ich das in Visual Studio getestet.
    Man kann einach Breakpoints setzen und wenn das Programm angehalten wurde mittels Rechtsklick auf die Zeile den Assembler-Code untersuchen.
    Mit der Funktion time() habe ich verglichen wie viel schneller bzw langsamer die Funktionen ausgeführt werden:

    extern "C" __int64 _stdcall assembly(__int64 x);
    
    int main()
    {
    	unsigned int timeStart = time(0);
    	cout << "Performing C++ loop\n";
    	register unsigned __int64 i = 0;
    	register unsigned __int64 c = 0x200000000;
    	while (i < c)
    	{
    		i++;
    	}
    	cout << "C++ loop took " << time(0) - timeStart << " seconds\n\n\n\n";
    
    	timeStart = time(0);
    	cout << "Performing ASM loop\n";
    	assembly();  // dieselbe Schleife, nur in Assembler
    	cout << "Assembly loop took " << time(0) - timeStart << " seconds\n";
    
    	system("pause");
        return 0;
    }
    

    Die C++ Schleife brauchte 19 Sekunden, die Assembler-Schleife nur 4.
    Klar wurde, wenn ich mit einem Array arbeite auch Speicherzugriffe von Nöten sein, aber ich kann den Rest der Variablen (Offset, Adresse des Arrays, Adresse des RAM-Dumps, usw) in den Registern behalten.

    firefly schrieb:

    Mit welchen Compiler und mit welchen Einstellungen?

    Habe lediglich die Einstellung auf x64 geändert.

    firefly schrieb:

    Mit aktiven Optimierungen oder ohne?

    Optimieriung: Maximum Speed (/O2),
    Favor Maximum Speed or Size: Inheriet/vererbt (ich weiß nicht, wie genau die deutsche Übersetzung ist, jedenfalls, wenn es nicht vererbt ist, sagt es, dass die beiden Einstellungen zueinander inkompatibel sind)
    Performance hat sich aber nicht geändert.

    Aber unabhängig davon, ob ich nun Assembler nutze oder nicht, brauche ich den frei verfügbaren Speicherbereich. Deswegen dieser Thread..



  • Das wurde bestimmt nicht mit Optimierungen kompiliert. Ein optimierender Compiler (habs mit GCC getestet) kann die ganze Schleife in den Zeilen 9-12 wegoptimieren (ich nehme an der Microsoft C++ Compiler ist aehnlich gut wie GCC). Auf jeden Fall dauert die Ausfuehrung unter Windows nicht 19 Sekunden (habs getestet). Kann es sein, dass der Debugger den nicht optimieren Assembly Code zeigt?

    In deinem Fall irgendwas mit Assembler optimieren zu wollen ist einfach nur sinnlos (ausser du willst wirkliche Optimierungen vornehmen, wie z.B. Cache Prefechting etc.).

    Google mal nach Memory Mapped Files, das koennte dir helfen. Oder nimm einfach malloc , das ist wohl am einfachsten.

    *Edit
    Auch Visual Studio optimiert die gesamte Schleife weg (habs gerade getestet). Ist ja auch relativ offensichtlich wenn man ein wenig Erfahrung mit Compiler-Optimierungen besitzt.



  • Mit malloc funktionierts. danke



  • KratzKatz schrieb:

    Mit malloc funktionierts. danke

    Schreibst du den Code immer noch in Assembly?



  • nur die eigentliche Suche nach den Pointer



  • Wäre es nicht einfacher die Compiler-Optimierungen zu aktivieren?



  • TyRoXx schrieb:

    Wäre es nicht einfacher die Compiler-Optimierungen zu aktivieren?

    Einfacher ja. Aber ob schneller...
    Die Suche nach "einfachen" Pointer funktioniert bereits und dauert bei einem Dump von 1GB größe nicht mal eine Sekunde. Schneller als bei allen anderen Tools dieser Art, die ich kenne



  • KratzKatz schrieb:

    TyRoXx schrieb:

    Wäre es nicht einfacher die Compiler-Optimierungen zu aktivieren?

    Einfacher ja. Aber ob schneller...
    Die Suche nach "einfachen" Pointer funktioniert bereits und dauert bei einem Dump von 1GB größe nicht mal eine Sekunde. Schneller als bei allen anderen Tools dieser Art, die ich kenne

    Zeig mal deinen Assembly Code.


  • Mod

    KratzKatz schrieb:

    TyRoXx schrieb:

    Wäre es nicht einfacher die Compiler-Optimierungen zu aktivieren?

    Einfacher ja. Aber ob schneller...

    Aber ausprobiert hast du es nicht, oder? Gerade bei solchen Dingen optimieren Compiler eigentlich wesentlich besser als jeder Mensch. Handgeschriebener Assemblycode ist erfahrungsgemäß gut für die Ausnutzung ganz besonderer Prozessorfeatures, aber nicht für 0815-Code.


Log in to reply