Нормализация SSE медленнее, чем простое приближение? - PullRequest
6 голосов
/ 01 февраля 2011

Я пытаюсь нормализовать 4-мерный вектор.

Моим первым подходом было использование встроенных функций SSE - что обеспечило увеличение моей скорости в 2 раза по векторной арифметике. Вот основной код: (v.v4 - это ввод) (с использованием GCC) (все это встроено)

//find squares
v4sf s = __builtin_ia32_mulps(v.v4, v.v4);
//set t to square
v4sf t = s;
//add the 4 squares together
s   = __builtin_ia32_shufps(s, s, 0x1B);
t      = __builtin_ia32_addps(t, s);
s   = __builtin_ia32_shufps(s, s, 0x4e);
t      = __builtin_ia32_addps(t, s);
s   = __builtin_ia32_shufps(s, s, 0x1B);
t      = __builtin_ia32_addps(t, s);
//find 1/sqrt of t
t      = __builtin_ia32_rsqrtps(t);
//multiply to get normal
return Vec4(__builtin_ia32_mulps(v.v4, t));

Я проверяю разборку, и похоже, что я и ожидал. Я не вижу там больших проблем.

В любом случае, тогда я попробовал, используя приближение: (я получил это от Google)

float x = (v.w*v.w) + (v.x*v.x) + (v.y*v.y) + (v.z*v.z);
float xhalf = 0.5f*x;
int i = *(int*)&x; // get bits for floating value
i = 0x5f3759df - (i>>1); // give initial guess y0
x = *(float*)&i; // convert bits back to float
x *= 1.5f - xhalf*x*x; // newton step, repeating this step
// increases accuracy
//x *= 1.5f - xhalf*x*x;
return Vec4(v.w*x, v.x*x, v.y*x, v.z*x);

Он работает немного быстрее, чем версия SSE! (примерно на 5-10% быстрее) Его результаты также очень точны - я бы сказал, 0,001 при поиске длины! Но .. GCC дает мне это слабое строгое правило псевдонимов из-за типа punning.

Поэтому я изменяю это:

union {
    float fa;
    int ia;
};
fa = (v.w*v.w) + (v.x*v.x) + (v.y*v.y) + (v.z*v.z);
float faHalf = 0.5f*fa;
ia = 0x5f3759df - (ia>>1);
fa *= 1.5f - faHalf*fa*fa;
//fa *= 1.5f - faHalf*fa*fa;
return Vec4(v.w*fa, v.x*fa, v.y*fa, v.z*fa);

А теперь модифицированная версия (без предупреждений) работает медленнее !! Он работает почти на 60% быстрее, чем версия SSE (но результат тот же)! Почему это?

Итак, вот вопрос (ы):

  1. Правильно ли введено мое SSE?
  2. Действительно ли SSE медленнее, чем обычные операции с процессором?
  3. Почему, черт возьми, третий код намного медленнее?

Ответы [ 3 ]

2 голосов
/ 01 февраля 2011

Я допинг - я понял, что у меня запущен SETI @ Home во время бенчмаркинга.Я предполагаю, что это убивало мою работу SSE.Выключил его и заставил работать в два раза быстрее.

Я также протестировал его на AMD Athlon и получил те же результаты - SSE был быстрее.

По крайней мере, я исправил ошибку shuf!

1 голос
/ 02 февраля 2011

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

       ; start with xmm0 = { v.x v.y v.z v.w }
       movaps  %xmm0, %mm1         ; save it till the end
       mulps   %xmm0, %xmm0        ; v=v*v
       pshufd  $1, %xmm0, %xmm1    ; xmm1 = { v.y v.x v.x v.x }
       addss   %xmm0, %xmm1        ; xmm1 = { v.y+v.x v.x v.x v.x }
       pshufd  $3, %xmm0, %xmm2    ; xmm2 = { v.w v.x v.x v.x }
       movhlps %xmm0, %xmm3        ; xmm3 = { v.z v.w ? ? }
       addss   %xmm1, %xmm3        ; xmm3 = { v.y+v.x+v.z v.x ? ? }
       addss   %xmm3, %xmm2        ; xmm2 = { v.y+v.x+v.z+v.w v.x v.x v.x }
       rsqrtps  %xmm2, %xmm1        ; xmm1 = { rsqrt(v.y+v.x+v.z+v.w) ... }
       pshufd  $0, %xmm1, %xmm1    ; xmm1 = { rsqrt(v.y+v.x+v.z+v.w) x4 }
       mulps   %xmm1, %xmm0       
       ; end with xmm0 = { v.x*sqrt(...) v.y*sqrt(...) v.z*sqrt(...) v.w*sqrt(...) }
0 голосов
/ 01 февраля 2011

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

Относительно того, почему SSE неточен, у меня нет ответа.Это поможет, если вы можете дать реальные цифры.Если разница составляет 0,3 для вектора размера 1, это было бы возмутительно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...