Before you cringe at the duplicate title, the other question wasn\'t suited to what I ask here (IMO). So.
I am really wanting to use virtual functions in my applicat
Extending Charles' answer.
The problem here is that your loop is doing more than just testing the virtual call itself (the memory allocation probably dwarfs the virtual call overhead anyway), so his suggestion is to change the code so that only the virtual call is tested.
Here the benchmark function is template, because template may be inlined while call through function pointers are unlikely to.
template <typename Type>
double benchmark(Type const& t, size_t iterations)
{
timeval a, b;
gettimeofday(&a, 0);
for (;iterations > 0; --iterations) {
t.getArea();
}
gettimeofday(&b, 0);
return (b.tv_sec * (unsigned int)1e6 + b.tv_usec) -
(a.tv_sec * (unsigned int)1e6 + a.tv_usec);
}
Classes:
struct Regular
{
Regular(size_t w, size_t h): _width(w), _height(h) {}
size_t getArea() const;
size_t _width;
size_t _height;
};
// The following line in another translation unit
// to avoid inlining
size_t Regular::getArea() const { return _width * _height; }
struct Base
{
Base(size_t w, size_t h): _width(w), _height(h) {}
virtual size_t getArea() const = 0;
size_t _width;
size_t _height;
};
struct Derived: Base
{
Derived(size_t w, size_t h): Base(w, h) {}
virtual size_t getArea() const;
};
// The following two functions in another translation unit
// to avoid inlining
size_t Derived::getArea() const { return _width * _height; }
std::auto_ptr<Base> generateDerived()
{
return std::auto_ptr<Base>(new Derived(3,7));
}
And the measuring:
int main(int argc, char* argv[])
{
if (argc != 2) {
std::cerr << "Usage: %prog iterations\n";
return 1;
}
Regular regular(3, 7);
std::auto_ptr<Base> derived = generateDerived();
double regTime = benchmark<Regular>(regular, atoi(argv[1]));
double derTime = benchmark<Base>(*derived, atoi(argv[1]));
std::cout << "Regular: " << regTime << "\nDerived: " << derTime << "\n";
return 0;
}
Note: this tests the overhead of a virtual call in comparison to a regular function. The functionality is different (since you do not have runtime dispatch in the second case), but it's therefore a worst-case overhead.
EDIT:
Results of the run (gcc.3.4.2, -O2, SLES10 quadcore server) note: with the functions definitions in another translation unit, to prevent inlining
> ./test 5000000
Regular: 17041
Derived: 17194
Not really convincing.
There is a performance impact to calling a virtual function, because it does slightly more than calling a regular function. However, the impact is likely to be completely negligible in a real-world application -- even less so than appear in even the most finely crafted benchmarks.
In a real world application, the alternative to a virtual function is usually going to involve you hand-writing some similar system anyhow, because the behavior of calling a virtual function and calling a non-virtual function differs -- the former changes based on the runtime type of the invoking object. Your benchmark, even disregarding whatever flaws it has, doesn't measure equivalent behavior, only equivalent-ish syntax. If you were to institute a coding policy banning virtual functions you'd either have to write some potentially very roundabout or confusing code (which might be slower) or re-implement a similar kind of runtime dispatch system that the compiler is using to implement virtual function behavior (which is certainly going to be no faster than what the compiler does, in most cases).