[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