Подтвердить что ты не робот

Когда следует использовать __forceinline вместо встроенного?

Visual Studio включает поддержку __forceinline. Документация Microsoft Visual Studio 2005 гласит:

Исключение ключевых слов __forceinline анализ затрат/выгод и полагается по мнению программиста вместо этого.

Возникает вопрос: когда неправильный анализ затрат/выгод компилятора? И как я должен знать, что это неправильно?

В каком сценарии предполагается, что я знаю лучше, чем мой компилятор по этой проблеме?

4b9b3361

Ответ 1

Компилятор принимает решения на основе анализа статического кода, тогда как если вы профилируете, как говорит дон, вы проводите динамический анализ, который может значительно продвинуться. Количество вызовов определенной части кода часто во многом определяется контекстом, в котором он используется, например. данные. Профилирование типичного набора вариантов использования сделает это. Лично я собираю эту информацию, позволяя профилировать мои автоматические регрессионные тесты. В дополнение к форсированию встроенных линий у меня развернуты циклы и реализованы другие ручные оптимизации на основе таких данных. Также необходимо снова профилировать потом, так как иногда ваши лучшие усилия могут фактически привести к снижению производительности. Опять же, автоматизация делает это намного менее болезненным.

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

Ответ 2

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

Ответ 3

Единственное, что я использую, это проверка лицензии.

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


*) Пожалуйста, не включайте это в дискуссию о том, что все может быть взломанным - я знаю. Кроме того, это само по себе не очень помогает.

Ответ 4

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

Ответ 5

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

Ответ 6

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

рекурсивной, длинный, состоящий из петель,

Если вы хотите принудительно принять это решение, используя __forceinline

Ответ 7

Собственно, даже с ключевым словом __forceinline. Visual С++ иногда предпочитает не встраивать код. (Источник: итоговый исходный код сборки.)

Всегда смотрите на результирующий код сборки, где важна скорость (например, плотные внутренние петли должны выполняться на каждом кадре).

Иногда использование #define вместо встроенного будет делать трюк. (конечно, вы теряете много проверок, используя #define, поэтому используйте его только тогда, когда и где это действительно имеет значение).

Ответ 8

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

В общем, современные компиляторы действительно очень хороши в принятии этого решения.

Ответ 9

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

Ответ 10

На самом деле, boost загружается с ним.

Например

 BOOST_CONTAINER_FORCEINLINE flat_tree&  operator=(BOOST_RV_REF(flat_tree) x)
    BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value ||
                        allocator_traits_type::is_always_equal::value) &&
                         boost::container::container_detail::is_nothrow_move_assignable<Compare>::value)
 {  m_data = boost::move(x.m_data); return *this;  }

 BOOST_CONTAINER_FORCEINLINE const value_compare &priv_value_comp() const
 { return static_cast<const value_compare &>(this->m_data); }

 BOOST_CONTAINER_FORCEINLINE value_compare &priv_value_comp()
 { return static_cast<value_compare &>(this->m_data); }

 BOOST_CONTAINER_FORCEINLINE const key_compare &priv_key_comp() const
 { return this->priv_value_comp().get_comp(); }

 BOOST_CONTAINER_FORCEINLINE key_compare &priv_key_comp()
 { return this->priv_value_comp().get_comp(); }

 public:
 // accessors:
 BOOST_CONTAINER_FORCEINLINE Compare key_comp() const
 { return this->m_data.get_comp(); }

 BOOST_CONTAINER_FORCEINLINE value_compare value_comp() const
 { return this->m_data; }

 BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const
 { return this->m_data.m_vect.get_allocator(); }

 BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const
 {  return this->m_data.m_vect.get_stored_allocator(); }

 BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator()
 {  return this->m_data.m_vect.get_stored_allocator(); }

 BOOST_CONTAINER_FORCEINLINE iterator begin()
 { return this->m_data.m_vect.begin(); }

 BOOST_CONTAINER_FORCEINLINE const_iterator begin() const
 { return this->cbegin(); }

 BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const
 { return this->m_data.m_vect.begin(); }