How much of an increase in size do inline functions cause?
I have recently started making a C++ Wrapper of GTK+ (Nothing special, just wrapping everything into C++ classes for easy development, to be used in-house) and to cause minimum performance bloat to the already slow Gtk+ I used inline functions almost everywhere. Take a look at a few class functions...
class Widget : public Object
{
public: // A few sample functions. gwidget is the internal GTK+ widget.
void Show(void) { gtk_widget_show(GTK_WIDGET(gwidget)); }
void ShowNow(void) { gtk_widget_show_now(GTK_WIDGET(gwidget)); }
void Hide(void) { gtk_widget_hide(GTK_WIDGET(gwidget)); }
void ShowAll(void) { gtk_widget_show_all(GTK_WIDGET(gwidget)); }
public: // the internal Gtk+ widget.
GtkWidget* gwidget;
};
And although there is an almost non-existent performance bloat and the startup time and memory usage is exactly the same, the file size has increased dramatically. a C Gtk+ sample window generates 6.5 kb while a sample window using my wrapper generates 22.5 kb. , so I need a little advice. Should I continue using inline functions? I want my apps to be efficient and I can compromise a little on file size like I can take it even if a 6.5 kb C GTK+ program generated like 400-500 kb using my wrapper but NOT MORE. I don't want my wrapper to produce HUGE EXES like wxWidgets or MFC. So is it worthwile to use inline functions or should i use normal ones?
开发者_JS百科NOTE: all my functions only take up one or sometimes two lines and are not big as you can see in the example.
I strongly suspect you're comparing apples to oranges.
Did you compiler with exactly the same compiler, the same compile flags, and making an application with the exact same functionality?
If so, disassemble the executable, and see what the extra code is.
My guess is that it's some one-off library code used to support C++ features that were previously unused.
But as always, don't guess, measure.
You've got a single data point. That doesn't tell you much. We could be looking at a 350% increase in file size in all cases, or we could be looking at a fixed 16kb overhead. You need to find out which it is. So get some more data points. Extend your application. Make it open ten windows instead of one, or otherwise add extra functionality. is "your" version three times as big in that case too? Or is it 16kb larger? Or somewhere in between? Get some more data points, and you'll be able to see how the file size scales.
But most likely, you're worrying over nothing, for several reasons:
- the C++ compiler treats inline as a hint. You are making it easy for the compiler to inline the function, but the decision rests with the compiler itself, and it tries to make the application fast. If the file size starts growing out of control, that will slow down your code, and so your compiler will try to optimize more towards a smaller file size.
- you are looking at a couple of kilobytes. In an age of terabyte harddrives. If this has the potential to become a problem, then you should be able to provoke that problem in a test case. If you can't write a test that causes more than 16kb growth in file size, then it's not worth worrying about.
- if file size does become a problem, compilers typically have an "optimize for size" flag.
- large executables typically gain their size because they contain a lot of data and resources. The code itself is very rarely the problem (unless you go completely bonkers with template metaprogramming)
The size difference is more likely to be due to the libraries which are pulled in for C++, rather than in your C equivalent there is less library overhead.
If all your wrapper code follows the above, then very little to none in terms of bloat.
Looks to me that your solution is a good worth while way of implementing the wrapper.
To cause minimum performance bloat to the already slow Gtk+ I used inline functions almost everywhere
Compilers are quite good at knowing when to inline and when not to inline functions. The inline
keyword does not actually mean that the function will be inlined, only that definitions of that function in different translation units don't break the One Definition Rule (ODR).
Regarding the code size, it will depend on the compiler options, and a few other things, but for the code that you are presenting there should not be any effect, as if the function is inlined the call to one function will be replaced for the call to the other, those are one liners. Note that many compilers do create the function and leave it in the binary even if all uses are inlined, you might want to look at the compiler/linker documentation on how to remove those, but even if they are created, the size of the project should not be affected by much.
If you are willing to allow your project to grow from 6.5kb to 400kb, you should be more than fine.
It depends on
- how big your functions are
- how often you use them
- compiler settings (which you can influence)
- compiler implementation (which you can't)
etc. etc. In other words, don't assume, measure. Do a representative chunk of your project with and without inline functions and see what the effect is in your particular circumstances. Any predictions you receive across the internet will be educated guesses at best.
If your functions are only one or two lines then it's very unlikely that they'll increase the size of your resulting binary by any considerable amount. In fact, they could make it smaller if the code itself is smaller than the overhead code of a function call.
Note that either way, the overhead would be negligible. Just removing a single call to std::sort
or an instantiation of std::map
would offset any bloat. If you care about code size, small inlined functions are the least of your worries.
The examples that you give should incur no code increase at the calling side. Replacing an inline function that does just one call and nothing else, should be optimized by any decent compiler.
You'd have to investigate where the real increase is. Look at the assembler that is produced, this usually gives a good view on the the overhead.
There is no easy answer. It depends on many factors:
- the complexity of the function
- the CPU architecture and memory model
- implementation procedure calling conventions
- the parameter passing mechanism, including how the object accesses
this
Size is not the only efficiency to consider. On many modern CPUs, executing any kind of branch or call instruction may stall the CPU for the equivalent time of many instructions. Often replacing a call
instruction with a few instructions from the function body is a big time gain. It can also be a code size advantage since CPU registers may already have function parameters in them so they would not need to be pushed or moved.
Don't sweat little optimizations until there is a known space or speed issue. Then look for the 10% fix which affects 90% of the problem.
Congratulations, you are reinventing GTKmm, the official C++ bindings for GTK+.
精彩评论