monotonic_buffer_resource sorgt für DMA Interrupt Error



  • Hallo Leutz, war lange nicht mehr im Forum aktiv, aber es gab bisher auch nichts zu beanstanden.
    Zuerst mal wünsche ich allen ein gesunden neues Jahr.🙂

    Mein Jahres wechsel war ja so Semi gut, ich habe an meinem Hobby Playstation 2 Spiel weiter gemacht
    und da hat mich den ganzen Dezember über eine Race condition + Heisenbug geärgert😡 🤬 .
    Was für ein Ultra Nerv das war.

    Jetzt geht der Spaß weiter, aber anders. Jetzt stürzt das Programm ab wenn ich mit
    std::pmr::monotonic_buffer_resource eine Memory-Pool baue.
    Ich haben mir eine Pool Helper klasse gebastelt:

    #ifndef POOL_HELPER_H
    #define POOL_HELPER_H
    
    #include <memory>
    #include <memory_resource>
    #include <utility>
    
    // Bekannter Deleter
    struct PMRDeleter
    {
        template <typename T>
        void operator()(T* ptr) const
        {
            if (ptr) ptr->~T();
        }
    };
    
    template <typename T>
    using pool_ptr = std::unique_ptr<T, PMRDeleter>;
    
    // Die statische Speicher-Klasse
    class MemoryManager
    {
    private:
        static constexpr std::size_t GAME_OBJ_SIZE = 512 * 1024;//512 kb
        static constexpr std::size_t MAP_SIZE = 512 * 1024;//128kB
        static inline char buffer[MAP_SIZE];
        static inline std::pmr::monotonic_buffer_resource upstream{
            buffer, MAP_SIZE, std::pmr::null_memory_resource()
        };
    
    
    public:
        // Definition der Puffergrößen
        //static constexpr std::size_t RENDER_OBJECT_SIZE = 2 * 1024 * 1024;//2Mb
        /*
            static std::pmr::monotonic_buffer_resource& getrenderObjectPool() {
                alignas(64) static char buffer[RENDER_OBJECT_SIZE];
                static std::pmr::monotonic_buffer_resource res(buffer, RENDER_OBJECT_SIZE, std::pmr::null_memory_resource());
                return res;
            }
        */
        // Zugriff auf die Ressourcen
        static std::pmr::monotonic_buffer_resource& getGameObjectPool()
        {
            static char buffer[GAME_OBJ_SIZE];
            static std::pmr::monotonic_buffer_resource res(buffer, GAME_OBJ_SIZE, std::pmr::null_memory_resource());
            return res;
        }
    
        static std::pmr::unsynchronized_pool_resource& getMapPool()
        {
            static std::pmr::unsynchronized_pool_resource pool(&upstream);
            return pool;
        }
    
    
        // Die Factory-Funktion direkt in der Klasse
        template<typename T, typename... Args>
        static pool_ptr<T> createObject(std::pmr::monotonic_buffer_resource& currentPool, Args&&... args)
        {
            void* mem = currentPool.allocate(sizeof(T), alignof(T));
            T* obj = ::new (mem) T(std::forward<Args>(args)...);
            return pool_ptr<T>(obj);
        }
    
        // Optional: Den kompletten Speicher zurücksetzen (z.B. game over)
        static void resetAll()
        {
            getGameObjectPool().release();
            //getrenderObjectPool().release();
        }
    
        static uint32_t getPoolSize(){
            return GAME_OBJ_SIZE+MAP_SIZE;
        }
    };
    
    #endif
    
    

    Soweit so gut. Nur diese Strukturen werden im Pool abgelegt:

    struct alignas(16) effect_t
    {
        texrect_t rect;
        VECTOR border;
        uint16_t tex_x;
        uint16_t tex_y;
        bool show = false;
        bool brokenEffect = false;
        bool srcBufferIndex = 0;
    };
    
    struct alignas(16) renderObject_t
    {
        VECTOR texelPosition;   // 16
        VECTOR objectPosition;  // 16
        VECTOR border;          // 16
    
        float zIndex;           // 4
        float spriteWidth;      // 4
        float spriteHeight;     // 4
    
        uint16_t gID;           // 2
        uint8_t flip = 0;                // 1
        uint8_t srcBufferIndex = 0;      // 1
        bool show = true;              // 1
    
        struct alignas(16)
        {
            VECTOR pos;         // 16
            bool show = true;          // 1
            // Padding
        } shadow;
    };
    

    Jetzt gibt es eine Besonderheit. Nicht die Strukturen werden via DMA transportiert, sonder nur der VECTOR.
    Das funktioniert via Chain DMA Transfer.

    Ich bastel mir also eine src DMA Kette an Adressen zusammen von dem VECTOR, der in dem struct ist und letzten Endes im std::pmr::monotonic_buffer_resource.

    Jetzt das Kuriose, der erste Kampf läuft noch, dann wird der Game over screen angezeigt und man kehrt ins Menü zurück, dabei wird der monotonic_buffer_resource zurück gesetzt.
    Der zweite Kampf beginnt und erst nach einer Zeit x stützt die Play'si ab.
    Der Absturzbericht ist immer gleich:

     # DMAC: Bus error interrupt.
    
    *** Unexpected reply - type=BREAKR result=PROGEND
    
    dsedb S> dr
     at=00000002  v0-1=00000000,00000000  a0-3=00000001,00000000,80030000,80012618
     t0-7=8002ac54,b000e020,b000c800,00800000, 10000001,000068a5,30007fff,00011730
     s0-7=10000000,8001d604,009f5dd0,00000000, 0000000f,00000000,00000000,00000000
     t8=00000000 t9=00000000   k0=80016ed8 k1=00000000   gp=0042e870 sp=8001d3f0
     fp=009cad30 ra=80001db0   lo=00000024 hi=00000000   sa=00000000 PC=80000dc0
     badvaddr=40000f87 badpaddr=42084200
     $cause   = 0x50008424 [ BD2 CE1 EXC2=Reset IP7 IP2 EXC="Breakpoint" ]
     $status  = 0x70030c02 [ Cu210 EDI EIE IM3 IM2 KSU=Kernel EXL ]
      0x80000db8: 0x00000000  nop
      0x80000dbc: 0x00000000  nop
    ->0x80000dc0: 0x03ffffcd  break   0xfffff
      0x80000dc4: 0x00000000  nop
      0x80000dc8: 0x00000000  nop
      0x80000dcc: 0x00000000  nop
      0x80000dd0: 0x00000000  nop
    dsedb S>  
    

    die Return Adresse zeigt ins nirgendwo und ist deshalb total unnütz
    Nun ist ja Aligment immer so ein Thema bei DMA Transferen.
    Ich haben mir drauf hin einen eigenen arena allocator gebastelt und extra auf die Ausrichtung geachtet
    Mit der erkenntis. Der Absturz passiert da genau so.

    Zum Schluss habe ich auch noch alles auf Roh Zeiger umgebaut, hat auch nichts bewirkt.

    Flush Cache habe ich nach dem Zurücksetzen des Speichers probiert, das ist es auch nicht gewesen.

    Es muss also speziell damit zu tun haben, das man die DMA Src Adressen einsperrt.

    Ein ähnliches Problem besteht auch bei der Verwendung von einer unordered_map mit einer monotonic_buffer_resource
    wenn ich die Map lösche "clear()" und dann den Puffer zurück setze, knallt es direkt mit einem TLB Miss, sobald ich wider auf die Map zugreife.
    daher habe ich auf std::pmr::unsynchronized_pool_resource für unordered_map gesetzt und die Render Objecte landen im normalen heap mit std::unique_ptr.

    Ich habe heute Morgen 4 Stunden gezockt und es lief.
    Trotzdem die Heap Fragmentierung ist ein Problem und lässt mir keine ruhe.

    Das ist zwar ein sehr Spezielles Thema, eventuell weiß trotzdem jemand was das Problem sein könnte.

    VG. Dr. D.



  • @D_Key

    Nicht die Strukturen werden via DMA transportiert, sonder nur der VECTOR.

    Wie synchronisiert du den Zugriff? Nicht dass du auf den VECTOR zugreifst, während der DMA schreibt.


    BTW: MIr ist mal selbst ein unsigned int i; i++ um die Ohren geflogen.



  • @Quiche-Lorraine sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Wie synchronisiert du den Zugriff? Nicht dass du auf den VECTOR zugreifst, während der DMA schreibt.

    Das macht die Packet2 Bibliothek bzw die DMA Bibliothek, wenn man die entsprechende flag gesetzt hat.
    es gibt einmal FlushCache:
    https://github.com/ps2dev/ps2sdk/blob/master/ee/dma/src/dma.c#L164
    und
    https://github.com/ps2dev/ps2sdk/blob/master/ee/dma/src/dma.c#L193
    kurz vor dem Transfer.

    mit packet2_utils_vu_add_unpack_data schribe ich den VECTOR in das DMA Paket
    https://github.com/ps2dev/ps2sdk/blob/master/ee/packet2/include/packet2_utils.h#L67

    Ich habe nur noch nicht begriffen was der Parameter bei FlushCache zu sagen hat und was der unterschied zwischen
    iSyncDCache und SyncDCache ist.

    Ich habe mal geschaut was $cause = 0x50008424 und $status ist,
    Das sind zwei Register im Kernel die den Absturz status speichern,
    aber irwie ist das nichts aussagend.

    Ich habe heute mit nm mal geschaut, was da Speichertechnisch passiert.
    Also static inline char buffer[MAP_SIZE]; funktioniert überhaupt nicht, totz std 17. Die ganze Klasse verbraucht 5MB.
    Ich hatte das als header Only Datei, aus faulheit.
    habe jetzt ein cpp Datei dazu gebastelt jetzt passt das.

    Ob das jetzt das Problem war weiß ich noch nicht.

    Für Heute ist Dienstschluss.

    @Quiche-Lorraine sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    BTW: MIr ist mal selbst ein unsigned int i; i++ um die Ohren geflogen.

    Ja, da hätte ich ein volatile davor gesetzt, nicht das dir da der Optimizer quer kommt🤓



  • @D_Key sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Ich hatte das als header Only Datei, aus faulheit.
    habe jetzt ein cpp Datei dazu gebastelt jetzt passt das.
    Ob das jetzt das Problem war weiß ich noch nicht.

    Ein glasklares Nein. Embedded Entwicklung ist durch die Hardware-Nähe tückisch. Und ich habe schon selbst Spaß mit einem Watchdog gehabt.

    Das ist eigentlich so eine Phase wo ein genaues Studium der Doku rätsam wäre.

    Ja, da hätte ich ein volatile davor gesetzt, nicht das dir da der Optimizer quer kommt🤓

    Nö, es war eine 8-Bit CPU welche eine 32 Bit Variable mittels Interrupt inkrementieren wollte. Also musste ich die Inkrementierung atomar machen.



  • Mein Tipp. Mache mal einen Belastungstest. Jage mal ordentlich Daten über den DMA und schaue ob die Daten stimmen.



  • @D_Key sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Playstation 2

    Ich bin da sowas von nicht drin und kann nichts wertvolles beitragen, aber dennoch: Playstation 2? Alle Achtung! Nach dem, was ich gehört habe, gibt es wohl nur wenige Computersysteme, die dermaßen kompliziert korrekt und nicht zuletzt effizient zu programmieren sind. Viel Erfolg bei der Fehlersuche!

    Mir reicht gerade völlig mein eigenes Hobbyprojekt einer x86 DOS Runtime und GCC-basierter Toolchain für die Retroprogrammierung - aber das ist vermutlich ein Kindergeburtstag gegen die PS2 😉



  • @Quiche-Lorraine sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Mein Tipp. Mache mal einen Belastungstest. Jage mal ordentlich Daten über den DMA und schaue ob die Daten stimmen.

    Der Tipp ist gut, aber ich bombardiere den Grafikchip schon derartig, dass mir schon der VIF FIFO voll läuft.
    Und das ist das Problem. Durch die monotonic buffer resource schränke ich den restlichen Heap weiter ein.
    Beim ersten Match ist noch alles Schick, nachdem das erste Match vorbei ist, geht es wider in das Menü zurück.
    Da werden wider die Sprites und Texturen für das Menü geladen, schön mit new uint16_t usw.
    Zu beginn des zweiten Kampfes werden die Menü Texturen wider gelöscht.
    Dadurch, das der VIF FIFO voll ist, klaut er mir RAM und ich bin schon am RAM Limit angekommen mit 28Mb von 32.
    2Mb gehen schon durch kernel und IOP RAM Hops, und der VU Micro code liegt auch im RAM.

    Irwas Fragmentiert also noch immer meinen HEAP, sodass der VIF Fifo irgendwann außerhalb des Speichers liegt.
    Wenn ich den unique_ptr nutze findet die CPU wahrscheinlich genug Lücken wo sie die Strukturen hin Pakt, ohne das es knallt.

    Einige Sachen habe ich schon gefundene,d ie HEAP Fresser sind, unordered_map und vor allem
    unordered_map<int, std::vector> sind absolute heap Killer.
    std::vector ist auch schon problematisch, std::function, cout, alles heap Killer.

    Von Modernen c++ kann man nur die Smartpointer und std::array verwenden, der Rest ist problematisch.

    @Finnegan sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Ich bin da sowas von nicht drin und kann nichts wertvolles beitragen, aber dennoch: Playstation 2? Alle Achtung! Nach dem, was ich gehört habe, gibt es wohl nur wenige Computersysteme, die dermaßen kompliziert korrekt und nicht zuletzt effizient zu programmieren sind. Viel Erfolg bei der Fehlersuche!

    Es geht eigentlich, dank sdk auf github und google und KI kommt an recht schnell rein. Datenblätter gibt es auch irwo auf github. Und das Original Sony sdk findet man auch wenn man will. Mit einem Haufen Beispiel-Code.

    Am Anfang war ich auch recht überfordert, vor allem die Grafikkonfiguration war der Hass.

    Wenn du ein PC Spiel auf die PS2 Portierst, muss du dich gedanklich davon lösen, dass es Auflösungen wie 800x600 oder 1024x768 nicht gibt auf der PS2, es seiden man konfiguriert PS2 auf VGA output, was Grütze ist, weil die keinen V_Sync ausgibt nur sync on green. Und ein VGA Adpter für die PS2 sind ohnehin Goldstaub.
    Beim Röhren TV muss alles ein ganzes teilbares von 64 sein.

    Zum debuggen ist PCSX2 recht gut. Aber bei manchen Problemen schließt sich das Programm einfach oder es bootet ins BIOS. Das booten ins bios ist noch ok, weil man kann noch ein Register dump ausgeben. Wenn aber PCSX2 abstützt tapst man im Dunkeln. Aber PCSX2 speichert einen stack trace, das ist ultra nützlich
    Wo PCSX2 gar nichts nützt ist das Timing bei DMA oder beim PSCRT Register Einstellungen, die werden komplett ignoriert.

    Dann muss man sich mit FreeMcBoot und PS2-client und einer Retail Konsole helfen.
    Oder man hat das Glück (so wie ich) und hat ein PS2 DEV Tool (DTL-T10000H) zu hause.
    Das DEV Tool hat aber einen Nachteil, es speichert keinen Stack Trace, da ist einfach die Hard- und Software(dsedb) zu alt.
    Es ist nicht schwer Playstation 2 zu programmieren aber definitiv anspruchsvoll.



  • @D_Key Dagegen ist Debugging bei meinem DOS-Projekt ja richtig luxuriös: Ich kann u.a. in QEMU mit FreeDOS testen. QEMU hat einen integrierten GDB Server (aktivierbar mit `-gdb'). Ich baue dann die DOS .EXE in zwei Schritten: Einmal eine ELF-Datei, mit einem über Linker Script integrierten MZ-header (DOS Executables) und vollen DWARF Debug-Informationen. Aus der erzeuge ich dann eine "rohe Binärkopie", das ist dann die DOS-Executable (MZ-Format). Die ELF-Datei verwende ich dann im GDB Debugger als "executable" und lasse den Debugger mit QEMU verbinden, während die .EXE ausgeführt wird. Das erlaubt dann volles Debugging in der IDE (Durchsteppen, Werte/Speicher inspizieren, Breakpoints setzen, etc.). Purer Luxus 😉

    Ich frage mich da gerade, ob es auch für die PS2 einen Emulator mit integriertem GDB-Server gibt. Dann wäre evtl. etwas ähnliches möglich. Eine schnelle Suche hat sowas hier zutage gefördert: Fork of PCSX2 that includes a GDB server. Keine Ahnung wie gut das funktioniert, aber vielleicht lohnt es sich ja, damit mal etwas zu experimentieren.

    Wenn das PS2-Board irgendwo ein serielles Interface hat, könnte man so eventuell sogar auf echter Hardware remote-debuggen. Evtl. auch über einen USB-port. Aber das könnte sehr aufwändig sein, sowas ans laufen zu bekommen. Es gibt da diese gdbstub.c die man im Prinzip mit einkompiliert und darin dann die Kommunikation mit der Außenwelt selbst implementiert (UART oder sowas). Das GDB-Protokoll ist in dem Stub schon fertig, es braucht nur den Code um die serielle Kommunikation durchzuführen. Aber wie gesagt, das könnte ein Krampf sein, bis sowas dann halbwegs läuft, wäre aber fürs Debuggen ein Traum.

    Auch das Problem mit der unpräzisen Emulation kenne ich (was du mit DMA Timing und PSCRT Register angerissen hast). QEMU und DOSBox sind für einige Dinge auch ungeeignet (speziell Hardware direkt ansprechen). Da nutze ich dann 86Box, was da deutlich präziser emuliert (und z.B. auch mit der Original Firmware/BIOS arbeitet). Es gab einige Bugs, die ich nur damit finden konnte. Auch 86Box scheint so einen GDB Server zu haben, der aber oft nicht mit einkompiliert ist. Den zu integrieren steht als nächstes an.

    Und was DOS-Grafik angeht: Die VGA-Adapter kennen zwar fixe Modi mit wohldefinierten Auflösungen, sind aber im Prinzip letztendlich auch nur "ein PCB, wo etwa 300 virtuelle Drähte rausgucken". Das ist dann die Grafik-API 😉 ... da kann man dann auch nicht-Standard Modi mit konfigurieren, wenn man an Registern für Timings und Frequenzen herumbastelt (und alles richtig macht, ohne dass der CRT Monitor explodiert). Das ermöglicht dann solche Modi wie "Mode X", die ursprünglich nicht vorgesehen waren aber sich dann doch irgendwie als "Standard" etabliert haben (gerade Mode X für Spiele wie Doom damals). Solche lowlevel-Hacks sind mir also durchaus ein Begriff 😉



  • @D_Key sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Einige Sachen habe ich schon gefundene,d ie HEAP Fresser sind, unordered_map und vor allem
    unordered_map<int, std::vector> sind absolute heap Killer.

    Wegen den Vorgaben des C++ Standard bezüglich Iterator Invalidation muss unordered_map auch Kollisionen mittels Chaining auflösen und kann keine offene Adressierung verwenden. Das bedeutet, dass jeder "Bucket" eine Linked List ist, die alle Einträge mit dem selben Hash enthält. Konkret ist das eine zusätzliche Indirektion und eben auch eine zusätzliche Heap-Allokation je Eintrag. Eventuell sind hier alternative Implementierungen eine gute Wahl, wie z.B. Container der Google Abseil Bibliothek oder andere.

    Und: Wie wird Heap reserviert? Alles "manuell" oder über eine eine "malloc"-Implementierung? Wenn ja, welche? Eventuell ist das ja ein Punkt wo man ansetzen könnte, um Fragmentierung zu reduzieren.



  • @Finnegan sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Dagegen ist Debugging bei meinem DOS-Projekt ja richtig luxuriös:

    Dadurch das ich ohnehin nur Mikrocontroller Programmiere, bin ich debug Probleme gewohnt.

    @Finnegan sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Ich frage mich da gerade, ob es auch für die PS2 einen Emulator mit integriertem GDB-Server gibt.

    Bei PCSX2 ist ein Debugger mit integriert, der funktioniert auch ganz gut. Aber wie gesagt bei Timing Problemen ist der Emulator unnütz.

    @Finnegan sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Wenn das PS2-Board irgendwo ein serielles Interface hat, könnte man so eventuell sogar auf echter Hardware remote-debuggen.

    Dazu gibt es https://github.com/ps2dev/ps2gdb
    Das funktioniert über die Netzwerkschnittstelle, aber das ist schnarch langsam
    wenn du 20Mb an Texturen drüber schaufelst vergehen 40 Min.
    Für die ersten Gehversuche ist das aber ok.

    Wenn die Projekte größer werden ist FreeMC Boot und ein USB-Stick die beste Wahl.
    Der USB Port ist zwar auch langsam aber immer noch besser als die Netzwerkschnittstelle.

    Der richtige Kracher ist dann der MemoryCard BUS, das ist ein "Regulärer SPI Bus".
    Aber es gibt eine Fallstricke es gibt kein Chip Select.
    das ist anders gelöst siehe:
    https://hackaday.io/project/170365-blueretro/log/186471-playstation-playstation-2-spi-interface.
    Da kannst du dann die Projekte via SD-Karte laden:
    https://www.trisaster.de/page/index.php?topic=575

    Das beste ist aber man hat ein DEV Tool, da kann man auch den IOP+PS1 Spiele debuggen, was in PCSX2 überhaupt nicht geht.

    Bei den DOS Kram bin ich raus, ich habe zwar noch einen Pentium 133 auf dem Dachboden aber ich nicht so in die DOS Welt hineingewachsen.
    Obwohl ich auch gerne crystal caves und simcity damals gespielt habe.
    Oder Superfrog...

    @Finnegan sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Und: Wie wird Heap reserviert? Alles "manuell" oder über eine eine "malloc"-Implementierung?

    Wie genau meinen heap initialisieren? Im Likerfile wird nur der Stack initialisiert und beim Linken die Statischen Arrays bzw in crt0.s. Der Rest der über bleibt ist der heap. std:.vector oder std::unordered_map wird beim Programmstart in den heap geladen.

    @Finnegan sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    wie z.B. Container der Google Abseil Bibliothek oder andere.

    Das schaue ich mir an.



  • @D_Key sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Das funktioniert über die Netzwerkschnittstelle, aber das ist schnarch langsam
    wenn du 20Mb an Texturen drüber schaufelst vergehen 40 Min.
    Für die ersten Gehversuche ist das aber ok.

    Texturen über die Debug-Schnittstelle finde ich auch etwas schwergewichtig. Auf einer DOS-Maschine über den seriellen Port wäre das auch nicht gerade schneller. Eher noch langsamer. Aber braucht man das wirklich? Ich würde darüber eher nur Breakpoints setzen und einzelne Variablen im Speicher inspizieren. Wenn ich die ganze Textur begutachten will, würd ich mir die dann eher auf der Maschine anzeigen lassen. Also in dem Fall dann sowas wie "printf-Debugging" nur eben mit Grafik und Texturen 😉

    @Finnegan sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Und: Wie wird Heap reserviert? Alles "manuell" oder über eine eine "malloc"-Implementierung?

    Wie genau meinen heap initialisieren? Im Likerfile wird nur der Stack initialisiert und beim Linken die Statischen Arrays bzw in crt0.s. Der Rest der über bleibt ist der heap. std:.vector oder std::unordered_map wird beim Programmstart in den heap geladen.

    Ich hab das glaube ich nicht ganz sauber formuliert. Wie wird der Heap verwaltet wenn du dynamisch zugewiesenen Speicher benötigst? Das was "übrig bleibt" ist der Heap, geschenkt. Aber auf dem arbeitet ja meist noch ein Speichermanager wie eine malloc-Implementierung bzw. im weiteren dann ein operator new der meist eben auch auf malloc aufbaut.

    Statisch initialisierte std::vector und evtl. auch std::unordered_map können theoretisch auch direkt vom Compiler in der .bss oder .data Section angelegt werden. Evtl. mit einem statischen Initialisierungscode um die Datenstrukturen zu füllen (sollte von der crt0 aufgerufen werden). Aber neue Werte einfügen und eventuell auch alte löschen sollte eigentlich auch malloc/free benötigen. Zumindest für den Standard-C++-Allokator.

    Kurz: bei dem SDK ist eine C Runtime dabei und die kann auch malloc/free? Ich vermute mal ja. Dieses malloc/free dürfte halt auch seinen Anteil an der "Heap-Fragmentierung" haben. Darauf will ich hinaus.

    Verwendest und verwaltest du denn auch Heap-Speicher direkt oder läuft das alles über malloc/free und new/delete? Oder machst du es eventuell nur "direkt"?

    In meinem DOS-Projekt habe ich auch einen solchen Heap (der Aufgrund von memory-gemappter Hardware und geladenem DOS bereits von Anfang an eine gewisse "Fragmentierung" aufweist). Den Speicher stelle ich dann dlmalloc zur Vefügung (eine simple und leichtgewichtige malloc-Implementierung). Das verwaltet dann den verfügbaren Heap dynamisch via malloc/free, auf denen dann alles weitere aufbaut. Letzten Endes eben auch die Default-Allokatoren für std::vector und andere.



  • @Finnegan sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Texturen über die Debug-Schnittstelle finde ich auch etwas schwergewichtig.

    Ja da gebe ich dir recht, im Grunde richtet man seinen TexturPuffer-Konfiguration einmalig ein und dann ist gut.

    @Finnegan sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Statisch initialisierte std::vector und evtl. auch std::unordered_map können theoretisch auch direkt vom Compiler in der .bss oder .data Section angelegt werden. Evtl. mit einem statischen Initialisierungscode um die Datenstrukturen zu füllen (sollte von der crt0 aufgerufen werden).

    Also was crt0 genau macht, habe ich noch nicht untersucht.
    Die Datei ist aber kein Geheimnis:
    https://github.com/ps2dev/ps2sdk/blob/master/ee/startup/src/crt0.c

    @Finnegan sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    Verwendest und verwaltest du denn auch Heap-Speicher direkt oder läuft das alles über malloc/free und new/delete?

    Das kommt darauf an für einigen Sachen nutze ich new.
    Bei den Texturen habe ich was mit align_val_t gebastelt.

    Bei MIPS Prozessoren muss alles ausgerichtet sein, sonst knallt es bei SQ oder LQ ,
    Sprich Store Quadword / Load Quadword.



  • @D_Key Ja, ich gehe davon aus, dass da irgendwo eine malloc-Implementierung drin ist. Beim groben Überfliegen hab ich auch was von "newlib" gesehen. Das ist eine flexible libc-Implementierung, die sich gut an verschiedenste Systeme anpassen lässt. Ich verwende auch für mein Projekt ein Derivat von dieser (picolibc). Das ist dann unter der Haube sehr wahrscheinlich ebenfalls dlmalloc oder eine Modifikation davon, was da den Speicher für new/delete verwaltet.

    Ich versuche halt, dein Heap-Fragmentierungs-Problem zu verstehen. Das sollte sich eigentlich dadurch äußern, dass Allokationen ab einer gewissen Größe fehlschlagen, obwohl in der Summe noch genug Speicher frei wäre. Ist das korrekt?

    Das mit dem VIF FIFO verstehe ich a nicht so ganz. Ich hab wie gesagt keine Ahnung von der PS2, aber wenn das stimmt was mir die KI hier erzählt, dann sollte der eigentlich nicht im Hauptspeicher liegen, sondern ein relativ kleiner (nur 128 Byte großer) Hardware-Puffer der Vector Instructional Unit (VIF) sein, der ausschließlich über spezielle Register angesprochen wird. Also nicht über MMIO in den Hauptspeicher-Adressraum gemappt. Daher ist mir etwas unklar, wie sich das mit dem normalen RAM und dem Heap in die Quere kommen kann.

    Der FIFO sollte eigentlich auch nur sehr kleine und kompakte Grafik-Kommandos beinhalten. Kann es vielleicht sein, dass sich da irgendwas staut und die Kommandos nicht abgearbeitet werden, so dass sich letztendlich dann auch sowas wie geladene Texturen im RAM unterwegs in den VRAM (via DMA?) ansammeln und den voll machen? Das wäre zumindest für mich einleuchtender. Aber wie gesagt, keine wirkliche Ahnung von der Kiste 😉

    @D_Key sagte in monotonic_buffer_resource sorgt für DMA Interrupt Error:

    align_val_t

    Ich kenne da deine konkrete Problematik nicht, aber Klassen und Daten-Member sollten sich eigentlich mit alignas(N) passend ausrichten lassen. Automatische Variablen, die Default-Allokatoren und new/delete sollten das auch entsprechend respektieren. Eine selbst-implementierte std::pmr::monotonic_buffer_resource sollte das in do_allocate() über den Alignment-Parameter natürlich auch berücksichtigen. dlmalloc sollte auch auf malloc/free-Ebene posix_memalign() unterstützen. Da müsste man mal schauen, ob das nach einem #include <malloc.h> zur Verfügung steht. C++17 kennt auch std::aligned_alloc(). Nur so als Anregung, aber offenbar hast du das Problem ja bereits gelöst.


Anmelden zum Antworten