Wie werden Profilerstellung und Speicherpooling pro System durchgeführt?


8

Ich war daran interessiert, für jedes Subsystem ein Profil zu erstellen und einen verwalteten Speicherpool zu führen, damit ich eine Statistik darüber erhalten konnte, wie viel Speicher in so etwas wie Sounds oder Grafiken verwendet wurde. Was wäre jedoch ein Design, das dafür funktioniert? Ich dachte daran, mehrere Allokatoren und nur einen pro Subsystem zu verwenden, was jedoch zu globalen Variablen für meine Allokatoren führen würde (oder so scheint es mir). Ein anderer Ansatz, den ich gesehen habe / der vorgeschlagen wurde, besteht darin, einfach neu zu überladen und einen Allokator für einen Parameter zu übergeben.

Ich hatte eine ähnliche Frage über auf Stackoverflow hier mit einer Prämie, aber es scheint , als ob vielleicht war ich zu ungenau oder einfach nur da ist nicht genug , um Menschen mit Wissen in dem Thema.


Meine Antwort wurde entfernt. Ich ging zurück und las die Artikel und die Pools, die zum Verfolgen der Zuordnungen pro System verwendet wurden, sind nicht Teil dieser Artikel (obwohl sie darauf basierten). Wenn ich diese spezifischen wieder finde, werde ich diese stattdessen verknüpfen! Es tut uns leid!
James

1
Schauen Sie sich diesen Blog-Beitrag von Jesus de Santos Garcia an. Darin erörtert er die Verfolgung des Speichers nach Subsystemen und die Verwendung mehrerer Allokatoren für verschiedene Speicheranforderungen.

7
Sei nicht besessen von theoretischen Paradigmen. Wenn Sie Funktionen und Daten global benötigen, ist an globalen Daten nichts auszusetzen. Es gibt bereits eine Reihe globaler Funktionen wie new / delete / malloc / free. Fügen Sie einfach hinzu, was Sie tun müssen, um die Arbeit zu erledigen.
Maik Semder

Antworten:


1

Es ist definitiv eine Frage, die für manche vage klingen könnte;)

Aber ich glaube ich weiß woher du kommst.

Sie haben eine Million Möglichkeiten, wie Sie dies implementieren möchten. Einige dieser Entscheidungen sollten sich sowohl auf die Zielplattformen als auch auf die allgemeinen Entwurfsziele beziehen. Diese Überlegungen lösen alle Bindungen, bis Sie sich mit unterschiedlichen Implementierungskosten wohl genug fühlen, um das Design von der Plattform und den allgemeinen Designproblemen zuerst zu erweitern. Bis dahin gibt es hier einige Möglichkeiten, die Sie nicht in Bezug auf Komplexität (Verwaltungsaufwand) oder den Umgang mit Entfernung oder Änderungen kosten, wenn Sie Ihre Meinung ändern ...

Wenn das Ziel darin besteht, zu messen und zuzuweisen, mit der Möglichkeit, Pools zu verwenden, müssen Sie zuerst über den Mindestsatz an lebenswertem Code nachdenken, um loszulegen. Zur Erklärung können Sie, wenn Sie Teil von Klassen sind, eine Klasse erstellen, die für einen Heap steht, oder stattdessen eine Reihe von Funktionen verwenden, die ein Handle oder einen Heap-Namen annehmen. Es ist wirklich eine Frage der Semantik, um ehrlich zu sein. Die nächste Entscheidung ist neu oder malloc; Ich bin ein Teil von Malloc, weil ich mich oft mit Konstrukten auf niedriger Ebene beschäftige und in den meisten Implementierungen weiß, dass New Malloc aufruft, und ich muss mir keine Sorgen über die Komplexität der Überladung neuer und über alle Plattformen machen . Ich habe jedoch oft Systeme oder Komponenten gebaut, um neue zu überladen oder zu haken. Und natürlich ist das Kernproblem oder der Unterschied, dass "neu" muss den Typ vor der Zuweisung kennen, wobei 'malloc' keine Rolle spielt und Sie mit malloc nach der Zuweisung in einen Typ auflösen. All dieses Detail soll Ihnen eine Idee und einen Kontext geben, in dem Sie Designentscheidungen in diesen Angelegenheiten treffen können :)

Also werde ich Klasse und Malloc auswählen, weil es hier einfacher zu erklären ist, aber es ist am Ende wirklich egal. Die Einbauten weisen im Vergleich zum Rest des Gesamtdesigns nur geringe Materialunterschiede auf.

In dieser Hypothese weiß ich also, dass ich (oder davon ausgehen werde) möglicherweise 7-8 echte Instanziierungen von Subsystemklassen habe und Hunderttausende von Anrufen für die Zuweisung und kostenlos vorwegnehme. Da sich ein Großteil meiner Neugier und meiner wirklichen Dynamik bei all dem auf die Größe und die Profilseite bezieht, möchte ich die Leistung der App nicht belasten. Für den Anfang könnte ich mich entscheiden, das Ganze einfach offen und öffentlich zu lassen, bis ich es festgenagelt habe, während ich es im gesamten Rest der App implementiere. Eine Struktur wird dies gut tun. Das 's_' soll zeigen, welche Variablen eindeutig für Statistiken bestimmt sind.

struct Mem
{
  int s_allocs;
  int s_frees;
  int s_peak;
  int s_current;
  void* heap; // if you wanted to go into having real actual separate heaps, else ignore
  void* alloc(int size);
  void free(void* p);

  Mem() {memset(this,0,szieof(Mem));}  // want this to be inlined with the call site constructor (a design decision example)
}

class MySubSystem
{
   Mem mem;
   ....  you get the idea
}

Das ist extremLeichtgewicht an vielen Fronten und vielleicht ein guter Ort, um zu konkretisieren, wo immer Sie wirklich hin wollten. Und Sie haben sofort ein Problem, woher wissen Sie die Größe des freigegebenen Artikels. (Dies wäre ein Problem, das für fast jeden Ansatz zu lösen ist.) Da dies ein Spielforum ist, können Sie die ersten paar Bytes mit der Größe dotieren, oder Sie müssen entweder umbrechen oder sich auf andere Weise daran erinnern. Die meisten Spielentwickler sollten nicht zu sehr gegen Doping sein, und es ist das einfachste Beispiel, wenn man bedenkt, dass ich bereits eine Textwand erstellt habe. Grundsätzlich geht das so: Sie wollen nicht, ob geholfen werden kann, die inhärente Ausrichtung zu zerstören, Sie wollen wissen, da fast kostenlos, ob die Größe kohärent ist. Also etwas so Einfaches wie "s_allocs ++; s_total + = size; uint64 * p = (uint64 *) malloc / calloc (size + = 8); * p = 0xDEADDAED00000000 | Größe; return p + 1; "wobei die Zuweisungen weniger als 4 GB betragen und uint64 das ist, was der Compiler für ein 64-Bit-Int ohne Vorzeichen hält, und wo Sie den Sanity-Wert kostenlos überprüfen können.

Dies ist alles eine Möglichkeit, um Ihnen das Nötigste zu minimalen Kosten zu bieten, die den Anforderungen entsprechen. Das tut es nichtAdresszuweisung von Klassen mit virtuellen Funktionen, wenn diese für die Profilerstellung oder Verwaltung vorgesehen sind, da Sie die Größe der von Ihnen verwendeten C ++ - Umgebung nicht vorhersehen können, ohne sie zu überladen oder neu zu verknüpfen, oder wenn Sie sich auf den Konstruktor in einem der Klassen verlassen seltsame Wege, die von keiner anderen 'init'-Funktion gehandhabt werden konnten. Andernfalls ist eine Struktur eine Klasse, eine willkürliche Zuordnung und beim Casting alle gleich. Wenn Sie an Neuem interessiert sind und die inhärente virtuelle Tabellen- oder Konstruktorsemantik benötigen, müssen Sie Neu einbinden, aber das ist ein ganz anderes Tier, das Sie wirklich studieren müssen, um sicherzustellen, dass Sie die neuen Anforderungen erfüllen und signalisieren müssen Ihr Code, der neu behandelt, auf welchen Bucket dies angewendet wurde. Ansonsten ist das obige Konzept dasselbe.

Noch wichtiger ist, dass dies Ihr Gehirn in Schwung bringt und hoffentlich in die Richtung geht, die Sie brauchen und was Ihre Toleranzen sind, nachdem Sie etwas mehr hinter dem Vorhang gesehen haben. Es gibt keinen Assistenten :)


Wenn Sie Vorlagenfunktionen zum Zuweisen und Freigeben verwendet haben, sollte es kein Problem sein, die Größe zu bestimmen, die freigegeben (und zugewiesen) werden muss.
API-Beast

1
Es ging darum, das zugrunde liegende Problem aufzuzeigen, um eine Grundlage für die Auswahl einer beliebigen Abstraktion zu schaffen und keine bestimmte Abstraktion zu präsentieren. Alles hat seine Nachteile. Das Wissen über die Größe ist notwendig, um nicht die Tat der Befreiung zu tun, sondern für die Statistik.
Celess

1

Sie müssen für diese Daten nichts in Ihrem Spiel implementieren. Tools wie Massif Valgrind können alle erforderlichen Daten aus den Debug-Symbolen extrahieren. Sie können die Speicherauszüge von Massif in Massif Visualizer anzeigen .


4
Ich würde vermuten, dass die meisten Grafikspiele leider nicht auf einem System entwickelt werden, auf dem Valgrind ausgeführt wird.
Kylotan

1

Ich empfehle dringend, keinen eigenen Speicherzuweiser zu schreiben. Sie benötigen eine stabile, zuverlässige und getestete Version mit guten Debugging-Funktionen wie Korruptionserkennung und vor allem: zuverlässigen Statistiken. Dies ist keine leichte Aufgabe und hat viele Fallstricke. Es gibt großartige und einfach zu verwendende, zum Beispiel:

Doug Lea Allokator

Es kommt mit dem Konzept der Speicherplätze, Sie können einen pro Subsystem verwenden. Es ist hoch optimiert und bietet Ihnen großartige Statistiken und Laufzeitinformationen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.