2015-03-14 10 views
8

В рамках проектирования системы нам необходимо реализовать заводскую модель. В сочетании с шаблоном Factory мы также используем CRTP, чтобы предоставить базовый набор функций, которые затем могут быть настроены классами Derived.C++ Низкая задержка Дизайн: Функция Dispatch v/s CRTP для заводской реализации

Пример кода ниже:

class FactoryInterface{ 
    public: 
    virtual void doX() = 0; 
}; 

//force all derived classes to implement custom_X_impl 
template< typename Derived, typename Base = FactoryInterface> 
class CRTP : public Base 
{ 
    public: 
    void doX(){ 
     // do common processing..... then 
     static_cast<Derived*>(this)->custom_X_impl(); 
    } 
}; 

class Derived: public CRTP<Derived> 
{ 
    public: 
     void custom_X_impl(){ 
     //do custom stuff 
     } 
}; 

Хотя эта конструкция свертывается, она делает обеспечить несколько преимуществ. Все вызовы после вызова начальной виртуальной функции могут быть встроены. Вызов производного класса custom_X_impl также выполняется эффективно.

Я написал программу сравнения, чтобы сравнить поведение для подобной реализации (жесткий цикл, повторные вызовы) с помощью указателей функций и виртуальных функций. Этот дизайн получился триумфом для gcc/4.8 с O2 и O3.

Гуру C++, однако, вчера сказал мне, что любой вызов виртуальной функции в большой исполняющей программе может принимать переменное время, учитывая промахи в кэше, и я могу добиться потенциально лучшей производительности, используя таблицы функций таблицы стиля и gcc hotlisting функций. Однако я все еще вижу 2x стоимость в моей примерной программе, упомянутой выше.

Мои вопросы следующие: 1. Утверждается ли утверждение гуру? Для любых ответов есть ли ссылки, на которые я могу ссылаться. 2. Есть ли какая-либо реализация с низкой задержкой, которую я могу ссылаться, имеет базовый класс, вызывающий пользовательскую функцию в производном классе, используя указатели функций? 3. Любые предложения по улучшению дизайна?

Любая другая обратная связь всегда приветствуется.

ответ

2

Ваш гуру ссылается на горячий атрибут gcc-компилятора. Эффект этого attribute является:

функция оптимизирована более агрессивна и на многих целях она помещаются в специальный подраздел раздела текста таким образом, все горячие функций появляются близко друг к другу, улучшение местности.

Так что да, в очень большой базе кода функция hotlisted может оставаться в кеше, готовой к выполнению без задержки, потому что она пропускает кеширование avodis.

Вы можете прекрасно использовать этот атрибут для функций-членов:

struct X { 
    void test() __attribute__ ((hot)) {cout <<"hello, world !\n"; } 
}; 

Но ...

При использовании виртуальных функций компилятор обычно генерирует vtable, который разделяется между всеми объектами класса. Эта таблица представляет собой таблицу указателей на функции. И действительно - ваш гуру прав - ничто не гарантирует, что эта таблица останется в кэшированной памяти.

Но если вы вручную создаете таблицу указателей функций «C-style», проблема будет ТОЧНО ОДНОЙ. Хотя функция может оставаться в кеше, ничто не гарантирует, что ваша таблица функций также останется в кеше.

Основное различие между этими двумя подходами заключается в следующем:

  • в случае виртуальных функций, компилятор знает, что виртуальная функция является горячей точкой, и может принять решение, чтобы убедиться, чтобы сохранить виртуальные таблицы в кеше (я не знаю, может ли gcc это сделать или если есть планы сделать это).

  • в случае таблицы указателей ручной функции, ваш компилятор не будет легко вывести, что таблица принадлежит горячей точке. Таким образом, эта попытка ручной оптимизации может очень сильно отразиться на обратном.

Мое мнение: никогда не пытайтесь оптимизировать себя, что может сделать компилятор намного лучше.

Заключение

Доверьтесь в своих тестах. И доверяйте своей ОС: если ваша функция или ваши данные часто используются, есть большие шансы, что современная ОС учтет это в своем управлении виртуальными памятью и независимо от того, что будет генерировать компилятор.

+0

Thanks Christophe. Ваш анализ связан с тем, что я вижу в тестах производительности. Вы видите какие-либо потенциальные оптимизации в дизайне? – Sid

+0

Думаю, будет еще труднее оптимизировать! Поскольку doX() должен быть виртуальным, а Derived определяется клиентом, я не нахожу другой альтернативы с меньшей косвенностью. – Christophe

 Смежные вопросы

  • Нет связанных вопросов^_^