Performance

Runtime Performance
Instance Size
Invocation Efficiency
Compile-Time Performance
Preprocessor Metaprogramming
Template Metaprogramming
Possible Improvements

Runtime Performance

Instance Size

Each interface instance has the size of a struct containing two void pointers.[1] The same is true for the smart interface pointers manual_ptr and unique_ptr, and for the smart reference unique_obj. Instances of shared_ptr and shared_obj are slightly larger, because of the use of shared_count, but still of fixed size. This contrasts sharply with classes inheriting from abstract base classes, whose instances, in many C++ implementations, may contain several vtable pointers to handle multiple inheritance.

Invocation Efficiency

Invocation of a function through an interface instance involves a lookup in an array of function pointers and a call through a function pointer. The body of the function which is called indirectly conatins an invocation of the appropriate member function of the bound object. This second invocation is potentially inlinable.

Code using interfaces can be significantly faster than code using abstract classes, for the following reason. Within the body of a class member function which implements an interface member function, calls to other member functions of the same class may be eligible for inlining even if they also implement interface member functions. By contrast, within the implementation of a member function declared in an abstract class, calls to other functions declared in the base class use virtual function dispatch by default. The program hfront-test.cpp in the directory <libs/interfaces/test/hfront> illustrates that this can result in a significant performance difference when the indirect calls are made in an inner loop: in some cases code using interfaces executes nearly ten times as fast as similar code using virtual functions.[2] These result suggest that it may be feasible to use indirect calls through interface instances in some cases where the use of virtual functions would be prohibitively expensive.[3]

Compile-Time Performance

Boost.Interfaces uses preprocessor metaprogramming to construct C++ class definitions from IDL macros and template metaprogramming to construct interface function tables from these C++ class definitions. Both of these constructions require a significant amount of processing; as a result, compiling IDL interface definitions is significantly slower than compiling the defintions of abstract classes.

Preprocessor Metaprogramming

Boost.Interfaces makes heavy use of the The Boost Preprocessor Metaprogramming library (see [Karvonen]). Preliminary measurements involving the regression tests indicate that preprocessor metaprogramming represents a relatively small percentage of total compilation time. Preprocessing time can still make a significant difference with a large project, however, especially with a slow preprocessor such as EDG.

Template Metaprogramming

The construction of an interface function table is an iterative process with length roughly equal to the total number of functions in the interface, including inherited functions, plus the total size of the inheritance graph. It is therefore an O(N) construction a with a relatively small N in most cases. Nonetheless, since each step requires a significant number of template instantiations, the overall cost can be high.

Possible Improvements

A certain amount of additional compiation time may be acceptable if there are gains in other areas. It remains to be seen what effect the additional compilation time will have on real-world projects. In any case, there are several ways that compilation times might be improved:

  1. People knowledgeable in preprocessor and template metaprogramming may be able to suggest improvements to the current implementation.
  2. The template-based IDL may turn out to offer better performance than the macro-based IDL.
  3. The syntax of the macro-based IDL could be modified to allow the definition of an interface in a single macro invocation.[4] While this would put more demands on the preprocessor, it would greatly reduce the amount of template metaprogramming required. Whether overall compilation times would improve is not known; the resulting syntax would almost certainly be less readable, however.
  4. Some of the library headers could be preprocessed before being included in the distribution. The most significant improvement would involve the headers <boost/interfaces/detail/invoker.hpp> and <boost/interfaces/detail/function_traits.hpp>.
  5. An IDL compiler could be provided to generate C++ class definitions from pseudocode definitions. This would eliminate the need for C++ metaprogramming alost entirely, but would make the library less accessible.

[1]See Implementation, note 1.

[2]This program originally appeared in the C/C++ Users Journal, together with sample output showing execution times. See [Diggins2]

[3]In some cases the performance penalty associated with virtual functions can be negated by explicitly qualifying the intra-object calls to disable virtual function dispatch. However, when a class hierarchy has been designed around the use of virtual functions, disabling virtual function dispatch may yield the wrong semantics. Furthermore, disabling virtual function dispatch is often impossible: the desired functionality may be accessible only through a public non-virtual member function which invokes a private virtual function.

[4]See [Abrahams].


Sha'arei Tefila, an Orthodox Shul (Synagogue) in Salt Lake City, Utah Chabad Lubavitch of Utah