views:

328

answers:

4

After three years working on a C++ project, the executable has grown to 4 MB. I'd like to see where all this space is going. Is there a tool that could report what the biggest space hogs are? It would be nice to see the size by class (all functions in a class), by template (all instantiations), and by library (how much belongs to the C standard library and STL? how much for each library in the exe?)

Edit: Note, I am using Visual C++ on Windows.

+4  A: 

In Linux, you can use nm to show all symbols in the executable and to sort them in reverse order by size:

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

Options:

  • -C demangles C++ names.
  • -S shows size of symbols.
  • --size-sort sorts symbols by size.
  • -r reverses the sort.

If you want to get the results per namespace or per class, you can just grep the output for 'namespace::', 'namespace::class_name::', etc..

If you only want to see symbols that are defined in the executable (not ones defined elsewhere, like in libraries) then add --defined-only. Sorting by size should take care of this, though, since undefined symbols aren't going to have a size.

For Windows, you should still be able to use nm on your binary files, since nm supports COFF binaries. You can install nm via cygwin, or you could copy your windows executable to a linux box and run nm on it there.

You could also try dumpbin, which dumps info about a binary on Windows. You can get info on symbols with the /SYMBOLS switch, but it doesn't look like it directly provides information about their size.

tgamblin
Ahh, the wonders of Linux. It's too bad I'm on Windblows.
Qwertie
you could compile it with gcc under cygwin and then use its nm tool for an aproximate list.
Blindy
As far as I know, nm supports COFF. You could just install it via cygwin, or you could copy the exe over to a Linux box and run nm on it there. You could also try the windows utility dumpbin. See here: http://support.microsoft.com/?id=121460
tgamblin
I don't think you even need to compile your exe with gcc to use nm on it. All nm does is read the binary format.
tgamblin
If you copy it to linux, it can happen you need to recompile binutils, to have target support for COFF, i think.
Johannes Schaub - litb
Thank you for explaining the meanings of the parameters you used, instead of just giving the whole command as a magic incantation. More people should follow your good example.
Rob Kennedy
+1  A: 

Get a link map, or use dumpbin to get a list of symbols and sizes.

Chances are there's a lot of stuff being pulled in that you don't strictly need.

ADDED: Did you get a satisfactory answer? I realized there are two ways people approach problems like this:

  • Get measurements before they do anything.
  • Just find something big that they don't need, rip it out, and repeat until they can't.

Personally I prefer the latter - it gets results quicker.

You say the app is 4MB. Suppose the true necessary size is 1MB (or some such size). That means if you pick a routine at random from the map file, it is 75% likely to be something you don't need. Find out what's causing it to be included, and see if you really need it.

In the example you gave, you saw a class that wraps device-independent-bitmaps. You could find instances of that class in your app, and possibly replace them with basic WIN32 bitmaps. It would be less pretty, but save gobs of app size.

Then keep on doing it. Each large piece you get rid of makes the remaining pieces take a larger percentage of the app, because the app has shrunk but the pieces haven't. That makes them easier to find in the map file.

Mike Dunlavey
Taking the example of the DIB wrapper again, that class might be tiny and I might not save anything by ripping it out. OTOH, maybe there are many different instances of vector<T>, map<K,V>, hash_map, etc. and maybe I'd save space by finding ways to share instances. But then again, maybe the compiler is smart enough to merge identical suproutines (which probably happens often with templates) or maybe those classes don't take up that much space despite many instances. Maybe if I had good data it would turn out that I can't easily save any space, or that the space was going to unexpected places.
Qwertie
I know from my experiences with "normal" profilers that my intuitions about where resources are going are often wrong. So it's not enough to just make a visual inspection of a .map file and simply guess which classes/functions/libraries take a lot of room.
Qwertie
@Qwertie: I know what you mean, but if a lot of some resource exists for a poor reason, sparsely sampling the resource, and determining the reason behind each sample, can reveal the problem. You don't something that measures accurately but gives little insight. You need something that measures coarsely but gives maximum insight.
Mike Dunlavey
+6  A: 

In Windows under Visual Studio compiles, this information is in your .map file (it'll be near the .pdb).

ADDED: To convert the decorated names found in the .map file to something more human-readable, you can use the undname.exe utility included with Visual Studio. It accepts individual names on the commandline or you can feed it a .map file.

For example,

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

Undecoration of "?push_back@?$mini_vector@U?$Point@U?$FixedPoint@$0O@H@Math@@@Math@@$05@@QAAXABU?$Point@U?$FixedPoint@$0O@H@Math@@@Math@@@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 &)"
Crashworks
I'm looking at my map file, and not really seeing how lines like "0001:0000f380 ?push_back@?$mini_vector@U?$Point@U?$FixedPoint@$0O@H@Math@@@Math@@$05@@QAAXABU?$Point@U?$FixedPoint@$0O@H@Math@@@Math@@@Z 10010380 f i dibitmapsce:DIBitmap.obj" are useful for profiling.
Qwertie
Don't be put off by the mangled names. That says in the device-independent bitmap support there is a function for appending to the end of a vector of points, and it is at address F380 (62336) in segment 1. I bet there are a lot more like it. You might look to see where this is referenced, and if not needed, see if you can get rid of it.
Mike Dunlavey
You can undecorate names with undname.exe, found in your Visual Studio bins directory; running the "Visual Studio 200X Command Prompt" shortcut will put it into your %PATH%. Or if you want to do them in bulk, I found this Python script that does it automatically: http://holycall.tistory.com/entry/A-Simple-Python-Wrapper-to-Undecorate-Visual-Studio-Linker-Symbol-Names
Crashworks
Crashworks
@Qwertie: the thing is, the length of name correlates with the number of routines, so you're probably seeing the tip of a big iceberg. If there is a line somewhere like "CDiBitmap myDIB;" that is not actually used, it could pull that elephant into your living room. If you need a DIB, you might just use the basic WIN32 object.
Mike Dunlavey
@Qwertie your comment makes the whole website a mess, at least on Mozilla Firefox 3.5.
Daniel Daranas
Looks fine in IE and Chrome. Firefox is open source; why not fix it yourself? (j/k)
Crashworks
Nah, I refuse to work for free :)
Daniel Daranas
+1  A: 

Don't just look at code - resources can easily cause multi-megabyte growth.

Michael
Mike Dunlavey
Luckily bitmap size is easy to measure - and is not an issue in my case.
Qwertie