2013-08-28 2 views
0

У меня есть ядро ​​CUDA, где есть много операций и несколько ветвей. ПохожеНизкопроизводительное ядро ​​

__global__ 
void kernel(Real *randomValues, Real mu, Real sigma) 
{ 
    int row = blockDim.y * blockIdx.y + threadIdx.y; 
    int col = blockDim.x * blockIdx.x + threadIdx.x; 

    if (row >= cnTimeSteps || col >= cnPaths) return; 

    Real alphaLevel = randomValues[row*cnPaths+col]; 
    Real q = 0.0; 
    Real x = 0.0; 

    if (alphaLevel < p_low) 
    { 
     q = sqrt(-2*log(alphaLevel)); 
     x = (((((c1*q+c2)*q+c3)*q+c4)*q+c5)*q+c6)/((((d1*q+d2)*q+d3)*q+d4)*q+1); 
    } 
    else if (alphaLevel < p_high) 
    { 
     q = alphaLevel-0.5; 
     Real r = q*q; 
     x= (((((a1*r+a2)*r+a3)*r+a4)*r+a5)*r+a6)*q/(((((b1*r+b2)*r+b3)*r+b4)*r+b5)*r+1); 
    } 
    else 
    { 
     q = sqrt(-2*log(1.0-alphaLevel)); 
     x = -(((((c1*q+c2)*q+c3)*q+c4)*q+c5)*q+c6)/((((d1*q+d2)*q+d3)*q+d4)*q+1); 
    } 

    randomValues[row*cnPaths+col] = sigma * x + mu; 
} 

где все a 'ы, b' ы, c 's и d' s являются постоянными величинами (в устройстве постоянной памяти)

static __device__ __constant__ Real a1 = 1.73687; 
static __device__ __constant__ Real a2 = 1.12321100; 

и так далее.

После профилирования ядра я обнаружил, что теоретическое занятие составляет 100%, но я получаю не более 60%.

Я прошел через this и this GTC говорит, чтобы попытаться оптимизировать мое ядро.

С одной стороны у меня есть, что IPC сообщает в среднем 1,32 выданных инструкций и 0,62 выполненных. Сериализация инструкций составляет около 50%, но активность SM составляет почти 100%. С другой стороны, существует около 38 активных перекопов, но 8 имеют право выполнять следующую инструкцию, но при эффективности эмиссионного анализа я получаю, что около 70% циклов не имеют подходящей основы. Причины срыва указаны как «Прочие», которые, как я полагаю, связаны с вычислением log и sqrt.

  1. Как может активность SM быть 99,82%, если в большинстве циклов нет подходящей основы?
  2. Как я могу уменьшить стойло?
  3. Поскольку потоки в деформации не могут попасть в одну ветвь, запросы на постоянную память, вероятно, серализованы, это правда? Должен ли я помещать эти константы в глобальную память (возможно, также использовать разделяемую память)?

Впервые я использую Nsight Visual Studio, поэтому я пытаюсь понять смысл всего анализа производительности. Кстати, моя карточка Quadro K4000.

+3

относительно вашего вопроса 3, я не вижу ничего плохого в использовании постоянной памяти. Это разумное применение постоянной памяти. Дивергенция warp является несвязанной проблемой и сама по себе не приводит к какой-либо «сериализации» доступа к постоянной памяти. Все потоки в деформации по определенному пути выполняются в режиме блокировки, и эти потоки будут обслуживаться одновременно заданным запросом постоянной памяти, по крайней мере, в коде, который вы здесь указали. –

+2

(1) С точки зрения производительности, вероятно, лучше использовать литеральные константы вместо данных '__constant__'. (2) Код, кажется, вычисляет рациональные аппроксимации некоторой математической функции, и похоже, что эта функция может быть тесно связана с функцией ошибки или с CDF нормального распределения. Если да, рассмотрите возможность использования одной из функций erf(), erfc(), erfinv(), erfcinv(), normcdf(), normalcdfinv() CUDA. – njuffa

+1

@ BRabbit27: Более пристальное изучение приближений выше настоятельно указывает на то, что они представляют собой одноточное приближение обратной функции кумулятивного распределения нормального распределения. CUDA имеет встроенную функцию для этого, normcdfinvf().Я хотел бы предложить, чтобы попытаться выяснить, может ли его использование помочь улучшить производительность этого кода. – njuffa

ответ

3

1) Как может активность SM быть 99,82%, если в большинстве циклов нет подходящих оснований?

Варп активен, если регистры и слот деформации выделены для основы. SM активен, если на SM активна не менее 1 warp.

Активность SM не должна путаться с эффективностью.

2) Как я могу уменьшить стойло?

В случае кода, находящегося выше перекоса, задерживается, ожидая, что будут доступны блоки исполнения двойной точности. Quadro K4000 имеет пропускную способность 8 потоков/циклов для операций двойной точности.

Средства правовой защиты для этой проблемы: a. Уменьшите количество операций двойной точности. Например, перемещение последовательных операций в float может значительно повысить производительность, поскольку пропускная способность с одинарной точностью с плавающей запятой - это пропускная способность с двойной точностью 24x. b. Выполните ядро ​​на GK110, который имеет 8X пропускную способность с двойной точностью GK10x.

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

Эксперимент «Достигнутый FLOP» может использоваться для подтверждения того, связана ли производительность ядра с двойной пропускной способностью.

3) Поскольку потоки в деформации не могут попасть в одну ветвь, запросы на постоянную память, вероятно, являются серализованными, это правда? Должен ли я помещать эти константы в глобальную память (возможно, также использовать разделяемую память)?

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

Начальная глобальная нагрузка не может быть объединена. Вы должны указать значение cnPaths для просмотра кем-то. Вы также можете посмотреть эксперименты с памятью или эксперименты с корреляцией источника.

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

+0

Большое спасибо. ** 2. ** Я попробую оба варианта, хотя сначала мне нужно получить GK110. Для достигнутого эксперимента FLOP я получаю примерно 40 GFLOP. Где я могу найти пропускную способность single vs с двойной точностью для GK104 и GK110? ** 3. ** Значение cnPaths может варьироваться в диапазоне [1e4 - 1e6], но я думаю, что шаблон доступа достигнет объединения, если я не забываю что-то. – BRabbit27

+0

Ничего, я нашел [Kepler Tunning Guide] (http://docs.nvidia.com/cuda/kepler-tuning-guide/index.html) – BRabbit27

0

Вы могли бы уменьшить влияние искривления дивергенции за счет упрощения:

if (alphaLevel < p_low) 
{ 
    q = sqrt(-2*log(alphaLevel)); 
    x = (((((c1*q+c2)*q+c3)*q+c4)*q+c5)*q+c6)/((((d1*q+d2)*q+d3)*q+d4)*q+1); 
} 
else if (alphaLevel < p_high) 
{ 
    q = alphaLevel-0.5; 
    Real r = q*q; 
    x= (((((a1*r+a2)*r+a3)*r+a4)*r+a5)*r+a6)*q/(((((b1*r+b2)*r+b3)*r+b4)*r+b5)*r+1); 
} 
else 
{ 
    q = sqrt(-2*log(1.0-alphaLevel)); 
    x = -(((((c1*q+c2)*q+c3)*q+c4)*q+c5)*q+c6)/((((d1*q+d2)*q+d3)*q+d4)*q+1); 
} 

к:

if (alphaLevel >= p_low && alphaLevel < p_high) 
{ 
    q = alphaLevel-0.5; 
    Real r = q*q; 
    x= (((((a1*r+a2)*r+a3)*r+a4)*r+a5)*r+a6)*q/(((((b1*r+b2)*r+b3)*r+b4)*r+b5)*r+1); 
} 
else 
{ 
    alphaLevel = alphaLevel >= p_low ? 1.0-alphaLevel : alphaLevel; 
    q = sqrt(-2*log(alphaLevel)); 
    x = -(((((c1*q+c2)*q+c3)*q+c4)*q+c5)*q+c6)/((((d1*q+d2)*q+d3)*q+d4)*q+1); 
} 
1

Я полагаю, ваш Real тип данных является ЬурейеЕ поплавка. Вы можете попробовать добавить суффикс f к постоянным значениям, которые используются, чтобы компилятор не добавлял ненужные приведения.

E.g.

q = alphaLevel-0.5; 

Постоянная 0.5 - двойное значение, альфа-уровень - значение real = float. alphaLevel будет передано в двойное. q имеет тип float. Результат от вычитания должен быть уменьшен до плавающего значения.

Если Real - это typedef dobule, все ваши вычисления смешиваются в два раза и плавают, что приводит к тому же литье вверх и вниз.

+0

Да, Реал - типед для парных. В этом случае, где будут отливки? Я почти уверен, что все равно – BRabbit27

+0

@ BRabbit27 каждая константа, используемая вами, т. Е. A1, a2 и т. Д., Будет увеличена до double каждый раз, когда она будет использоваться. –

+0

Так жаль, что я допустил ошибку, константы также являются «реальными», поэтому не должно быть никаких поощрений, чтобы удвоить. – BRabbit27

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