2009-06-26 8 views
12

Dopo tre anni di lavoro su un progetto C++, l'eseguibile è cresciuto fino a 4 MB. Mi piacerebbe vedere dove sta andando tutto questo spazio. C'è uno strumento in grado di segnalare quali sono i più grandi maiali dello spazio? Sarebbe bello vedere la dimensione in base alla classe (tutte le funzioni in una classe), in base al modello (tutte le istanze) e in base alla libreria (quanto appartiene alla libreria standard C e alla STL? Quanto costa per ogni libreria nell'exe?)Esiste un "profiler della dimensione della funzione"?

Modifica: Nota, sto usando Visual C++ su Windows.

+0

Nel caso qualcuno si stia chiedendo, si è scoperto che Flite (un motore di sintesi vocale) era di gran lunga il componente più grande dei 4 MB a 1,8 MB IIRC, che ho scoperto rimuovendolo. – Qwertie

risposta

14

In Linux, è possibile utilizzare nm per mostrare tutti i simboli nel eseguibile e per ordinarli in ordine inverso per dimensione:

$ nm -CSr --size-sort <exe> 

Opzioni:

  • -C demangles C++ nomi.
  • -S mostra la dimensione dei simboli.
  • --size-sort ordina i simboli per dimensione.
  • -r inverte l'ordinamento.

Se si desidera ottenere i risultati per namespace o per classe, si può solo grep l'uscita per 'namespace::', 'namespace::class_name::', ecc.

Se si desidera visualizzare solo i simboli definiti in nell'eseguibile (non quelli definiti altrove, come nelle librerie), aggiungere --defined-only. L'ordinamento per dimensione dovrebbe occuparsi di questo, tuttavia, poiché i simboli indefiniti non avranno dimensioni.

Per Windows, si dovrebbe comunque essere in grado di utilizzare nm sui vostri file binari, poiché nm supporta COFF binari. È possibile installare nm tramite cygwin, oppure copiare il file eseguibile di Windows in un box Linux ed eseguire nm su di esso.

Si potrebbe anche provare dumpbin, che scarica informazioni su un file binario su Windows. Puoi ottenere informazioni sui simboli con lo switch /SYMBOLS, ma non sembra che fornisca direttamente informazioni sulla loro dimensione.

+0

Ah, le meraviglie di Linux. Peccato che io sia su Windblows. – Qwertie

+0

potresti compilarlo con gcc sotto cygwin e quindi usare il suo strumento nm per un elenco approssimativo. – Blindy

+1

Per quanto ne so, nm supporta COFF. Potresti semplicemente installarlo tramite cygwin, oppure puoi copiare l'exe su una macchina Linux ed eseguirlo su di esso. Si potrebbe anche provare il dumpbin dell'utilità Windows. Vedi qui: http://support.microsoft.com/?id=121460 – tgamblin

1

Ottenere una mappa di collegamento o utilizzare dumpbin per ottenere un elenco di simboli e dimensioni.

È probabile che ci sia un sacco di roba che non è strettamente necessario.

AGGIUNTO: hai avuto una risposta soddisfacente? Ho capito che ci sono due modi in cui le persone affrontano problemi come questo:

  • Ottenere le misure prima di fare qualsiasi cosa.
  • Basta trovare qualcosa di grosso di cui non hanno bisogno, strapparlo e ripetere finché non possono.

Personalmente preferisco quest'ultimo - ottiene risultati più rapidamente.

L'app è 4 MB. Supponiamo che le dimensioni reali necessarie siano 1 MB (o alcune di queste dimensioni). Ciò significa che se scegli una routine a caso dal file di mappa, è probabile che il 75% sia qualcosa che non ti serve. Scopri cosa sta causando la sua inclusione e vedi se ne hai davvero bisogno.

Nell'esempio che hai fornito, hai visto una classe che avvolge bitmap indipendenti dalla periferica. È possibile trovare istanze di tale classe nell'app e eventualmente sostituirle con bitmap WIN32 di base. Sarebbe meno carino, ma risparmia le dimensioni delle app.

Quindi continuare a farlo. Ogni pezzo di grandi dimensioni di cui ti sei sbarazzato fa sì che i pezzi rimanenti prendano una percentuale maggiore dell'app, perché l'app si è ridotta, ma i pezzi no. Questo li rende più facili da trovare nel file della mappa.

+0

Riprendendo l'esempio del wrapper DIB, quella classe potrebbe essere minuscola e non potrei salvare nulla estraendola. OTOH, forse ci sono molte diverse istanze di vettore , mappa , hash_map, ecc. E forse avrei risparmiato spazio trovando modi per condividere istanze. Ma poi di nuovo, forse il compilatore è abbastanza intelligente da fondere le sovroutine identiche (che probabilmente capita spesso con i template) o forse quelle classi non occupano così tanto spazio nonostante molte istanze. Forse se avessi dati buoni, risulterebbe che non posso salvare facilmente nessuno spazio, o che lo spazio sta andando in posti inaspettati. – Qwertie

+0

So dalle mie esperienze con i profiler "normali" che le mie intuizioni su dove stanno andando le risorse sono spesso sbagliate. Quindi non è sufficiente fare solo un'ispezione visiva di un file .map e semplicemente indovinare quali classi/funzioni/librerie occupano molto spazio. – Qwertie

+0

@Qwertie: So cosa intendi, ma se molte risorse esistono per un motivo non valido, scarsamente campionando la risorsa e determinando il motivo dietro ciascun campione, può rivelare il problema. Non si tratta di qualcosa che misura in modo accurato, ma dà poca idea. Hai bisogno di qualcosa che misura in modo approssimativo, ma dà la massima comprensione. –

7

In Windows sotto Visual Studio compila, questa informazione è nel tuo file .map (sarà vicino al .pdb).

AGGIUNTO: Per convertire i nomi decorati trovati nel file .map a qualcosa di più leggibile, è possibile utilizzare l'utilità undname.exe incluso in Visual Studio. Accetta i singoli nomi sulla riga di comando o è possibile alimentarlo con un file .map.

Per esempio,

Microsoft (R) C++ Name Undecorator 
Copyright (C) Microsoft Corporation. All rights reserved. 

Undecoration of "[email protected][email protected][email protected][email protected][email protected]@[email protected]@@[email protected]@[email protected]@[email protected][email protected][email protected]@[email protected]@@[email protected]@@Z" is 

"public: void __cdecl mini_vector<struct Math::Point<struct Math::FixedPoint<14,int> >,6>::push_back(struct Math::Point<struct Math::FixedPoint<14,int> > const &)" 
+2

Sto guardando il mio file di mappa e non vedo realmente righe come "0001: 0000f380? Push_back @? $ Mini_vector @ U? $ Punto @ U? $ FixedPoint @ $ 0O @ H @ Math @@@ Math @@ $ 05 @@ QAAXABU? $ Point @ U? $ FixedPoint @ $ 0O @ H @ Math @@@ Math @@@ Z 10010380 fi dibitmapsce: DIBitmap.obj "sono utili per la profilazione. – Qwertie

+0

Non lasciatevi scoraggiare dai nomi storti. Quello che dice nel supporto bitmap indipendente dal dispositivo c'è una funzione per l'aggiunta alla fine di un vettore di punti, ed è all'indirizzo F380 (62336) nel segmento 1. Scommetto che ce ne sono molti di più. Potresti cercare di vedere dove viene fatto riferimento, e se non è necessario, vedi se riesci a sbarazzartene. –

+0

È possibile undecorare i nomi con undname.exe, trovato nella directory dei bins di Visual Studio; l'esecuzione del collegamento "Prompt dei comandi di Visual Studio 200X" lo inserirà nel% PATH%. O se vuoi farli alla rinfusa, ho trovato questo script Python che lo fa automaticamente: http://holycall.tistory.com/entry/A-Simple-Python-Wrapper-to-Undecorate-Visual-Studio-Linker- Nomi dei simboli – Crashworks

1

Non guardate solo al codice - risorse può facilmente causare la crescita multi-megabyte.

+0

Proprio così: bitmap e simili possono essere enormi. –

+0

Fortunatamente la dimensione della bitmap è facile da misurare e non è un problema nel mio caso. – Qwertie

2

Non sono riuscito a far funzionare nm ma sono riuscito a trovare uno strumento utile chiamato Sizer. Legge le informazioni di debug create da Visual Studio utilizzando le librerie di accesso all'interfaccia di debug. È piuttosto semplice da usare, come descritto sul sito.

  1. compilazione con il debug di informazioni nel database di programma (PDB) file
  2. Run sizer da linea di comando per esempio Sizer.exe <path-to-exe-file>. L'output andrà allo stdout, quindi probabilmente vorrai reindirizzare a un file.

Le dimensioni del codice sono suddivise in sezioni diverse e raggruppate per funzione, dati, classe, ecc., Ciascuna sezione ordinata in ordine decrescente di dimensioni del codice.