Как выравнивание адресов цикла влияет на скорость Intel x86_64?

Я наблюдаю снижение производительности на 15% для одного и того же кода C ++, скомпилированного с точно такими же машинными инструкциями, но расположенного на по-разному выровненных адресах. Когда мой крошечный основной цикл начинается с 0x415220, он быстрее, чем когда он находится с 0x415250. Я использую это на Intel Core2 Duo. Я использую gcc 4.4.5 на x86_64 Ubuntu.

Может ли кто-нибудь объяснить причину замедления и как я могу заставить gcc оптимально выровнять цикл?

Вот разборка для обоих случаев с аннотацией профилировщика:

  415220 576      12.56% |XXXXXXXXXXXXXX       48 c1 eb 08           shr    $0x8,%rbx
  415224 110       2.40% |XX                   0f b6 c3              movzbl %bl,%eax
  415227           0.00% |                     41 0f b6 04 00        movzbl (%r8,%rax,1),%eax
  41522c 40        0.87% |                     48 8b 04 c1           mov    (%rcx,%rax,8),%rax
  415230 806      17.58% |XXXXXXXXXXXXXXXXXXX  4c 63 f8              movslq %eax,%r15
  415233 186       4.06% |XXXX                 48 c1 e8 20           shr    $0x20,%rax
  415237 102       2.22% |XX                   4c 01 f9              add    %r15,%rcx
  41523a 414       9.03% |XXXXXXXXXX           a8 0f                 test   $0xf,%al
  41523c 680      14.83% |XXXXXXXXXXXXXXXX     74 45                 je     415283 ::Run(char const*, char const*)+0x4b3>
  41523e           0.00% |                     41 89 c7              mov    %eax,%r15d
  415241           0.00% |                     41 83 e7 01           and    $0x1,%r15d
  415245           0.00% |                     41 83 ff 01           cmp    $0x1,%r15d
  415249           0.00% |                     41 89 c7              mov    %eax,%r15d
  415250 679      13.05% |XXXXXXXXXXXXXXXX     48 c1 eb 08           shr    $0x8,%rbx
  415254 124       2.38% |XX                   0f b6 c3              movzbl %bl,%eax
  415257           0.00% |                     41 0f b6 04 00        movzbl (%r8,%rax,1),%eax
  41525c 43        0.83% |X                    48 8b 04 c1           mov    (%rcx,%rax,8),%rax
  415260 828      15.91% |XXXXXXXXXXXXXXXXXXX  4c 63 f8              movslq %eax,%r15
  415263 388       7.46% |XXXXXXXXX            48 c1 e8 20           shr    $0x20,%rax
  415267 141       2.71% |XXX                  4c 01 f9              add    %r15,%rcx
  41526a 634      12.18% |XXXXXXXXXXXXXXX      a8 0f                 test   $0xf,%al
  41526c 749      14.39% |XXXXXXXXXXXXXXXXXX   74 45                 je     4152b3 ::Run(char const*, char const*)+0x4c3>
  41526e           0.00% |                     41 89 c7              mov    %eax,%r15d
  415271           0.00% |                     41 83 e7 01           and    $0x1,%r15d
  415275           0.00% |                     41 83 ff 01           cmp    $0x1,%r15d
  415279           0.00% |                     41 89 c7              mov    %eax,%r15d

person Alexander Gololobov    schedule 25.12.2010    source источник
comment
используйте параметр --march = XXX, если арка такая же, как и машина, на которой вы можете компилировать: -march = native Короче говоря, дайте компилятору как можно больше информации о целевой платформе, также выполните pgo, сначала компилируйте с помощью -pg -fprofile-generate, затем запустите программу, затем снова перекомпилируйте с помощью -fprofile-use   -  person    schedule 26.12.2010


Ответы (2)


Gcc имеет параметр -falign-loops = n, где n - это максимальное количество байтов, которое нужно пропустить, если он не указан, будет использоваться машина по умолчанию. Gcc автоматически включает это на уровнях оптимизации -O2 и -O3.

person ismail    schedule 25.12.2010

На процессорах Intel с функцией обнаружения потока циклов выравнивание кода тела цикла может повысить эффективность, особенно при нормальных уровнях развертывания. Выравнивание платит штраф при первом входе в петлю сверху. Вы не показали код там, где в выровненном регистре были бы несколько бессмысленные прославленные инструкции no-op. gcc обычно использует условное выравнивание, которое применяет выравнивание только в тех случаях, когда требуется ограниченное количество отступов. Когда я однажды рассмотрел это, параметры, влияющие на это поведение, не казались очень эффективными. Как сказал Александр, важно установить значение для -march или -mtune, чтобы gcc мог использовать соответствующие настройки выравнивания. Все компиляторы, которые я использую, в некоторых случаях не могут выровнять тело цикла, и, похоже, это не контролируется.

person tim18    schedule 10.02.2016
comment
Я думал, что буфер циклов на Nehalem, а позже сделал выравнивание практически несущественным для циклов, которые помещались в него. Никакого декодирования не происходит, и он просто воспроизводит до 28 мопов, которые он держит. Разве он не может удерживать столько мопов, если есть границы выравнивания? Или выдает менее 4 мопов за несколько циклов? Я понял это из документа по микроархитектуре Agner Fog. Конечно, этот вопрос касается Core2, где буфер цикла на этапе предкодирования (определение длины insn) буферизация до 64 байт машинного кода x86. Вы это имели в виду? - person Peter Cordes; 10.02.2016
comment
Насколько я понимаю, получение полной выгоды от декодированного буфера uops зависит от выравнивания кода. Таким образом, может происходить взаимодействие с количеством разворачивания. В последних моделях буфер достаточно велик в моих тестах, чтобы вместить развертку на 4 с выравниванием, так как ограниченное развертывание все еще может быть полезно для больших циклов, которые выходят за пределы ограничения размера буфера. Есть и другие факторы, такие как ограничение количества активных траекторий с условным переходом. gcc обычно использует .p2align 4,, 10. - person tim18; 11.02.2016