Какой наиболее эффективный способ умножить 4 числа с плавающей точкой на 4 с использованием SSE?

StackOverflow https://stackoverflow.com/questions/1227249

  •  22-07-2019
  •  | 
  •  

Вопрос

В настоящее время у меня есть следующий код:

float a[4] = { 10, 20, 30, 40 };
float b[4] = { 0.1, 0.1, 0.1, 0.1 };
asm volatile("movups (%0), %%xmm0\n\t"
             "mulps (%1), %%xmm0\n\t"             
             "movups %%xmm0, (%1)"             
             :: "r" (a), "r" (b));

У меня прежде всего несколько вопросов:

(1) если бы я БЫЛ выровнять массивы по границам 16 байт, сработало бы это вообще?Поскольку массивы распределены в стеке, правда ли, что их выравнивание практически невозможно?

см. выбранный ответ для этого сообщения: Выровнены ли переменные стека по GCC __attribute__((aligned(x)))?

(2) Можно ли вообще провести рефакторинг кода, чтобы сделать его более эффективным?Что, если я помещу в регистры оба массива с плавающей запятой, а не только один?

Спасибо

Это было полезно?

Решение

если бы я БЫЛ выровнять массивы по границам 16 байт, это вообще сработало бы?Поскольку массивы распределены в стеке, правда ли, что их выравнивание практически невозможно?

Требуется, чтобы выравнивание по стеку работало.В противном случае встроенные функции не будут работать.Я предполагаю, что сообщение, которое вы процитировали, было связано с непомерным значением, которое он выбрал для значения выравнивания.

до 2:

Нет, разницы в производительности быть не должно.Видеть это сайт для таймингов инструкций нескольких процессоров.


Как работает выравнивание переменных стека:

push    ebp
mov ebp, esp
and esp, -16                ; fffffff0H
sub esp, 200                ; 000000c8H

А и выравнивает начало стека по 16 байтам.

Другие советы

Напишите это на C, используйте

gcc -S -mssse3

если у вас довольно последняя версия gcc.

(1) если бы я БЫЛ выровнять массивы по границам 16 байт, сработало бы это вообще?Поскольку массивы распределены в стеке, правда ли, что их выравнивание практически невозможно?

Нет, выровнять указатель стека довольно просто, используя and:

and esp, 0xFFFFFFF0 ; aligned on a 16-byte boundary

Но вам следует использовать то, что предоставляет GCC, например, 16-байтовый тип или __attribute__ для настройки выравнивания.

Предоставляет ли GCC поддержку __m128 тип данных?Если да, то это ваш лучший план для обеспечения 16-байтового выровненного типа данных.Тем не менее, существует __attribute__((aligned(16))) для выравнивания вещей.Определите свои массивы следующим образом

float a[4] __attribute__((aligned(16))) = { 10, 20, 30, 40 };
float b[4] __attribute__((aligned(16))) = { 0.1, 0.1, 0.1, 0.1 };

а затем вместо этого используйте мовапы :)

Использование встроенных функций происходит намного быстрее, особенно при оптимизации.Я написал простой тест и сравнил обе версии (asm и встроенную).

unsigned long long time1;
__m128 a1,b1;


a1=_mm_set_ps(10, 20,30,40);
b1=_mm_set_ps(0.1, 0.1, 0.1, 0.1);
float a[4] = { 10, 20, 30, 40 };
float b[4] = { 0.1, 0.1, 0.1, 0.1 };

time1=__rdtsc();
a1=_mm_mul_ps(a1,b1);
time1=__rdtsc() - time1 ;
printf("Time: %llu\n",time1);


time1=__rdtsc();
asm volatile("movups (%0), %%xmm0\n\t"
                 "mulps (%1), %%xmm0\n\t"
                 "movups %%xmm0, (%1)"
                 :: "r" (a), "r" (b));
time1=__rdtsc() - time1 ;
printf("Time: %llu\n",time1);

Внутренняя версия 50-60 Процессор TimeStamps ASM версия ~ 1000 Proc TimeMests

Вы можете проверить это на своей машине

О рефакторинге.Вы можете использовать встроенный.Пример:

#include <emmintrin.h>

int main(void)
{
    __m128 a1,b1;

    a1=_mm_set_ps(10, 20,30,40);
    b1=_mm_set_ps(0.1, 0.1, 0.1, 0.1);

    a1=_mm_mul_ps(a1,b1);

    return 0;
}

С оптимизацией gcc (-O2 , -O3) возможно, он будет работать быстрее, чем asm.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top