Вопрос

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

Ясно, что когда архиватор / компоновщик создает библиотеку из объектных файлов или связывает их в исполняемый файл, даже простая оптимизация наказывается. В приведенном ниже примере тривиальное встраивание стоит 1,8% в производительности, когда выполняется компоновщиком вместо компилятора. Кажется, что технология компилятора должна быть достаточно продвинутой, чтобы справляться с довольно распространенными ситуациями, подобными этой, но этого не происходит.

Вот простой пример использования Visual Studio 2008:

#include <cstdlib>
#include <iostream>
#include <boost/timer.hpp>

using namespace std;

int foo(int x);
int foo2(int x) { return x++; }

int main(int argc, char** argv)
{
  boost::timer t;

  t.restart();
  for (int i=0; i<atoi(argv[1]); i++)
    foo (i);
  cout << "time : " << t.elapsed() << endl;

  t.restart();
  for (int i=0; i<atoi(argv[1]); i++)
    foo2 (i);
  cout << "time : " << t.elapsed() << endl;
}

foo.cpp

int foo (int x) { return x++; }

Результаты выполнения: увеличение производительности на 1,8% при использовании связанного foo вместо встроенного foo2 .

$ ./release/testlink.exe  100000000
time : 13.375
time : 13.14

И да, флаги оптимизации компоновщика (/ LTCG) включены.

Это было полезно?

Решение

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

Кстати, извините, я отвлек ваш оригинальный вопрос в обсуждение ltcg. Теперь я понимаю, что ваш вопрос был немного другим, больше связан с возможной / доступной статической оптимизацией времени соединения и времени компиляции.

Другие советы

Ваш коллега устарел. Технология работает здесь с 2003 года (на компиляторе MS C ++): / LTCG . Генерация временного кода ссылки имеет дело именно с этой проблемой. Из того, что я знаю, GCC имеет эту функцию на радаре для компилятора следующего поколения.

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

  

Встраивание & # 8211; Например, если есть   существует функция А, которая часто   вызывает функцию B, а функция B   относительно маленький, затем с профилем   оптимизации будут встроены функции B   в функции А.

     

Спекуляция виртуальными вызовами & # 8211; Если   виртуальный звонок или другой звонок через   указатель на функцию, часто предназначается для   определенная функция, управляемая профилем   оптимизация может вставить   условно исполненный прямой вызов   часто целевая функция, и   прямой вызов может быть встроенным.

     

Распределение регистра & # 8211; Оптимизация с   данные профиля приводят к лучшему   распределение регистров.

     

Оптимизация базовых блоков & # 8211; Базовый блок   оптимизация позволяет обычно выполнять   основные блоки, которые временно исполняются   в данном кадре, который будет помещен в   тот же набор страниц (местность). это   минимизирует количество используемых страниц,   таким образом минимизируя накладные расходы памяти.

     

Оптимизация размера / скорости & # 8211; функции   где программа тратит много времени   можно оптимизировать по скорости.

     

Расположение функций & # 8211; На основании вызова   график и профилированный абонент / абонент   поведение, функции, которые имеют тенденцию быть   вдоль того же пути выполнения   размещены в том же разделе.

     

Условная оптимизация ветвей & # 8211; С   датчики значения, профильные   оптимизации могут найти, если данный   значение в выражении switch используется   чаще других ценностей. это   значение может быть извлечено из   сменить заявление. То же самое можно сделать   с инструкциями if / else где   оптимизатор может заказать if / else так   что блок if или else является   ставится на первое место в зависимости от того, какой блок   чаще правда.

     

Разделение мертвого кода & # 8211; Код, который   не вызывается во время профилирования перемещается   в специальный раздел, который добавляется   до конца набора разделов.   Это эффективно держит этот раздел   из часто используемых страниц.

     

Разделение кода EH & # 8211; Код EH,   будучи в исключительном порядке, может   часто перемещать в отдельный раздел   когда профильная оптимизация может   определить, что происходят исключения   только на исключительных условиях.

     

Встроенные функции памяти & # 8211; Расширение   внутренние можно решить лучше, если это   можно определить, является ли внутренняя   звонил часто. Внутренняя банка   также оптимизировать на основе блока   размер ходов или копий.

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

Однако вы спросили об этом два года назад, и я свидетельствую, что с тех пор многое изменилось (по крайней мере, с g ++). Например, девиртуализация намного надежнее.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top