Стоит ли использовать SSE или мне следует просто полагаться на компилятор?C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Стоит ли использовать SSE или мне следует просто полагаться на компилятор?

Сообщение Anonymous »

Я изучаю отличные инструкции SSE и начал работать над простым кодом для измерения разницы между функцией, использующей их, и той же функцией, использующей «стандартный» код (т. е. не SSE). Я понял, что когда я скомпилировал код (с флагом -O3), версия, использующая версию функции SSE, на самом деле (очень немного) «медленнее», чем версия программы, которая НЕ использует инструкции SSE. Я предполагаю, что:
  • компилятор отлично справляется с оптимизацией кода
  • SSE функция могла бы работать быстрее, но загрузка чисел с плавающей запятой в регистры требует затрат, что сводит на нет преимущества использования инструкций SSE.
  • функция testSSE() недостаточно сложна, чтобы действительно показать разница между версией программы, использующей SSE, и той, которая нет.
Может ли кто-нибудь сказать мне, что он/она думает по этому поводу? Большое спасибо -

РЕДАКТИРОВАТЬ: поэтому я исправил код (см. два листинга кода ниже). Даже с исправленной версией, которая короче, версия SSE дает мне 2''48, а версия без SSE дает мне 1''36, подтверждая тот факт, что в этом случае компилятор справляется со своей задачей лучше меня!

РЕДАКТИРОВАНИЕ: СТАРЫЙ КОД С ОШИБКОЙ (см. исправленную версию ниже)

// compiled with c++ tmp.cpp -msse4 -o testSSE -O3

#include
#include

#include
#include

inline void testSSE(float *node1, float *node2, float *node3, float *node4, float *result)
{
__m128 tmp0, tmp1, tmp2, tmp3;
__m128 l, r;

l = _mm_load_ps(node1); //_mm_store_ps(result, l); fprintf(stderr, "1 %f %f %f %f\n", result[0], result[1], result[2], result[3]);
r = _mm_load_ps(node1 + 4); //_mm_store_ps(result, r); fprintf(stderr, "2 %f %f %f %f\n", result[0], result[1], result[2], result[3]);
tmp0 = _mm_hadd_ps(l, r); //_mm_store_ps(result, tmp0); fprintf(stderr, "3 %f %f %f %f\n", result[0], result[1], result[2], result[3]);

l = _mm_load_ps(node2); //_mm_store_ps(result, l); fprintf(stderr, "4 %f %f %f %f\n", result[0], result[1], result[2], result[3]);
r = _mm_load_ps(node2 + 4); //_mm_store_ps(result, r); fprintf(stderr, "5 %f %f %f %f\n", result[0], result[1], result[2], result[3]);
tmp1 = _mm_hadd_ps(l, r); //_mm_store_ps(result, tmp0); fprintf(stderr, "6 %f %f %f %f\n", result[0], result[1], result[2], result[3]);

l = _mm_load_ps(node3);
r = _mm_load_ps(node3 + 4);
tmp2 = _mm_hadd_ps(l, r);

l = _mm_load_ps(node4); //_mm_store_ps(result, l); fprintf(stderr, "10 %f %f %f %f\n", result[0], result[1], result[2], result[3]);
r = _mm_load_ps(node4 + 4); //_mm_store_ps(result, r); fprintf(stderr, "11 %f %f %f %f\n", result[0], result[1], result[2], result[3]);
tmp3 = _mm_hadd_ps(l, r); //_mm_store_ps(result, tmp0); fprintf(stderr, "12 %f %f %f %f\n", result[0], result[1], result[2], result[3]);

l = _mm_hadd_ps(tmp0, tmp1);
r = _mm_hadd_ps(tmp2, tmp3);

__m128 pDest = _mm_hadd_ps(l, r);

_mm_store_ps(result, pDest); // fprintf(stderr, "FINAL %f %f %f %f\n", result[0], result[1], result[2], result[3]);
}

void test(float *node1, float *node2, float *node3, float *node4, float *result)
{
float tmp0[4], tmp1[4], tmp2[4], tmp3[4];
tmp0[0] = node1[0] + node1[1];
tmp0[1] = node1[2] + node1[3];
tmp0[2] = node1[4] + node1[5];
tmp0[3] = node1[6] + node1[7];

tmp1[0] = node2[0] + node2[1];
tmp1[1] = node2[2] + node2[3];
tmp1[2] = node2[4] + node2[5];
tmp1[3] = node2[6] + node2[7];

tmp2[0] = node3[0] + node3[1];
tmp2[1] = node3[2] + node3[3];
tmp2[2] = node3[4] + node3[5];
tmp2[3] = node3[6] + node3[7];

tmp3[0] = node4[0] + node4[1];
tmp3[1] = node4[2] + node4[3];
tmp3[2] = node4[4] + node4[5];
tmp3[3] = node4[6] + node4[7];

float l[4], r[4];
l[0] = tmp0[0] + tmp0[1];
l[1] = tmp0[2] + tmp0[3];
l[2] = tmp1[0] + tmp1[1];
l[3] = tmp1[2] + tmp1[3];

r[0] = tmp2[0] + tmp2[1];
r[1] = tmp2[2] + tmp2[3];
r[2] = tmp3[0] + tmp3[1];
r[3] = tmp3[2] + tmp3[3];

result[0] = l[0] + l[1];
result[1] = l[2] + l[3];
result[2] = r[0] + r[1];
result[3] = r[2] + r[3];

}

int main(int argc, char **argv)
{
int nnodes = 4;
double t = clock();
for (int k = 0; k < 10000000; ++k) {
float *data = new float [nnodes * 8];
for (int i = 0; i < nnodes * 8; ++i) { data = (i / 8) + 1; /* fprintf(stderr, "data %02d %f\n", i, data); */ }
float result[4];
int off = sizeof(float) * 8;
testSSE(data, data + 8, data + 16, data + 24, result);
delete [] data;
}
fprintf(stderr, "%02f (sec)\n", (clock() - t) / (float)CLOCKS_PER_SEC);
return 0;
}


РЕДАКТИРОВАТЬ: новый (исправленный) код

#include
#include

#include
#include

inline void testSSE(float *node1, float *node2, float *node3, float *node4, float *result)
{
__m128 tmp0, tmp1, tmp2, tmp3;

tmp0 = _mm_load_ps(node1);
tmp1 = _mm_load_ps(node2);
tmp2 = _mm_hadd_ps(tmp0, tmp1);

tmp0 = _mm_load_ps(node3);
tmp1 = _mm_load_ps(node4);
tmp3 = _mm_hadd_ps(tmp0, tmp1);

tmp0 = _mm_hadd_ps(tmp2, tmp3);

_mm_store_ps(result, tmp0);
}

void test(float *node1, float *node2, float *node3, float *node4, float *result)
{
float tmp0[4], tmp1[4], tmp2[4], tmp3[4];
tmp0[0] = node1[0] + node1[1];
tmp0[1] = node1[2] + node1[3];
tmp0[2] = node1[4] + node1[5];
tmp0[3] = node1[6] + node1[7];

tmp1[0] = node2[0] + node2[1];
tmp1[1] = node2[2] + node2[3];
tmp1[2] = node2[4] + node2[5];
tmp1[3] = node2[6] + node2[7];

tmp2[0] = node3[0] + node3[1];
tmp2[1] = node3[2] + node3[3];
tmp2[2] = node3[4] + node3[5];
tmp2[3] = node3[6] + node3[7];

tmp3[0] = node4[0] + node4[1];
tmp3[1] = node4[2] + node4[3];
tmp3[2] = node4[4] + node4[5];
tmp3[3] = node4[6] + node4[7];

float l[4], r[4];
l[0] = tmp0[0] + tmp0[1];
l[1] = tmp0[2] + tmp0[3];
l[2] = tmp1[0] + tmp1[1];
l[3] = tmp1[2] + tmp1[3];

r[0] = tmp2[0] + tmp2[1];
r[1] = tmp2[2] + tmp2[3];
r[2] = tmp3[0] + tmp3[1];
r[3] = tmp3[2] + tmp3[3];

result[0] = l[0] + l[1];
result[1] = l[2] + l[3];
result[2] = r[0] + r[1];
result[3] = r[2] + r[3];
}

int main(int argc, char **argv)
{

int nnodes = 4;
float *data = new float [nnodes * 8];
for (int i = 0; i < nnodes * 8; ++i) { data = (i / 8) + 1; /* fprintf(stderr, "data %02d %f\n", i, data); */ }
double t = clock();
for (int k = 0; k < 1e+9; ++k) {
float result[4];
int off = sizeof(float) * 8;
test(data, data + 8, data + 16, data + 24, result);
}
fprintf(stderr, "%02f (sec)\n", (clock() - t) / (float)CLOCKS_PER_SEC);
delete [] data;
return 0;
}


Подробнее здесь: https://stackoverflow.com/questions/163 ... e-compiler
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»