умножение с использованием SSE (x*x*x)

Я пытаюсь оптимизировать функцию куба с помощью SSE.

long cube(long n)
{
    return n*n*n;
}

Я пробовал это:

return (long) _mm_mul_su32(_mm_mul_su32((__m64)n,(__m64)n),(__m64)n);

И производительность была еще хуже (и да я никогда ничего не делал с sse).

Есть ли функция SSE, которая может повысить производительность? Или что-то другое?

вывод из cat /proc/cpuinfo


processor   : 0
vendor_id   : GenuineIntel
cpu family  : 6
model       : 15
model name  : Intel(R) Xeon(R) CPU            3070  @ 2.66GHz
stepping    : 6
cpu MHz     : 2660.074
cache size  : 4096 KB
physical id : 0
siblings    : 2
core id     : 0
cpu cores   : 2
apicid      : 0
initial apicid  : 0
fpu     : yes
fpu_exception   : yes
cpuid level : 10
wp      : yes
flags       : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx lm constant_tsc arch_perfmon pebs bts rep_good pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm lahf_lm tpr_shadow
bogomips    : 5320.14
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management:

processor   : 1
vendor_id   : GenuineIntel
cpu family  : 6
model       : 15
model name  : Intel(R) Xeon(R) CPU            3070  @ 2.66GHz
stepping    : 6
cpu MHz     : 2660.074
cache size  : 4096 KB
physical id : 0
siblings    : 2
core id     : 1
cpu cores   : 2
apicid      : 1
initial apicid  : 1
fpu     : yes
fpu_exception   : yes
cpuid level : 10
wp      : yes
flags       : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx lm constant_tsc arch_perfmon pebs bts rep_good pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm lahf_lm tpr_shadow
bogomips    : 5320.35
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management:


c sse
person sherif    schedule 27.11.2011    source источник
comment
Какая у вас платформа, и вы проверили, что ваш компилятор уже не выводит что-то оптимальное (или близкое)?   -  person Mat    schedule 27.11.2011
comment
Я не проверял, но насколько я слышал, компилятор gcc делает это автоматически.   -  person sherif    schedule 27.11.2011
comment
SSE предназначен для одновременной обработки нескольких элементов (вычисления нескольких кубов), а не для ускорения вычислений одной операции.   -  person Marat Dukhan    schedule 28.11.2011


Ответы (3)


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

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

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

person Mats    schedule 27.11.2011
comment
У меня есть несколько данных, это n и n, а также 3 значения, которые я хочу умножить - person sherif; 27.11.2011
comment
@sherif Нет. У вас есть n, n*n и (n*n)*n. Вы не можете вычислить последнее значение без второго. т.е. распараллеливание невозможно. Если бы у вас были s и t и вы хотели вычислить s*s*s и t*t*t, вы могли бы выполнить некоторые расчеты одновременно. - person Mats; 28.11.2011
comment
как я мог это сделать? Я вызываю функцию куба из оператора for. Я, вероятно, мог бы создать что-то вроде sss и ttt - person sherif; 29.11.2011
comment
Я задал новый вопрос относительно (xxx)+(yyy) stackoverflow.com/questions/8357182/ - person sherif; 02.12.2011

Ваш код компилируется в:

cube:
        movl    4(%esp), %edx
        movl    %edx, %eax
        imull   %edx, %eax
        imull   %edx, %eax
        ret

Если встроить ret и move, они будут оптимизированы, поэтому у вас будет две инструкции imul. Я сомневаюсь, что mmx или SSE могут сделать это быстрее (передача данных только в регистры mmx / sse, вероятно, будет медленнее, чем два imuls)

person Nils Pipenbrinck    schedule 27.11.2011

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

cube(long* inArray, long* outArray, size_t size) {
  ...
}
person Monkey    schedule 27.11.2011
comment
функция куба вызывается из оператора for, который выполняет итерацию по массиву, компилятор должен встроить его туда автоматически, кроме того, что я ограничен использованием памяти, в любом случае спасибо - person sherif; 27.11.2011