Оптимизация времени соединения и встраивание - PullRequest
15 голосов
/ 13 августа 2011

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

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

Вопрос заключается в следующем: делает ли оптимизация во время соединения (например, в GCC) ручное встраивание, например, объявляет в C99 функцию «встроенной» и обеспечивает реализацию, устаревшую?Правда ли, что нам не нужно учитывать встроенные функции для большинства функций самим?Как насчет функций, которые всегда извлекают выгоду из встраивания, например, deg_to_rad (x)?

Уточнение: Я не думаю о функциях, которые находятся в одном переводе.unit в любом случае, но о функциях, которые должны логически находиться в разных единицах перевода.

Обновление: Я часто встречал оппозицию против "inline", и это было предложено устаревшим.Лично, однако, я часто вижу явно встроенные функции: как функции, определенные в теле класса.

Ответы [ 5 ]

11 голосов
/ 13 августа 2011

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

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

Если производительность является вашей конечной целью, и вы действительно знаете, что делаете, и действительно проводите тщательный анализ своего кода, то на самом деле нужен способ указать компилятору встроенный или не встроенный при каждом вызове не подсказка для каждой функции. На практике я справился с этим, используя специфичные для компилятора подсказки типа «force_no_inline» для случаев, которые я не хочу вставлять, и отдельную копию «force_inline» (или макрос в редких случаях, когда это не удается) функции, когда я хочу, чтобы она была встроенной , Если кто-нибудь знает, как сделать это более понятным способом с помощью специальных подсказок компилятора (для любых компиляторов C / C ++), пожалуйста, дайте мне знать.

Чтобы конкретно адресовать ваши очки:

1.Код становится менее кратким и несколько менее понятным.

Как правило, нет - это просто подсказка для ключевого слова, которая управляет тем, как оно встроено. Однако, если вы прыгаете через обручи, как я описал в предыдущем абзаце, тогда да.

2. Иногда встраивание может значительно увеличить производительность во время выполнения.

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

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

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

3 голосов
/ 13 августа 2011

Вопрос заключается в следующем: выполняет ли оптимизация во время соединения (например, в GCC) ручное включение, например, объявление в C99 функции «inline» и обеспечение реализации, устарело?

Эта статья может показаться "Да:"

Задумайтесь на минуту: что превращает функцию в хорошего кандидата на встраивание? Помимо фактора размера, оптимизатор должен знать, как часто эта функция вызывается, откуда она вызывается, сколько других функции в программе являются подходящими кандидатами для встраивания и - хотите верьте, хотите нет - вызывается ли эта функция. Оптимизация (т.е. вставка) функция, которая не вызывается ни разу, является пустой тратой время и ресурсы. Но как оптимизатор может знать, что функция никогда не звонил? Ну, это не может. Если он не отсканировал весь программа. Именно здесь [оптимизация времени соединения] становится решающей.

1 голос
/ 13 августа 2011

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

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

0 голосов
/ 13 августа 2011
  1. Я не думаю, что встроенное ключевое слово влияет на удобство обслуживания, и лишь краткость.(мнение)
  2. Иногда inline может снизить производительность во время выполнения: http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.3
  3. Компиляторы достаточно умны в отношении вставки, я слышал, что Visual Studio почти полностью игнорирует их и решает встроить сам.

does link-time optimization render manual inlining, obsolete? Вовсе нет, оптимизатор, который делает встроенное ключевое слово почти устаревшим, начинает работать раньше, чем время соединения.

0 голосов
/ 13 августа 2011

Пункт 33 - Скотт Майерс - 2-е издание - Эффективные C ++ приходят на ум.

Вы должны иметь в виду ключевое слово static в строке! Теперь есть гнездо шершней!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...