2010-08-22 2 views
3

Некоторые концепции и конструкции архитектуры «SIMT» до сих пор не ясны.OpenCL: основные вопросы о модели выполнения SIMT

Из того, что я видел и читал, расходящихся путей кода, а если() вообще довольно плохая идея, потому что многие потоки могут выполняться в lockstep. Что это значит? А что-то вроде:

kernel void foo(..., int flag) 
{ 
    if (flag) 
     DO_STUFF 
    else 
     DO_SOMETHING_ELSE 
} 

Параметр «флаг» является одинаковым для всех рабочих узлов и той же отрасли берется для всех рабочих единиц. Теперь, GPU собирается выполнить весь код, все еще сериализуя все, и в основном все еще беря ветвь, которая не берется? Или это немного более умно и будет выполнять только ветвь, если все нити согласуются с ветвью? Это всегда было бы так.

I.e. делает сериализацию ВСЕГДА случается или только при необходимости? Извините за глупый вопрос. ;)

ответ

3

Нет, не всегда. Выполнение обеих ветвей происходит только в том случае, если условие не согласовано между потоками в локальной рабочей группе, это означает, что если условие оценивается по разным значениям между рабочими элементами в локальной рабочей группе, текущие поколения графических процессоров будут выполнять обе ветви, но только правильные ветви будет писать значения и иметь побочные эффекты.

Таким образом, поддержание согласованности имеет жизненно важное значение для производительности в ветвях GPU.

+0

Я бы не назвал это жизненно важным. Это важный фактор в производительности. Хотя это зависит от того, насколько сложны ветви, но, по крайней мере, для большинства ситуаций, с которыми я столкнулся до сих пор, было гораздо более важно оптимизировать доступ к памяти (объединение, избежание конфликтов в банках, сокращение трафика в целом), чем проверка ветвей на тот же путь (который в некоторых случаях работал бы против этих оптимизаций). – Grizzly

+0

@ Grizzly Очень важно, если вы используете ветви :) –

1

не уверен о ati, но для nvidia - умный. Не будет сериализации, если каждая нить в warp идет одинаково.

1

В вашем примере флаг будет иметь одинаковое значение для всех рабочих элементов, поэтому хороший компилятор сгенерирует код, который будет принимать все рабочие элементы в одном направлении.

Но рассмотрим следующий случай:

kernel void foo(..., int *buffer) 
{ 
    if (buffer[get_global_id(0)]) 
     DO_STUFF 
    else 
     DO_SOMETHING_ELSE 
} 

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

+0

Решение о том, должны ли расходящиеся коды происходить внутри аппаратного обеспечения в каждом конкретном случае, что означает, что для вашего примера может произойти или не произойти сериализация в зависимости от значений в буфер (это может произойти только для некоторых рабочих групп, но не для других) – Grizzly

+0

Что такое устранение потока управления? Не могли бы вы объяснить немного больше? благодаря – Zk1001

Смежные вопросы