gtkmm code size



I have recently done some work to optimize gtkmm for code size, for use
on embedded devices, such as Nokia's 770 internet table. I was concerned
that, for instance
- the _stripped_ code size of gtkmm 2.6's libgtkmm .so is 2.5M on i686, 
- which is comparable to the size of libgtk-x11's .so (version 2.8 is
2.9M).

It didn't seem right that the wrapper is as big as the thing it wraps,
because our method implementations are so small.

I have discovered that a large part of this code size is explained
simply by the size of our API, and we have a lot of extra convenience
API compared to GTK+. Simply exporting a symbol adds to the code size. I
shaved a few 100K off the .so size just by using the static 
keyword on private functions, to stop them being exported. The 2.5M
number above is including these easy optimizations.


*** Optional API:

I also added some glibmm configure options to remove rarely-used API.
Remember, nothing will change on regular linux distros, because they
won't use these options:
--enable-api-properties=no
  You can use get/set_property<>("propertyname") instead.
--enable-api-vfuncs=no
  These are rarely needed. You can use the C function pointer instead.
--enable-api-exceptions=no
  Methods that throw an exception have an extra 
  std::auto_ptr<Glib::Error>& output parameter when this option is
  used. 
  This allows use of the "-fno-exceptions" CXXFLAGS, which does not 
  have much affect, but being able to use "-fno-exceptions" means 
  that "-g -Os" (Optimize for code size) can start to be significant.
  Together they reduce code size by about 15%.
--enable-deprecated-api=no
  Do not build deprecated API, such as Gtk::FileSelector. This option 
  has been in tarballs for a few months already.
  This must be specified to gtkmm as well as glibmm.

These options will soon be in releases of glibmm 2.6, 2.8, and 2.10.
Necessary changes will be in gtkmm 2.6, 2.8, and 2.9/2.10. Until Cairo
is fully optimized, people are using GTK+/gtkmm 2.6 on embedded
platforms, but some are using glib/glibmm 2.10.

Together, with the mentioned CXXFLAGS, these reduce total code size for
all of the gtkmm 2.6 .so files by around 800K, or 23%.


*** Virtual methods:

However, there is another huge gain to be made by removing default
signal handlers, such as Gtk::Button::on_clicked(). The problem is that
they are virtual methods, so we have to pay for them even if we don't
use them. We must pay for them in 
- code size: That's a lot of symbols in libgtkmm, and the symbols must
be listed in applications that use libgtkmm.
- load time: the symbols must be resolved by applications that use
libgtkmm.

Gtk::Widget has about 60 signals, so that's at least 60 virtual methods
for each widget. As far as I can tell, this increases the code size of
each derived class, even if a derived-of-derived class, maybe due to
multiple inheritance.

I have not yet committed this configure option to cvs, because this is
the most disruptive option. Overriding virtual methods, instead of
connecting signals, is quite convenient, but I don't think it's worth
the cost on an embedded platform just for convenience. I might commit it
later. The patch is here:
http://bugzilla.gnome.org/show_bug.cgi?id=341380

It removes an extra approx. 500K from the libgtkmm code size.

I also have a simple patch to remove libatkmm, which is not yet very
useful on embedded devices. 


*** Failed attempts

- I have not noticed any significant reduction in code size by using the
-fno-inline CXXFLAGS. I had thought that there might be a lot of RefPtr
or sigc:: inlining, but I guess that the implementations of these
functions are not significantly larger than a function call itself.

- I have tried ripping libsigc++ apart to reduce the number of templates
and template parameters that are used, with almost no effect. Based on
this, and my other code-size investigations, I no longer believe the
commonly-mentioned theory that libgtkmm is large because of too many
template instantiations. I'd gladly be proven wrong.

- I can strip a few more 100K from the code size by turning
the /private/*.h callbacks into functions instead of class methods, and
marking them as static, but I would then need to make various protected
parts of the classes public.


*** Summary

I believe that the remaining code size is just a fact of life of using C
++, and of having such a large (capable) API. In particular, we must
list all those symbol names, and C++ symbol names are larger than C
symbol names, due to the (wanted) namespaces and mangling. I can imagine
that the linker/ELF could some kind of compression, but that would slow
down load times. 

But it is rather difficult to analyze code size:
http://www.murrayc.com/blog/permalink/2006/02/15/c-code-size/
so I hope that some of you have some more ideas.

These options (and the patch) do at least mean that developers would not
have to pay for things they don't use. That is the C++ philosophy.

-- 
Murray Cumming
murrayc murrayc com
www.murrayc.com
www.openismus.com




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]