[Asterisk-Dev] Moving towards macros..

Kevin P. Fleming kpfleming at starnetworks.us
Sun Dec 26 20:55:09 MST 2004


Matthew Boehm wrote:

> Perhaps someone could explain how/why macros gain performance over regular
> function calls, the additional malloc calls, and the inheritance?

There are some distinct advantages of macros over function calls in some 
situations. Especially when the macros are as complex as some of the 
ones in astobj.h, if you are using an intelligent optimizing compiler, 
it may be able to predetermine that some (possibly major) portion of the 
macro's code is not needed _in that particular instance_, due to the 
contents of the arguments being passed to the macro. This cannot be done 
using function calls; the function call must always occur.

With that said, though, gcc's support for "inline" functions can 
accomplish many of the same objectives: the compiler may choose to 
inline the function body, and if it does, then the function body's code 
is compiled as if it was actually present in that location in the 
caller's source, so the same optimizations can occur. The big benefit of 
using inline functions this way is compile-time type checking, which 
greatly reduces the time for developers to find problems, and can also 
reduce the number of occurrences of bugs that are not found until 
run-time. Also, using long (10+ line) macros makes compiler error 
messages next to useless for finding the true cause of a syntax error; 
inline functions don't have this problem.

Finally, inline functions will be left "out of line" when the compiler 
feels it is the right thing to do (although this decision can be 
influenced by the developer), and can even reference an "extern" copy of 
the function so the function's code is not duplicated in the current 
module when it has not been inlined. In other words, it's really slick 
:-) I've been trying to convince Mark and the others that this is a much 
better way to go than macros (there must be _some_ reason why the Linux 
kernel uses them so heavily), but so far noone has responded to my 
suggestions (other than by implementing things in a macro-based way).

I can't speak to how this affects inheritance; implemented properly, I 
don't believe it makes any difference, but I could certainly be proven 
wrong :-) There are also creative ways to avoid the "multiple malloc" 
issue, but they only work for "single inheritance" models.

I'll be interested to see how this plays out; the commit message for the 
conversion of chan_sip to this new model did not make it to my inbox, so 
  I'll have to go look at the code to see how it works.

One huge benefit to this change is that all modules will use a common 
locking infrastructure, and if it makes sense to switch to reader/writer 
locks for performance reasons, that can be done in only one place.

Brian's point (which didn't really answer your question) was very valid; 
I have already converted app_queue to use finer-grained locking to 
combat the very problem he referred to. I'll be interested to see if 
these new macros can help me make it an even cleaner implementation; I 
was just about to implement refcounts and object destruction myself, but 
now I don't have to :-) One thing that I don't like about the astobj.h 
macros, though, is the need to supply a pointer to the destructor for 
every call to "UNREF". IMHO that is a bad model, especially when it 
means that the destructor can no longer be a static function in the 
module that instantiated the object. It is much better to follow the 
Linux kernel's "kobject" model and when objects are instantiated, they 
get a pointer to their "class" structure that contains all method 
pointers for that class. This means that no user of the object ever 
needs to supply a destructor pointer (or even worry about whether the 
objects needs one), the object model core can always handle it on its 
own. It also allows for "lazy destruction", if that ever becomes of value.



More information about the asterisk-dev mailing list