Понимание встраивания GCC - PullRequest
       22

Понимание встраивания GCC

0 голосов
/ 23 сентября 2018

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

Я не совсем понимаю, какВстроенный код gcc, но для моего конкретного случая я получаю скорость выполнения, эквивалентную рукописному коду в gcc 8.2.1, используя следующие параметры:

-std=c++17 -Winline 
-Ofast -march=native -DNDEBUG 
-finline-limit=100000 --param large-function-insns=10000 --param large-stack-frame-growth=1000 
--param inline-unit-growth=1000 --param early-inlining-insns=150 --param max-early-inliner-iterations=1000
-fopenmp -fPIC

Без встроенных параметров моя программав 3 раза медленнее.Я бы ожидал более простой вариант, чтобы сказать компилятору: «Поверьте мне, когда я говорю inline, вы ДОЛЖНЫ включить его».Есть ли такая опция компилятора?

Примечания:

  • Некоторые подробности о коде: есть 3 вложенных цикла для циклов, третий - SIMD, каждая итерация вычисляет сложный фиксированныйразмер линейной алгебры.Сам материал линейной алгебры не SIMD (так как цикл выше).Большая часть абстракции имеет дело с многомерными массивами и плотной линейной алгеброй (для которой нужны шаблоны выражений).
  • Все функции, которые я хочу встроить, определены в модуле компиляции.У меня нет ни рекурсивных, ни виртуальных функций, я не выкидываю исключения.Мои функции являются constexpr, а не встроенными, но constexpr подразумевает неявное inline.Сторонних библиотечных вызовов нет (все вызовы - математические функции, такие как std :: sqrt).Параллелизма нет, кроме SIMD.
  • В начале рефакторинга, когда еще мало функций для встраивания, проблем не возникает.Но по мере того, как я добавляю все больше и больше встроенных функций для абстрагирования кода, компилятор начинает бороться со встраиванием (и, похоже, с другими вещами, такими как SROA).Я не определяю функции ради этого, но мне нужно определить их много, чтобы они были общими.
  • Я работаю над реалистичным тестом для измерения производительности.Это не микро-эталон, поэтому я уверен, что я измеряю то, что я действительно хочу измерить.
  • Если функция в моем горячем цикле не встроена, я измеряю снижение производительности x2 (конечно, из-затот факт, что это предотвращает много дальнейших оптимизаций, в частности, с векторизацией и SROA)
  • Я начал работать над этим с компилятором intel, который мучительно медленен и глючит в коде шаблона.Ведение рукописного исполнения было очень сложным, поэтому я переключился на gcc.

Теперь я заметил странное поведение:

  • В некоторых случаях не используется -fPIC madegcc выдает -Winline предупреждение о том, что оно не встроено.Я не понимаю связи между -fPIC и встраиванием вообще.
  • Я не понимаю необходимости указывать ранние проходы встраивания для gcc.Я бы подумал, что --param early-inlining-insns=150 следует использовать только для оптимизации времени компиляции, а не кода, сгенерированного gcc.Но дело в том, что если значение 50, я получаю тихий плохой встраивание (нет предупреждения от gcc), а если значение 1000, я также получаю плохое встраивание (gcc предупреждает меня на этот раз).Что происходит?
  • Я немного неохотно использую __attribute__((always_inline)), потому что это было бы уродливо делать для каждой маленькой функции, но мне кажется, что даже с этим атрибутом gcc иногда не включаетсяфункция.Действительно ли gcc всегда встроенные функции с этим атрибутом?

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

...