2016-02-16 12 views
5

Ich versuche, ein großes C++ - Programm zu analysieren. Das Programm verwendet stark STL-Container-Datenstrukturen wie Satz, Karte, ungeordneter Satz, ungeordnete Karte, Vektor usw. Manchmal sind sie verschachtelt, z. Karte der Sätze.C++: Finde den größten Container in einem Programm

Ich möchte in einem bestimmten Lauf des Programms herausfinden, welche Container die größte Anzahl von Elementen enthalten (d. H. Der größte Wert von size()). Ich kann kleinere Änderungen am Programm vornehmen.

Wenn es eine Möglichkeit gab, über alle Container zu iterieren, oder wenn es eine Möglichkeit gab, die (größenmodifizierenden) APIs der Container abzufangen, hätte das hilfreich sein können. Aber das ist nicht möglich.

Wie würden Sie diesen Ansatz?

Zusatz: Die Plattform in Linux, Compiler ist entweder g ++ oder Clang ++.

+5

ich ein Speicher-Monitoring-Tool wie valgrind oder Entschlacken verwenden würden. – SergeyA

+1

Auf welcher Plattform befinden Sie sich? Ich würde dies mithilfe eines Tools erreichen, das den globalen Speicherzuordner festlegt. Visual Studio 2015 verfügt über leistungsstarke integrierte Tools zum Analysieren von Zuordnungen, Tools gibt es auch für andere Plattformen. – mattnewport

+0

@SergeyA: Können Sie bitte erwähnen, wie Valgrind hier verwendet werden kann? – Arun

Antwort

2

Diese Methode ist nützlich, wenn Ihr Projekt wirklich groß ist und sehr viele verschiedene Container enthält. Vorteil der Methode ist, dass Sie keine große Menge Code ändern müssen. Sie können den Typ des zu suchenden Containers einschränken. Diese Methode hilft, die Situation pro Behälter und Typ zu diagnostizieren.

Es ist möglich, template< class T > struct allocator neu zu definieren. Der ursprüngliche Zuordner kann in Standard-Kopfzeilen umbenannt oder geändert werden. Ermöglicht es, Statistiken für die Zuordnung und Freigabe zu erstellen. Sie werden Anzahl und Größe pro Elementtyp kennen. Aber Sie können nicht wissen, welche Instanz des Containers Elemente enthält.

Vorlage template< class T > struct allocator in Bibliothek Header-Dateien platziert. Es ist immer vorhanden und muss Ihre Entwicklungsumgebungsbibliothek nicht neu erstellen, da Sie wissen, dass die Vorlage nicht in eine statische Bibliothek kompiliert werden kann (Spezialisierung ausschließen). Vorlagen werden immer mit Ihren Quellen kompiliert. Aber möglicherweise ein Problem mit vorkompilierten Headern. Für das Projekt ist es möglich, es neu zu generieren oder nicht zu verwenden, aber für die Bibliothek muss es überprüft werden. Möglich ist dies ein Engpass der Methode, aber es ist einfach zu überprüfen, ob ein Problem existiert oder nicht.

Es gibt eine empirische Methode, die keine Genauigkeit garantiert. Wenn Ihre Anwendung heruntergefahren wird, werden die Container nach Zuweisung der Elemente freigegeben. So können Sie Statistiken pro Container des übergeordneten Typs schreiben, wie viele interne Elemente sich bei welchem ​​Containertyp befanden.

Zum Beispiel lassen wir haben:

vector<A>({1,2,3}) and map<string,B>({1,2}) and map<string,B>({1,2}) 

Diese Deallokation Ereignisliste wie folgt generieren:

B, B, map<string,B>, 
A, A, map<string,A>, 
A, A, A, vector<A>, 

So können Sie wissen, dass drei Elemente A bei vector<A>, 2 Elemente A bei map<string,A>, und 2 Elemente A unter map<string,A>

+0

Das Ändern von Std-Headern ist nicht koscher. – BitWhistler

+1

Kosher. Wenn es hilft, genug schwieriges Problem zu lösen. Und es ist nur in der Entwicklungsumgebung. Es ist auch koscher in der Produktion, wenn es hilft, Probleme zu lösen und Rollback wird so schnell wie möglich durchgeführt. Wenn das Ändern von std nicht koscher ist als das Entwickeln von std lib und IDE und OS ist auch nicht koscher. – oklas

2

Wenn Sie kleinere Änderungen vornehmen können, Können Sie jeden Container einer großen Liste hinzufügen?
So:

std::set<......> my_set; // existing code 
all_containers.add(&my_set); // minor edit IMHO 

Dann können Sie all_containers.analyse() nennen, die size() auf jeden von ihnen nennen würde und die Ergebnisse ausdrucken.

Sie können so etwas verwenden:

struct ContainerStatsI { 
    virtual int getSize() = 0; 
}; 
template<class T> struct ContainerStats : ContainerStatsI { 
    T* p_; 
    ContainerStats(T* p) : p_(p) {} 
    int getSize() { return p->size(); } 
}; 
struct ContainerStatsList { 
    std::list<ContainerStatsI*> list_; // or some other container.... 
    template<class T> void add(T* p) { 
    list_.push_back(new ContainerStats<T>(p)); 
    } 
    // you should probably add a remove(T* p) as well 
    void analyse() { 
    for(ContainerStatsI* p : list_) { 
     p->getSize(); // do something with what's returned here 
    } 
    } 
}; 
+0

Es ist möglich, Makros zu verwenden, die an die all_containers-Datei und die Zeile übergeben werden, in der der Container tatsächlich erstellt wird. – oklas

+0

Sie können es mit einem Makro für file: line tun oder Sie können einen String-Namen oder eine andere Form von id in der add-Methode hinzufügen. – BitWhistler

+0

Danke für die Idee. Das Hinzufügen von 'ContainerStats *' -Klassen ist sehr gut möglich, aber das Hinzufügen von 'add()' für jeden Container ist beeindruckend. Wie adressieren wir verschachtelte Container, z.B. eine Karte von einem Int zu einem Set? – Arun

1

Statistiken hinzufügen Code Destruktoren von Containern in std Header-Dateien. Dies erfordert nicht, große Menge an Code eines großen Projekts zu ändern. Aber das zeigt auch nur Containertyp (siehe meine andere Antwort hier). Methode erfordert nicht C++ 0x oder C++ 11 oder mehr.

Erste und Pflicht Schritt ist std libary unter Quellcodeverwaltung, git zum Beispiel für die schnelle Ansicht hinzuzufügen, was tatsächlich geändert wird und für den schnellen Wechsel zwischen modifizierten und Original-Version.

Diese Erklärung Stat Klasse in std Bibliothek Quellen Ordner:

class Stat { 
    std::map<std::string,int> total; 
    std::map<std::string,int> maximum; 
public: 
    template<class T> 
    int log(std::string cont, size_t size) { 
     std::string key = cont + ": " + typeid(T).name(); 
     if(maximum[key] < size) maximum[key] = size; 
     total[key] += size; 
    } 
    void show_result() { 
     std::cout << "container type total maximum" << std::endl; 
     std::map<std::string,int>::const_iterator it; 
     for(it = total.begin(); it != total.end(); ++it) { 
      std::cout << it->first << " " << it->second 
       << " " << maximum[it->first] << std::endl; 
     } 
    } 
    static Stat& instance(); 
    ~Stat(){ show_result(); } 
}; 

Instantiate Instanz von Singleton von Stat Klasse in Ihrem Projekt CPP-Datei:

Stat& Stat::instance() { 
    static Stat stat; 
    return stat; 
} 

Bearbeiten Sie die std Bibliothek Container-Vorlagen. Fügen Sie statistische Deskriptionen bei Destruktoren hinzu.

// modify this standart template library sources: 

template< T, Allocator = std::allocator<T> > vector { 
    ... 
    virtual ~vector() { 
     Stat::instance().log<value_type>("std::vector", this->size()); 
    } 
}; 

template< Key, T, Compare = std::less<Key>, 
    Allocator = std::allocator<std::pair<const Key, T> > map { 
    ... 
    virtual ~map(){ 
     Stat::instance().log<value_type>("std::map", this->size()); 
    } 
}; 

ein Programm zum Beispiel Betrachten wir nun:

int main() { 
    { 
     // reject to use C++0x, project does not need such dependency 
     std_vector<int> v1; for(int i=0;i<10;++i) v1.push_back(i); 
     std_vector<int> v2; for(int i=0;i<10;++i) v2.push_back(i); 
     std_map<int,std::string> m1; for(int i=0;i<10;++i) m1[i]=""; 
     std_map<int,std::string> m2; for(int i=0;i<20;++i) m2[i]=""; 
    } 
    Stat::instance().show_result(); 
    return 0; 
} 

Das Ergebnis für gcc ist:

container type total maximum 
std::map: St4pairIiSsE 30 20 
std::vector: i 20 10 

Wenn Sie ausführlichere Typ desription benötigen, als Ihre finden Informationen über Entwicklungsumgebung. Eine solche Umwandlung hier für gcc beschrieben: https://lists.gnu.org/archive/html/help-gplusplus/2009-02/msg00006.html

Ausgang kann so aussehen:

container type total maximum 
std::map: std::pair<int, std::string> 30 20 
std::vector: int 20 10 
+0

Vielleicht möglich, aber die schmutzigste Annäherung möglich. – BitWhistler

+1

Realy Durty ist so ohne Argumente sprechen. – oklas

+0

Achten Sie auf Ihre statischen Daten. Es kann möglicherweise zerstört werden, nachdem die Stat-Instanz zerstört wurde. Solche Daten können manchmal wie "nicht sichtbar" für Statistik sein. – oklas

Verwandte Themen