А и В являются векторами или длиной N, где N может быть в диапазоне от 20 до 200, скажем.
Я хочу вычислить квадрат расстояния между этими векторами,
то есть d ^ 2 = || A-B || ^ 2.
Пока что у меня есть:
float* a = ...;
float* b = ...;
float d2 = 0;
for(int k = 0; k < N; ++k)
{
float d = a[k] - b[k];
d2 += d * d;
}
Кажется, это работает нормально, за исключением того, что я профилировал свой код, и это узкое место (более 50% времени тратится только на это).
Я использую Visual Studio 2012, на Win 7, с этими параметрами оптимизации: /O2 /Oi /Ot /Oy-
,
Насколько я понимаю, VS2012 должен автоматически векторизовать этот цикл (используя SSE2).
Однако, если я вставлю #pragma loop(no_vector)
в коде я не вижу заметного замедления, поэтому я предполагаю, что цикл не векторизован. Компилятор подтверждает это этим сообщением:
info C5002: loop not vectorized due to reason '1105'
Мои вопросы:
reason '1105'
?От Документация MSDN, код ошибки 1105 означает, что компилятор не может понять, как свести код к векторизованным инструкциям. Для операций с плавающей запятой указано, что вам нужно указать параметр / fp: fast, чтобы разрешить любые сокращения с плавающей запятой вообще.
Это довольно просто реализовать с помощью встроенных функций SSE:
#include "pmmintrin.h"
__m128 vd2 = _mm_set1_ps(0.0f);
float d2 = 0.0f;
int k;
// process 4 elements per iteration
for (k = 0; k < N - 3; k += 4)
{
__m128 va = _mm_loadu_ps(&a[k]);
__m128 vb = _mm_loadu_ps(&b[k]);
__m128 vd = _mm_sub_ps(va, vb);
vd = _mm_mul_ps(vd, vd);
vd2 = _mm_add_ps(vd2, vd);
}
// horizontal sum of 4 partial dot products
vd2 = _mm_hadd_ps(vd2, vd2);
vd2 = _mm_hadd_ps(vd2, vd2);
_mm_store_ss(&d2, vd2);
// clean up any remaining elements
for ( ; k < N; ++k)
{
float d = a[k] - b[k];
d2 += d * d;
}
Обратите внимание, что если вы можете гарантировать, что a
а также b
выровнены 16 байтов, то вы можете использовать _mm_load_ps
скорее, чем _mm_loadu_ps
что может помочь производительности, особенно на старых (до Nehalem) процессорах.
Отметим также, что для таких циклов, как этот, где очень мало арифметических инструкций относительно количества нагрузок, производительность может быть ограничена пропускной способностью памяти, и ожидаемое ускорение от векторизации может не реализоваться на практике.