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

class MyClass
{
    public:
        MyClass()
        {
            m_dbLoopStart   = 0.0;
            m_dbLoopStop    = 100.0;
            m_dbLoopStep    = 0.001;
        }

        // Which of the following methods complete in a shorter time?

        void Foo1() const   // This one?
        {
            for (double x=m_dbLoopStart; x<=m_dbLoopStop; x+=m_dbLoopStep)
            {
                f(x);
            }
        }

        void Foo2() const   // Or, this one?
        {
            for (double x=m_dbLoopStart; x<=m_dbLoopStop; x+=m_dbLoopStep)
            {
                2.0 * x + 1.0;
            }
        }

    private:
        double m_dbLoopStart, m_dbLoopStop, m_dbLoopStep;

        inline static double f(double x)
        {
            return 2.0 * x + 1.0;
        }
};

Что из Foo1() и Foo2() завершится быстрее?


person hkBattousai    schedule 03.01.2012    source источник
comment
Если вообще есть какая-то разница, то вам нужен лучший компилятор.   -  person Mike Seymour    schedule 03.01.2012
comment
Оба они должны привести к очень похожей сборке (если не к одинаковой).   -  person Niklas B.    schedule 03.01.2012
comment
Единственное отличие состоит в том, что встроенная функция может обязательно не быть встроенной, тогда как при прямой вставке кода у компилятора нет выбора.   -  person Paul R    schedule 03.01.2012
comment
Так же быстро, как ручное копирование и вставка? Да (при условии, что компилятор действительно встроен)! Быстрее, чем вообще не встраивать? Это зависит!   -  person Christian Rau    schedule 03.01.2012


Ответы (4)


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

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

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

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

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

person Thomas Matthews    schedule 16.01.2012

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

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

person stefaanv    schedule 03.01.2012

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

Так что строго теоретически, это быстрее.

person WeaselFox    schedule 03.01.2012
comment
Опять же, у компилятора может быть веская причина не встраивать функцию. Например, если тело функции большое, компилятор может не встроить его из-за эффекта кэширования. Современные процессоры достаточно сложны, поэтому их характеристики производительности не всегда интуитивно понятны. На самом деле может быть быстрее не встраивать конкретную функцию. - person In silico; 03.01.2012
comment
@Insilico: Да, но в данном конкретном случае лучше встроить. - person Mooing Duck; 17.01.2012

Часто существуют небольшие семантические различия между вызовом встроенных функций с параметрами и простым использованием кода копирования/вставки или макросов #define. Например, рассмотрим макрос и функцию:

extern void some_extern_function(int x);
#define foo1(x) (some_extern_function((x)), some_extern_function((x)))
void inline foo2(int x) {some_extern_function(x); some_extern_function(x); }

Теперь предположим, что кто-то вызывает их:

  extern volatile int some_volatile_int;
  foo1(some_volatile_int);
  foo2(some_volatile_int);

В этом сценарии встроенная функция foo2 должна создать копию some_volatile_int, а затем передать эту копию обоим вызовам some_extern_function. Напротив, макрос должен загрузить some_volatile_int дважды. В зависимости от соглашений о вызовах один из подходов может быть быстрее другого.

person supercat    schedule 16.01.2012