Який код краще для оптимізації прогнозування галузей?


10

Враховуючи галузеве передбачення, а також ефект оптимізацій компілятора, який код має тенденцію до вищої ефективності?

Зауважте, що bRareExceptionPresent є нечастою умовою. Це не нормальний шлях логіки.

/* MOST COMMON path must branch around IF clause */

bool SomeFunction(bool bRareExceptionPresent)
{
  // abort before function
  if(bRareExceptionPresent)
  {
     return false;
  }    
  .. function primary body ..    
  return true;
}

/* MOST COMMON path does NOT branch */

bool SomeFunction(bool bRareExceptionPresent)
{
  if(!bRareExceptionPresent)
  {
    .. function primary body ..
  }
  else
  {
    return false;
  }
  return true;
}

9
Я збираюся тут вийти на кінцівку і сказати, що різниці немає.
Роберт Харві

7
Це, мабуть, залежить від конкретного процесора, який ви збираєте, оскільки вони мають різні конвеєрні конвеєри (слоти затримки проти не слот затримки). Час, який ви витратили на роздуми про це, швидше за все, набагато більше, ніж час, який заощадили під час роботи - спочатку профіліруйте, а потім оптимізуйте.

2
Це майже напевно передчасна мікрооптимізація.
Роберт Харві

2
@MichaelT Так, профілювання - це справді єдиний надійний спосіб дізнатися, що насправді відбувається з ефективністю коду для цілі, платформи, в її контексті. Однак мені було цікаво, чи взагалі один віддається перевазі.
діаста

1
@RobertHarvey: Це передчасна мікрооптимізація, за винятком випадків, коли виконуються обидві умови: (1) цикл називається мільярдами (а не мільйонами) разів; та (2) за іронією долі, коли корпус петлі крихітний з точки зору машинного коду. Умова № 2 означає, що частка часу, витраченого на накладні витрати, не є незначною порівняно з часом, витраченим на корисну роботу. Хороша новина полягає в тому, що зазвичай у таких ситуаціях, коли дотримані обидві умови, SIMD (векторизація), який за своєю природою є безгалузевим, вирішить усі питання щодо продуктивності.
rwong

Відповіді:


10

У сучасному світі це не має великого значення, якщо воно взагалі є.

Динамічне прогнозування гілок (про що думали десятиліттями (див . Аналіз навантажень системи динамічного прогнозування гілок), опублікований у 1996 році) є досить поширеним місцем.

Приклад цього можна знайти в процесорі ARM. З інформаційного центру Arm з прогнозування філії

Для підвищення точності прогнозування галузей використовується комбінація статичних та динамічних методик.

Тоді питання: "що таке динамічне прогнозування гілок в кронштейні?" Тривале читання прогнозування динамічної гілки показує, що вона використовує 2-бітну схему прогнозування (описану в статті), будує інформацію про те, чи гілка сильно або слабко взята чи не взята.

З часом (і я маю на увазі кілька проходів через цей блок), це накопичує інформацію про те, яким шляхом піде код.

Для статичного прогнозування він дивиться на те, як виглядає сам код і яким чином зроблено гілку на тесті - на попередню інструкцію або одну далі в коді:

Схема, що використовується в процесорі ARM1136JF-S, передбачає, що всі передові умовні гілки не взяті і всі відсталі гілки прийняті. Близько 65% усіх гілок передує достатньому циклу нерозгалуження, який можна повністю передбачити.

Як згадував Спаркі, це ґрунтується на розумінні, що циклі частіше, ніж ні, циклічно. Петля відгалужується назад (вона має гілку в кінці циклу, щоб перезапустити її вгорі) - зазвичай це робить.

Небезпека спробувати вгадати компілятор полягає в тому, що ви не знаєте, як цей код насправді збирається (і оптимізується). І здебільшого це не має значення. При динамічному прогнозуванні двічі через функцію він передбачить пропуск через оператор захисту для передчасного повернення. Якщо продуктивність двох промитих трубопроводів має вирішальне значення, варто потурбуватися про інші.

Час, необхідний для читання одного стилю над іншим, швидше за все, має велике значення - зробити код чистим, щоб людина міг його читати, оскільки компілятор буде робити чудово, незалежно від того, наскільки брудно чи ідеалізовано ви пишете код.


7
Відоме запитання про стартовий потік показало, що передбачення галузей має значення навіть сьогодні.
Флоріан Маргайн

3
@FlorianMargaine, хоча це має значення, але потрапляння в ситуацію, коли це дійсно має значення, вимагає розуміння того, що ви збираєтесь і як це працює (arm vs x86 vs mips ...). Введення коду, який намагається зробити цю мікрооптимізацію на початку, швидше за все працює з помилкових приміщень і не досягне бажаного ефекту.

Ну звичайно, не будемо цитувати ДК. Але я думаю, що це питання було явно в сенсі оптимізації, коли ви вже пройшли етап профілізації. :-)
Флоріан Маргайн

2
@MichaelT Приємна відповідь, і я дуже згоден з вашим висновком. Цей вид попереднього профілювання / абстрактної оптимізації, безумовно, може бути контрпродуктивним. Це в кінцевому підсумку - це здогадка, яка змушує приймати дизайнерські рішення з нераціональних причин. І все-таки мені
здалося


9

Я розумію, що перший раз, коли CPU стикається з відділенням, він передбачить (якщо він підтримується), що передні гілки не приймаються, а назад - гілки. Обґрунтуванням цього є те, що петлі (як правило, гілки назад) приймаються.

На деяких процесорах ви можете дати підказку в інструкції по збірці, який шлях є більш імовірним. Деталі цього втечі мені зараз.

Крім того, деякі компілятори C також підтримують статичне передбачення гілок, щоб ви могли сказати компілятору, яка гілка є більшою ймовірністю. У свою чергу він може реорганізувати створений код або скористатися модифікованими інструкціями, щоб скористатися цією інформацією (або навіть просто вилучити її з уваги).

__builtin_expect((long)!!(x), 1L)  /* GNU C to indicate that <x> will likely be TRUE */
__builtin_expect((long)!!(x), 0L)  /* GNU C to indicate that <x> will likely be FALSE */

Сподіваюсь, це допомагає.


3
"Я розумію, що перший раз, коли CPU стикається з філією, він передбачить (якщо підтримується), що передні гілки не будуть взяті, а зворотні гілки". Це дуже цікава думка. Чи є у вас докази того, що це дійсно реалізовано в загальних архітектурах?
блека

5
Прямо з пащі коня: передня гілка за замовчуванням не береться. За замовчуванням гілка за замовчуванням прийнята . І з тієї ж сторінки: "префікс 0x3E - статично передбачити гілку як зроблену".
MSalters

Чи є платформа агностичної прагми, яка рівноважна __builtin_expect?
MarcusJ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.