[GCC] Два лица inline
От: Tilir Россия http://tilir.livejournal.com
Дата: 15.01.13 07:03
Оценка: 137 (21)
Hi,

Не могу не поделиться прекрасным. Итак исходные данные -- ваяем компилятор GCC (бэкенд к нему). От пользователя пришла проблема, схематично изображённая на рисунке ниже:



есть код A, в котором функция foo() проинлайнена в bar(). Присоединяем к нему код B, который ни к одной из функций не имеет никакого отношения и foo() перестаёт инлайниться. И код A и код B собирались с LTO. Была задача определить почему так произошло, виноват в этом наш бэкенд или это фишка компилятора как такового.

Расковыряв механизм IPA в GCC, я обнаружил там обычную priority queue, куда складываются все функции-кандидаты на инлайн с эвристическими приоритетами. При этом каждый ltrans-модуль имеет ограничение на то, на сколько он может вырасти при инлайне. Как только он вырос "вот на столько", инлайн прекращается. Из-за добавленного кода B, функция foo() отодвигалась по очереди слишком далеко и инлайн прекращался раньше чем очередь доходила до неё. Пользователю я порекомендовал подать в командную строку GCC параметр inline-unit-growth побольше чем дефолтный:

--param inline-unit-growth=60


И это решило проблему.

Через некоторое время, где-то два месяца, ко мне обратился другой пользователь, у которого был принципиально другой код, но очень похожая проблема, схематично изображённая на рисунке 2:



Есть код A+B, в котором функция foo() проинлайнена в bar(). Удаляем из него код B, и функция foo перестаёт инлайниться. Код B не имеет никакого отношения ни к foo, ни к bar, он просто лежит рядом. И код A и код B собирались с LTO.

Этому пользователю я предложил то же самое решение (увеличить --param inline-unit-growth по сравнению с дефолтными 60%) и оно ему помогло.

Кто-нибудь попробует догадаться почему?






А ответ крайне прост -- lto в GCC бьёт код на фиксированное количество ltrans модулей. Для кода A+B эти модули получались достаточно большими и в 60% от них попадал инлайн foo. После того как код B убрали, ltrans-модули стали меньше и инлайн foo перестал попадать в ограничение на рост модуля.

---
With best regards, Konstantin
Re: [GCC] Два лица inline
От: Pavel Dvorkin Россия  
Дата: 16.01.13 09:47
Оценка:
Здравствуйте, Tilir, Вы писали:

А это не поможет убрать двуличие ?

http://gcc.gnu.org/ml/gcc-help/2007-01/msg00051.html
With best regards
Pavel Dvorkin
Re[2]: [GCC] Два лица inline
От: Tilir Россия http://tilir.livejournal.com
Дата: 16.01.13 13:27
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А это не поможет убрать двуличие ?

PD>http://gcc.gnu.org/ml/gcc-help/2007-01/msg00051.html

Nope. Атрибут always_inline не улучшает инлайнинг. Он просто:
1) Включает инлайнинг для функции на которой висит даже для O0 (как вы понимаете там не шла речь об O0).
2) Выдаёт предупреждение если инлайнинг невозможен (если Werror=attributes, то error).

Несколько перспективнее gnu_inline, но это кривой хак. И в этих случаях тоже не сработал бы.
Re: [GCC] Два лица inline
От: fdn721  
Дата: 21.01.13 01:44
Оценка:
Здравствуйте, Tilir, Вы писали:

А где-то в стандарте написано, что функция объявленная как inline, обязательно будет встроена?
Re[2]: [GCC] Два лица inline
От: watch-maker  
Дата: 21.01.13 08:35
Оценка:
Здравствуйте, fdn721, Вы писали:

F>А где-то в стандарте написано, что функция объявленная как inline, обязательно будет встроена?


Нет, конечно. Но причём тут стандарт?
Re[3]: [GCC] Два лица inline
От: BulatZiganshin  
Дата: 21.01.13 16:04
Оценка:
Здравствуйте, watch-maker, Вы писали:

WM>Нет, конечно. Но причём тут стандарт?


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

ps: у меня есть программа с 128 вариантами кода, генерящимися по темплейтам. для того чтобы весь код проинлайнился, приходится задавать unit-growth=999, итого выходит аж мегабайт кода
Люди, я люблю вас! Будьте бдительны!!!
Re: [GCC] Два лица inline
От: MrUnknown2012  
Дата: 22.01.13 23:10
Оценка:
По стандарту inline — это скорее рекомендация компилятору, а не обязательное требование...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.