2016-05-25 6 views
-1

Я хочу умножить два (float/double) вектора с операторами AVX. Для этого мне нужна выровненная память. Моя функция для значений с плавающей точкой является:Выравнивание double vs align float для операций AVX

#define SIZE 65536 
float *g, *h, *j; 
g = (float*)aligned_alloc(32, sizeof(float)*SIZE); 
h = (float*)aligned_alloc(32, sizeof(float)*SIZE); 
j = (float*)aligned_alloc(32, sizeof(float)*SIZE); 
//Filling g and h with data 
for(int i = 0; i < SIZE/8; i++) 
    { 
     __m256 a_a, b_a, c_a; 
     a_a = _mm256_load_ps(g+8*i); 
     b_a = _mm256_load_ps(h+8*i); 
     c_a = _mm256_mul_ps(a_a, b_a); 
     _mm256_store_ps (j+i*8, c_a); 
    } 
free(g); 
free(h); 
free(j); 

Это работает, но когда я пытаюсь сделать это с двойными значениями, я получаю сообщение об ошибке доступа к памяти (например, если память не выровнена):

double *g_d, *h_d, *i_d; 
g_d = (double*)aligned_alloc(32, sizeof(double)*SIZE); 
h_d = (double*)aligned_alloc(32, sizeof(double)*SIZE); 
i_d = (double*)aligned_alloc(32, sizeof(double)*SIZE); 
for(int i = 0; i < SIZE/4; i++) 
{ 
    __m256d a_a, b_a, c_a; 
    a_a = _mm256_load_pd(g_d+4*i); 
    b_a = _mm256_load_pd(h_d+4*i); 
    c_a = _mm256_mul_pd(a_a, b_a); 
    _mm256_store_pd (i_d+i*4, c_a); 
} 
free(g_d); 
free(h_d); 
free(i_d); 

Почему выравнивание не работает для double -значений?

При запуске его в БГД, я получаю

Program received signal SIGSEGV, Segmentation fault. 
0x0000000000401669 in _mm256_load_pd (__P=0x619f70) at /usr/lib/gcc/x86_64-linux-gnu/5/include/avxintrin.h:836 

Edit: я нашел мою ошибку, это была ошибка копирования/вставки из прежней функции, которая проявляется в этой функции. Из-за того, что вы не помогаете другим (как я полагаю), я закрываю вопрос.

+1

Эти имена идентификаторов сосут камни. Какая черта, б, д? Всегда копируйте/вставляйте код из текстового редактора. Из тестовой программы, которая имеет эту проблему, никогда ничего не делайте. –

+0

Исправлены переменные, но позже будет добавлена ​​короткая тестовая программа. –

+1

Работы для меня (тм). Вы использовали отладчик? Точно, в какой строке это происходит, и каково значение адреса, которое он читает (или пишет?). Каков точный код отказа. –

ответ

0

Ну, ваша проблема, похоже, связана с разными размерами данных.

  • В своем первом фрагменте вы увеличиваете float петли к SIZE/8 = 8192. Здесь я не уверен, почему вы бы увеличили массив FLOAT с размером элемента 4 на 8. Таким образом, i < 8192
  • В своем втором фрагменте вы увеличиваете цикл double до SIZE/4 = 16384. Здесь я не уверен, почему вы бы увеличить DOUBLE массив с размером элемента 8 на 4. Так i < 16384 --- ** Противоположный! **

Последний элемент массива DOUBLE может превзойти ваши границы памяти !

В обоих случаях вы увеличиваете свою петлю с помощью i++. Таким образом, дела поступают следующим образом:

Первое: (плавающее (4)) J + I * 8 (0 < я < 8192) =>

0  4  8  12  16  20  24  28 
v1  .  v2  .  v3  .  v4  . 

Второй: (DOUBLE (8)) J + я * 4 (0 < я < 16384) => v1/v2/v3/v4

0  4  8  12  16  20  24  28  32 
v1(h) v1(l) v2(l) v3(l) v4(l) v5(l) v6(l) v7(l) 
v1(h) v2(h) v3(h) v4(h) v5(h) v6(h) v7(h) v8(h) v8(h) 
-------------------------------------------------------------- 
some thing ... some thing ... some thing .. some thing ... 

Во втором фрагменте вы перепутать высокие части (32-битные) и нижние части (32-битный) из 64-битного Double, только увеличивая на 4 (sizeof FLOAT) вместо 8 (sizeof DOUBLE).

Другая проблема состоит в том, что _mm256_store_pd требует, чтобы ...

Когда источник или операнд назначения является операндом памяти, операнд должен быть выровнен по границе 32 байт или исключению общей защиты (# GP).

for(int i = 0; i < SIZE/4; i++) не выполняет это требование.

Мне кажется, что ваша версия FLOAT работает, потому что _mm256_store_ps требует, чтобы ...

Когда операнд источника или назначения является операндом памяти, операнд должен быть выровнен по 16-байтовой границе или будет генерироваться исключение общей защиты (#GP).

, но у вас есть только выравнивание 8 байт ...

Однако, вам нужно исправить «масштаб» вашего i переменной, чтобы сделать эту работу.

+0

Странно, но если я потом сравниваю результаты (путем тестирования каждого элемента с помощью 'c [i]! = A [i] * b [i]' в цикле, я получаю правильные результаты ... –

+1

@arc_lupus: Если вы получить правильные результаты, что могло быть вашим реальным вопросом/проблемой? Я (просто) проанализировал ваш код для потенциальных недостатков/ошибок. И я не знаю, почему ваш тестовый код вернет правильные значения, я просто подчеркнул потенциальные источники проблем. – zx485

+0

Мне было интересно, почему вы говорите, что мой код неправильный, но я все равно получаю правильный результат для значений float после этого? –