Чому порівняння настільки дорогі на GPU?


10

Намагаючись покращити продуктивність мого класу виявлення зіткнень, я виявив, що ~ 80% часу, витраченого на gpu, він витратив на умови if / else, просто намагаючись з'ясувати межі для відра, через який він повинен пройти цикл.

Точніше:

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

  2. Потім він перетворює вершини в цілі точки сітки (в даний час 8x8x8) і перетворює їх у трикутні межі на цій сітці

  3. Щоб перетворити 3 точки в межі, він знаходить min / max кожного виміру серед кожної з точок

Оскільки в мові програмування, яку я використовую, відсутня властива minmax, я зробив її сам, виглядає так:

procedure MinMax(a, b, c):
   local min, max

   if a > b:
      max = a
      min = b
   else:
      max = b
      min = a
   if c > max:
      max = c
   else:
      if c < min:
         min = c

   return (min, max)

Таким чином, в середньому це повинно бути 2,5 * 3 * 3 = 22,5 порівняння, що закінчується їжею набагато більше часу, ніж фактичні тести на перетину трикутника - краю (приблизно 100 * 11-50 інструкцій).

Насправді я виявив, що попередній обчислення необхідних відро на процесорі (однопотокова, без векторизації), складання їх у подання gpu разом із визначенням відра і надання gpu робити ~ 4 додаткових читання на один потік було в 6 разів швидше, ніж спроба щоб вияснити межі на місці. (зауважте, що вони перераховуються перед кожним виконанням, оскільки я маю справу з динамічними сітками)

То чому порівняння настільки жахливо повільне на gpu?


2
Ваше запитання стосується виконання на рівні інструкцій певного коду на певному типі обладнання. Мені це звучить набагато більше як питання програмування, ніж питання інформатики.
Девід Річербі

7
Я здогадуюсь , що порівняння не є дорогими, а галузями. Якщо компілятор не використовує передбачення (або GPU не надає такого), будуть використовуватися гілки, що спричиняють "потокове" розгортання (оскільки графічні процесори орієнтовані на SIMD). Перетворення умови на маску та використання маски для синтезу умовних рухів / свопів може бути розумною альтернативою.
Пол А. Клейтон,

1
@DavidRicherby Я не впевнений, що це саме конкретне. Хіба це питання не стосується жодної архітектури SIMD?
kasperd

1
@DavidRicherby: причина, коли ми навчаємо арку комп у відділах CS, полягає в тому, що арка comp впливає на алгоритми, які ви вибираєте. SIMD-архітектури можуть створювати високу пропускну здатність, лише якщо ви можете зрозуміти, як написати програму без вкладених гілок.
Мандрівна логіка

2
Як відповідь Wandering Logic відповідає менш очевидним чином, GPU працюють, припускаючи, що багато "потоків" знаходяться в одній інструкції одночасно. Тож GPU, грубо кажучи, беруть кожну гілку, а не лише справжні гілки. Ось чому GPU використовує той факт, що сусіди зазвичай беруть однакові гілки; а продуктивність жахлива, коли це неправда.
Роб

Відповіді:


10

GPU - це архітектура SIMD. У архітектурах SIMD кожна інструкція повинна бути виконана для кожного елемента, який ви обробляєте. (З цього правила є виняток, але це рідко допомагає).

Отже, у вашому MinMaxрозпорядженні не тільки кожен виклик повинен отримати всі три інструкції гілки (навіть якщо в середньому оцінюється лише 2,5), але і кожен оператор призначення також займає цикл (навіть якщо він насправді не "виконується" ).

Ця проблема іноді називається розбіжністю ниток . Якщо ваша машина має щось на кшталт 32 смуг виконання SIMD, вона все одно матиме лише один блок отримання. (Тут термін "потік" в основному означає "смуга виконання SIMD".) Отже, внутрішньо у кожній смузі виконання SIMD є біт "Я ввімкнено / вимкнено", і гілки насправді просто маніпулюють цим бітом. (Виняток полягає в тому, що в точці, коли кожна смужка SIMD стає відключеною, блок вибору, як правило, переходить безпосередньо до пункту "else".)

Отже, у вашому коді виконується кожна смужка виконання SIMD:

compare (a > b)
assign (max = a if a>b)
assign (min = b if a>b)
assign (max = b if not(a>b))
assign (min = a if not(a>b))
compare (c > max)
assign (max = c if c>max)
compare (c < min if not(c>max))
assign (min = c if not(c>max) and c<min)

Може статися так, що на деяких графічних процесорах ця конверсія умовних умов у прогнозування відбувається повільніше, якщо GPU робить це сам. Як вказував @ PaulA.Clayton, якщо у вашій мові програмування та архітектурі передбачена умовна операція переміщення (особливо одна із форм if (c) x = y else x = z), ви могли б зробити краще. (Але, напевно, не набагато краще).

Крім того, розміщення c < minумовного всередині одиниці elseне c > maxє зайвим. Це, безумовно, нічого не економить, і (враховуючи, що GPU повинен автоматично перетворити його на передбачення), насправді може шкодити, щоб він вклався у двох різних умовах.


2
(Вибачте, якщо будь-яка частина цього неясна, я намагаюся отримати відповідь, перш ніж теоретики закриють питання як поза темою.)
Блукаюча логіка

Докладніше про основи: http.developer.nvidia.com/GPUGems2/gpugems2_chapter34.html А для останніх способів вирішення: eecis.udel.edu/~cavazos/cisc879/papers/a3-han.pdf
Fizz

Це тематично в тому сенсі, що деякі алгоритми неможливо просунути через паралелізм SIMD. (тобто: Work, Span і т. д. для більш теоретичного лікування того, чому)
Rob 24

1
Ось ще одна лекція про основи розбіжностей people.maths.ox.ac.uk/gilesm/cuda/lecs/lec3-2x2.pdf З цього зауважте, що проблема (у Nvidia так чи інакше) є лише за основу. Код, що працює на різних основах, може щасливо розходитися. І ще один документ, що пропонує метод його уникнення: hal.inria.fr/file/index/docid/649650/filename/sbiswi.pdf
Fizz

Щодо дещо іншого, але відповідно до коментарів, які я писав під запитанням eprint.iacr.org/2012/137.pdf , варто прочитати: 10-кратне уповільнення порівняно з передбачуваною продуктивністю може бути "нормальним" для GPU, якщо ви не отримаєте вниз до його складання (як правило, з офіційно непідтримуваними інструментами). Можливо, компілятори, орієнтовані на GPU, покращилися, але я не затримав би дихання.
Фіз
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.