Когда “встроен” неэффективный? (в C)

Предполагая, что каждая пара class и section соответствует уникальной паре school и city, мы можем использовать groupby:

# create a dictionary of class and section with school and city
# here we assume that for each pair and class there's a row with both school and city
# if that's not the case, we can separate the two series 
school_city_dict = df[['class', 'section','school','city']].dropna().\
                     groupby(['class', 'section'])[['school','city']].\
                     max().to_dict()
# school_city_dict = {'school': {('I', 'A'): 'jghss', ('III', 'A'): 'gphss'},
#                     'city': {('I', 'A'): 'salem', ('III', 'A'): 'salem'}}

# set index, prepare for map function
df.set_index(['class','section'], inplace=True)

df.loc[:,'school'] = df.index.map(school_city_dict['school'])
df.loc[:,'city'] = df.index.map(school_city_dict['city'])

# reset index to the original
df.reset_index()
15
задан Community 23 May 2017 в 11:45
поделиться

12 ответов

inline делает две вещи:

  1. дает Вам освобождение от "одного правила определения" (см. ниже). Это всегда применяется.
  2. Дает компилятору подсказку для предотвращения вызова функции. Компилятор является бесплатным проигнорировать это.

1. Может быть очень полезным (например, поместить определение в заголовок, если короткий), даже если № 2 отключен.

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


[РЕДАКТИРОВАНИЕ: Полные Ссылки и соответствующий текст]

Две точки выше обоих следуют из стандарта ISO/ANSI (ISO/IEC 9899:1999(E), обычно известный как "C99").

В §6.9 "Внешнее Определение", абзац 5:

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

В то время как equalivalent определением в C++ является explictly, названный Одно правилом определения (ODR), это служит той же цели. Внешний облик (т.е. не "статичный", и таким образом локальный для единственной Единицы перевода - обычно единственный исходный файл) может только быть определен однажды только, если это не функция и встроенный.

В §6.7.4, "Функциональные Спецификаторы", встроенное ключевое слово определяется:

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

И (ненормативная) сноска, но предоставляет разъяснение:

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

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

(Весь акцент в кавычках из стандарта.)


РЕДАКТИРОВАНИЕ 2: Несколько примечаний:

  • Существуют различные ограничения на внешние подставляемые функции. У Вас не может быть статической переменной в функции, и Вы не можете сослаться на статические объекты/функции объема TU.
  • Просто замеченный это на VC ++ "целая оптимизация программы", которая является примером компилятора, делающего его собственную встроенную вещь, а не автора.
26
ответ дан 1 December 2019 в 00:05
поделиться

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

5
ответ дан 1 December 2019 в 00:05
поделиться

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

Это - еще один случай Преждевременной Оптимизации, о которой предупредил Knuth.

2
ответ дан 1 December 2019 в 00:05
поделиться

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

2
ответ дан 1 December 2019 в 00:05
поделиться

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

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

3
ответ дан 1 December 2019 в 00:05
поделиться

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

2
ответ дан 1 December 2019 в 00:05
поделиться

Встроенный неэффективно, когда Вы используете указатель на функцию.

4
ответ дан 1 December 2019 в 00:05
поделиться

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

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

5
ответ дан 1 December 2019 в 00:05
поделиться

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

Можно сказать компилятору о желании чего-то встроенного.. до компилятора, чтобы сделать так. Существует нет - встроенная силой опция, которую я знаю, которых компилятор не может проигнорировать. Именно поэтому необходимо ли посмотреть на ассемблерный вывод и видеть ли, встраивал ли компилятор на самом деле функцию, в противном случае почему нет? Во многих компиляторах просто тихо говорится 'отвалите!' в этом отношении.

итак, если:

статическое встроенное неподписанное международное нечто (символ константы *панель)

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

Между тем, при создании чего-то (или попытке сделать что-то) встроенным, выполнение так на самом деле выравнивает по ширине чрезмерное увеличение размера? Вы действительно хотите ту функцию, развернул каждый раз его названный? Действительно ли переход является настолько дорогостоящим?, Ваш компилятор является обычно корректными 9/10 временами, проверьте промежуточный вывод (или дампы asm).

1
ответ дан 1 December 2019 в 00:05
поделиться
  1. inline действия как подсказка только.
  2. Добавленный только совсем недавно. Так работает только с последними стандартными совместимыми компиляторами.
1
ответ дан 1 December 2019 в 00:05
поделиться

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

2
ответ дан 1 December 2019 в 00:05
поделиться

Пример для иллюстрирования преимуществ встроенных. sinCos.h:

int16 sinLUT[ TWO_PI ]; 

static inline int16_t cos_LUT( int16_t x ) {
    return sin_LUT( x + PI_OVER_TWO )
}

static inline int16_t sin_LUT( int16_t x ) {
    return sinLUT[(uint16_t)x];
}

При выполнении некоторого тяжелого перемалывания чисел и Вы не хотите тратить впустую циклы на вычисления sin/cos, Вы заменяете sin/cos LUT.

Когда Вы скомпилируете без встроенного, компилятор не оптимизирует цикл, и вывод .asm покажет что-то вроде:

;*----------------------------------------------------------------------------*
;*   SOFTWARE PIPELINE INFORMATION
;*      Disqualified loop: Loop contains a call
;*----------------------------------------------------------------------------*

Когда Вы компилируете со встроенным, компилятор имеет знание о том, что происходит в цикле и оптимизирует, потому что это знает точно, что происходит.

Вывод .asm будет иметь оптимизированный "конвейерный" цикл (т.е. он попытается полностью использовать ALUs всего процессора и попытаться сохранить конвейер процессора полным без NOPS).


В этом конкретном случае я смог увеличить свою производительность приблизительно 2X или 4X, который получил меня в том, в чем я нуждался в течение своего оперативного крайнего срока.


p.s. Я работал над процессором фиксированной точки..., и любые операции с плавающей точкой как sin/cos уничтожили мою производительность.

5
ответ дан 1 December 2019 в 00:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: