Какова стоимость вызова функции?

По сравнению с

  • Простой доступ к памяти
  • Доступ к диску
  • Доступ к памяти на другом компьютере (в той же сети)
  • Доступ к диску на другом компьютере (в той же сети)

в С++ на окнах.

Ответ 1

относительные тайминги (не должны быть отключены более чем в 100 раз;)

  • доступ к памяти в кеше = 1
  • вызов функции/возврат в кеш = 2
  • доступ к памяти из кэша = 10.. 300
  • доступ к диску = 1000.. 1e8 (амортизируется зависит от количества переданных байтов)
    • в зависимости от времени поиска
    • сама передача может быть довольно быстрой.
    • включает как минимум несколько тысяч операций, так как порог пользователя/системы должен пересекаться, по крайней мере, дважды; запрос ввода-вывода должен быть запланирован, результат должен быть записан обратно; возможно выделение буферов...
  • сетевые вызовы = 1000.. 1e9 (амортизация зависит от количества переданных байтов)
    • тот же аргумент, что и с диском i/o
    • необработанная скорость передачи может быть довольно высокой, но некоторые процессы на другом компьютере должны выполнять фактическую работу.

Ответ 2

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

По сравнению со временем

Функциональный вызов ~ простой доступ к памяти
Вызов функции < Доступ к диску
Вызов функции < доступ к памяти на другом компьютере
Вызов функции < диск на другом компьютере

Ответ 3

По сравнению с простым доступом к памяти - немного больше, практически неважно.

По сравнению со всеми остальными перечисленными - на порядок меньше.

Это должно быть справедливо для любого языка на любой ОС.

Ответ 4

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

Во всем остальном вызов функции - это много (много) величин быстрее.

Ответ 5

Трудно ответить, потому что есть много факторов.

Прежде всего, "Простой доступ к памяти" не прост. Поскольку на современных тактовых частотах CPU может добавить два числа быстрее, чем получить номер с одной стороны чипа на другой (скорость света - это не просто хорошая идея, это ЗАКОН)

Итак, называется ли функция внутри кэша памяти процессора? Доступ к памяти вы тоже сравниваете?

Затем мы вызываем вызов функции, чтобы очистить конвейер команд CPU, который будет влиять на скорость недетерминированным способом.

Ответ 6

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

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

Также обратите внимание, что "простой" доступ к памяти иногда не является - если ОС должна принести страницу с диска, тогда у вас есть длинное ожидание на ваших руках. То же самое было бы верно, если вы перейдете на код, который в настоящее время выгружается на диск.

Если основной вопрос: "Когда мне нужно оптимизировать мой код, чтобы свести к минимуму общее количество вызовов функций?", тогда ответ "очень близок к никогда".

Ответ 7

В Google эта ссылка очень много. Для справки в будущем я провел короткую программу на С# по стоимости вызова функции, и ответ: "примерно в шесть раз больше стоимости встроенного". Ниже приведены подробности, см.//Выход внизу. ОБНОВЛЕНИЕ: Чтобы лучше сравнить яблоки с яблоками, я изменил Class1.Method, чтобы вернуть 'void', так: public void Method1() {//return 0; }
Тем не менее, inline быстрее на 2x: inline (avg): 610 мс; вызов функции (avg): 1380 мс. Поэтому ответ, обновленный, "примерно два раза".

с использованием System; используя System.Collections.Generic; используя System.Linq; используя System.Text; используя System.Diagnostics;

пространство имен FunctionCallCost {   классная программа   {       static void Main (string [] args)       {           Debug.WriteLine( "STOP1" );           int iMax = 100000000;//100M           DateTime funcCall1 = DateTime.Now;           Секундомер sw = секундомер .StartNew();

        for (int i = 0; i < iMax; i++)
        {
            //gives about 5.94 seconds to do a billion loops, 
          // or 0.594 for 100M, about 6 times faster than
            //the method call.
        }

        sw.Stop(); 

        long iE = sw.ElapsedMilliseconds;

        Debug.WriteLine("elapsed time of main function (ms) is: " + iE.ToString());

        Debug.WriteLine("stop2");

        Class1 myClass1 = new Class1();
        Stopwatch sw2 = Stopwatch.StartNew();
        int dummyI;
        for (int ie = 0; ie < iMax; ie++)
        {
          dummyI =  myClass1.Method1();
        }
        sw2.Stop(); 

        long iE2 = sw2.ElapsedMilliseconds;

        Debug.WriteLine("elapsed time of helper class function (ms) is: " + iE2.ToString());

        Debug.WriteLine("Hi3");


    }
}

//Класс 1 здесь использование системы; используя System.Collections.Generic; используя System.Linq; используя System.Text;

пространство имен FunctionCallCost {   класс Class1   {

    public Class1()
    {
    }

    public int Method1 ()
    {
        return 0;
    }
}

}

//Выход: STOP1 прошедшее время основной функции (мс): 595 STOP2 прошедшее время функции вспомогательного класса (мс): 3780

STOP1 прошедшее время основной функции (мс): 592 STOP2 прошедшее время функции вспомогательного класса (ms): 4042

STOP1 прошедшее время основной функции (мс): 626 STOP2 прошедшее время функции вспомогательного класса (мс): 3755

Ответ 8

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

Ответ 9

Не забывайте, что С++ имеет виртуальные вызовы (значительно дороже, около x10), а на WIndows вы можете ожидать VS к встроенным вызовам (0 по определению, так как в двоичном коде нет вызова)

Ответ 10

В зависимости от того, что делает эта функция, он будет падать 2-м в вашем списке, если бы он выполнял логику с объектами в памяти. Далее по списку, если он включает в себя доступ к диску/сети.

Ответ 11

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

Ответ 12

Если функция включена во время компиляции, стоимость функции становится эквивалентной 0.

0, конечно, то, что вы получили бы, не имея вызова функции, т.е. самостоятельно вложил его.

Это, конечно, звучит чрезмерно очевидно, когда я пишу это так.

Ответ 13

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

Ответ 14

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

Итак, говоря относительно:

  • Вызов функции > Простой доступ к памяти.
  • Вызов функции < < Доступ к диску - по сравнению с памятью он может быть в сотни раз дороже.
  • Вызов функции < < Доступ к памяти на другом компьютере - пропускная способность сети и протокол - великие убийцы времени здесь.
  • Вызов функции < < < Доступ к диску на другом компьютере - все вышеперечисленное и многое другое:)

Ответ 15

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

Но вызов можно избежать, если компилятор с встроенной оптимизацией (для компилятора (ов) GCC и не только он активируется при использовании уровня 3 оптимизации (-O3)).