Расширение Ответ Чарльза .
Проблема здесь в том, что ваш цикл выполняет больше, чем просто тестирование самого виртуального вызова (распределение памяти, вероятно, в любом случае затмевает издержки виртуального вызова), поэтому он предлагает изменить код так, чтобы проверялся только виртуальный вызов.
Здесь эталонной функцией является шаблон, поскольку шаблон может быть встроенным, в то время как вызов через указатели функций маловероятен.
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);
}
Классы:
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));
}
И измерения:
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;
}
Примечание: это проверяет издержки виртуального вызова по сравнению с обычной функцией. Функциональные возможности различны (поскольку во втором случае у вас нет диспетчеризации во время выполнения), но это накладные расходы в худшем случае.
EDIT
Результаты выполнения (gcc.3.4.2, -O2, четырехъядерный сервер SLES10) примечание: с определениями функций в другом модуле перевода, для предотвращения встраивания
> ./test 5000000
Regular: 17041
Derived: 17194
Не совсем убедительно.