LINUX.ORG.RU

Вопрос царям о SSE

 


0

1

Короче я хочу с помощью SSE найти среднее 4-х компонентных векторов (каждая координата в single precision).

Почему-то получается не слишком быстрей, чем обычный цикл:

http://pastebin.com/y1gRRfH3

> cc -O2 -o test2 test2.c
> ./test2
0.224113
360287968.000000 360287968.000000 360287968.000000
0.207714
360287968.000000 360287968.000000 360287968.000000

Зато вроде бы то же самое, но со скалярами, куда быстрее:

http://pastebin.com/Mqck8UZr

> cc -O2 -o test3 test3.c
> ./test3
0.001325 1074428160.000000
0.001332 1074428160.000000
0.000336 1074427136.000000
2.500000

По сути в первом варианте (с векторами) с помощью SSE мы убрали внутренний цикл, т.е. операций суммирования стало меньше в 4 раза, а скорость такая же. Подумал, что это из-за того, что компилятор может раскрыть цикл, и прыжков будет меньше, но нет, это не играет роли, как видно из второго теста. Как правильно готовить SSE для подсчета среднего именно векторов?

Насколько я знаю, SSE - это расширение разработанное для архитектур CISC. Начиная с Intel Pentium 3, архетектуру ядер процессоров изменили на RISC сделав эмуляцию CISC. SSE конечно даёт прирост производительности и на современных процессорах, но работает по другому чем на старых для которых изначально и разрабатывался.

А вообще, попробуй разные компиляторы.

rezedent12 ☆☆☆ ()

смотри ассемблерный листинг генерируемый компилятором из этого

anonymous ()

Почему-то получается не слишком быстрей, чем обычный цикл

Потому что встроенный векторизатор

0.000466 1074428160.000000
0.000466 1074428160.000000
0.000117 1074427136.000000
2.500000
gcc -O3 -fno-omit-frame-pointer -fno-inline -o test test.c
00000000004007a0 <calc_avg1>:
  4007a0:	55                   	push   %rbp
  4007a1:	85 f6                	test   %esi,%esi
  4007a3:	0f 57 c0             	xorps  %xmm0,%xmm0
  4007a6:	48 89 e5             	mov    %rsp,%rbp
  4007a9:	7e 12                	jle    4007bd <calc_avg1+0x1d>
  4007ab:	0f 57 c0             	xorps  %xmm0,%xmm0
  4007ae:	31 c0                	xor    %eax,%eax
  4007b0:	f3 0f 58 04 87       	addss  (%rdi,%rax,4),%xmm0
  4007b5:	48 83 c0 01          	add    $0x1,%rax
  4007b9:	39 c6                	cmp    %eax,%esi
  4007bb:	7f f3                	jg     4007b0 <calc_avg1+0x10>
  4007bd:	f3 0f 2a ce          	cvtsi2ss %esi,%xmm1
  4007c1:	5d                   	pop    %rbp
  4007c2:	f3 0f 5e c1          	divss  %xmm1,%xmm0
  4007c6:	c3                   	retq   
  4007c7:	66 0f 1f 84 00 00 00 	nopw   0x0(%rax,%rax,1)
  4007ce:	00 00 

00000000004007d0 <calc_avg2>:
  4007d0:	55                   	push   %rbp
  4007d1:	85 f6                	test   %esi,%esi
  4007d3:	0f 57 c0             	xorps  %xmm0,%xmm0
  4007d6:	48 89 e5             	mov    %rsp,%rbp
  4007d9:	7e 31                	jle    40080c <calc_avg2+0x3c>
  4007db:	8d 46 ff             	lea    -0x1(%rsi),%eax
  4007de:	0f 57 c0             	xorps  %xmm0,%xmm0
  4007e1:	c1 e8 02             	shr    $0x2,%eax
  4007e4:	48 c1 e0 04          	shl    $0x4,%rax
  4007e8:	48 8d 44 07 10       	lea    0x10(%rdi,%rax,1),%rax
  4007ed:	0f 1f 00             	nopl   (%rax)
  4007f0:	f3 0f 58 07          	addss  (%rdi),%xmm0
  4007f4:	48 83 c7 10          	add    $0x10,%rdi
  4007f8:	f3 0f 58 47 f4       	addss  -0xc(%rdi),%xmm0
  4007fd:	f3 0f 58 47 f8       	addss  -0x8(%rdi),%xmm0
  400802:	f3 0f 58 47 fc       	addss  -0x4(%rdi),%xmm0
  400807:	48 39 c7             	cmp    %rax,%rdi
  40080a:	75 e4                	jne    4007f0 <calc_avg2+0x20>
  40080c:	f3 0f 2a ce          	cvtsi2ss %esi,%xmm1
  400810:	5d                   	pop    %rbp
  400811:	f3 0f 5e c1          	divss  %xmm1,%xmm0
  400815:	c3                   	retq   
  400816:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
  40081d:	00 00 00 

0000000000400820 <calc_avg3>:
  400820:	55                   	push   %rbp
  400821:	85 f6                	test   %esi,%esi
  400823:	48 89 e5             	mov    %rsp,%rbp
  400826:	7e 4e                	jle    400876 <calc_avg3+0x56>
  400828:	8d 46 ff             	lea    -0x1(%rsi),%eax
  40082b:	0f 57 c9             	xorps  %xmm1,%xmm1
  40082e:	c1 e8 02             	shr    $0x2,%eax
  400831:	48 c1 e0 04          	shl    $0x4,%rax
  400835:	48 8d 44 07 10       	lea    0x10(%rdi,%rax,1),%rax
  40083a:	66 0f 1f 44 00 00    	nopw   0x0(%rax,%rax,1)
  400840:	0f 58 0f             	addps  (%rdi),%xmm1
  400843:	48 83 c7 10          	add    $0x10,%rdi
  400847:	48 39 c7             	cmp    %rax,%rdi
  40084a:	75 f4                	jne    400840 <calc_avg3+0x20>
  40084c:	0f 28 d1             	movaps %xmm1,%xmm2
  40084f:	0f 28 c1             	movaps %xmm1,%xmm0
  400852:	0f c6 d1 55          	shufps $0x55,%xmm1,%xmm2
  400856:	5d                   	pop    %rbp
  400857:	f3 0f 58 c2          	addss  %xmm2,%xmm0
  40085b:	0f 28 d1             	movaps %xmm1,%xmm2
  40085e:	0f 15 d1             	unpckhps %xmm1,%xmm2
  400861:	0f c6 c9 ff          	shufps $0xff,%xmm1,%xmm1
  400865:	f3 0f 58 c2          	addss  %xmm2,%xmm0
  400869:	f3 0f 58 c1          	addss  %xmm1,%xmm0
  40086d:	f3 0f 2a ce          	cvtsi2ss %esi,%xmm1
  400871:	f3 0f 5e c1          	divss  %xmm1,%xmm0
  400875:	c3                   	retq   
  400876:	0f 57 c9             	xorps  %xmm1,%xmm1
  400879:	eb d1                	jmp    40084c <calc_avg3+0x2c>
  40087b:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)

geks ()
Ответ на: комментарий от rezedent12

Что-то ты 100% неправильно слышал. Тот же SSE2 появился уже только на пне 4. Да и что такое «эмуляция CISC» не ясно. CISC это же дофига разных комманд, нетривиальное их кодирование кодами переменной длины (как раз в x86 от 1 до 15 байт, ЕМНИП), микрокод.

А вообще, попробуй разные компиляторы.

Да, вот gcc не догадывается раскрыть внутренний цикл. Может из за этого не-SSE версия работает чуть более, чем в 2 раза дольше. Но это дела gcc, непосредственно к делу это не относится. Ща я постану, что clang дает

php-tsar ()
0000000000400860 <calc_avg1>:
  400860:	55                   	push   %rbp
  400861:	48 89 e5             	mov    %rsp,%rbp
  400864:	85 d2                	test   %edx,%edx
  400866:	0f 57 c0             	xorps  %xmm0,%xmm0
  400869:	0f 11 07             	movups %xmm0,(%rdi)
  40086c:	7e 42                	jle    4008b0 <calc_avg1+0x50>
  40086e:	48 83 c6 0c          	add    $0xc,%rsi
  400872:	0f 57 c0             	xorps  %xmm0,%xmm0
  400875:	89 d0                	mov    %edx,%eax
  400877:	0f 57 c9             	xorps  %xmm1,%xmm1
  40087a:	0f 57 d2             	xorps  %xmm2,%xmm2
  40087d:	0f 57 db             	xorps  %xmm3,%xmm3
  400880:	f3 0f 58 5e f4       	addss  -0xc(%rsi),%xmm3
  400885:	f3 0f 11 1f          	movss  %xmm3,(%rdi)
  400889:	f3 0f 58 56 f8       	addss  -0x8(%rsi),%xmm2
  40088e:	f3 0f 11 57 04       	movss  %xmm2,0x4(%rdi)
  400893:	f3 0f 58 4e fc       	addss  -0x4(%rsi),%xmm1
  400898:	f3 0f 11 4f 08       	movss  %xmm1,0x8(%rdi)
  40089d:	f3 0f 58 06          	addss  (%rsi),%xmm0
  4008a1:	f3 0f 11 47 0c       	movss  %xmm0,0xc(%rdi)
  4008a6:	48 83 c6 10          	add    $0x10,%rsi
  4008aa:	ff c8                	dec    %eax
  4008ac:	75 d2                	jne    400880 <calc_avg1+0x20>
  4008ae:	eb 0c                	jmp    4008bc <calc_avg1+0x5c>
  4008b0:	0f 57 c0             	xorps  %xmm0,%xmm0
  4008b3:	0f 57 c9             	xorps  %xmm1,%xmm1
  4008b6:	0f 57 d2             	xorps  %xmm2,%xmm2
  4008b9:	0f 57 db             	xorps  %xmm3,%xmm3
  4008bc:	f3 0f 2a e2          	cvtsi2ss %edx,%xmm4
  4008c0:	f3 0f 5e dc          	divss  %xmm4,%xmm3
  4008c4:	f3 0f 11 1f          	movss  %xmm3,(%rdi)
  4008c8:	f3 0f 5e d4          	divss  %xmm4,%xmm2
  4008cc:	f3 0f 11 57 04       	movss  %xmm2,0x4(%rdi)
  4008d1:	f3 0f 5e cc          	divss  %xmm4,%xmm1
  4008d5:	f3 0f 11 4f 08       	movss  %xmm1,0x8(%rdi)
  4008da:	f3 0f 5e c4          	divss  %xmm4,%xmm0
  4008de:	f3 0f 11 47 0c       	movss  %xmm0,0xc(%rdi)
  4008e3:	5d                   	pop    %rbp
  4008e4:	c3                   	retq   
  4008e5:	66 66 2e 0f 1f 84 00 	nopw   %cs:0x0(%rax,%rax,1)
  4008ec:	00 00 00 00 

00000000004008f0 <calc_avg2>:
  4008f0:	55                   	push   %rbp
  4008f1:	48 89 e5             	mov    %rsp,%rbp
  4008f4:	85 d2                	test   %edx,%edx
  4008f6:	0f 57 c0             	xorps  %xmm0,%xmm0
  4008f9:	7e 10                	jle    40090b <calc_avg2+0x1b>
  4008fb:	89 d0                	mov    %edx,%eax
  4008fd:	0f 1f 00             	nopl   (%rax)
  400900:	0f 58 06             	addps  (%rsi),%xmm0
  400903:	48 83 c6 10          	add    $0x10,%rsi
  400907:	ff c8                	dec    %eax
  400909:	75 f5                	jne    400900 <calc_avg2+0x10>
  40090b:	66 0f 6e ca          	movd   %edx,%xmm1
  40090f:	66 0f 70 c9 00       	pshufd $0x0,%xmm1,%xmm1
  400914:	0f 5b c9             	cvtdq2ps %xmm1,%xmm1
  400917:	0f 5e c1             	divps  %xmm1,%xmm0
  40091a:	0f 29 07             	movaps %xmm0,(%rdi)
  40091d:	5d                   	pop    %rbp
  40091e:	c3                   	retq   
  40091f:	90                   	nop    

Вроде в calc_avg1 только внутренний цикл раскрыл

php-tsar ()
Ответ на: комментарий от geks

И где там векторизация?

Векторные операции только в calc_avg3, и они там вручную вписанные. Я заметил, что clang без --ffast-math такое не векторизирует, и очень правильно — результат будет другой немного в этих функциях

php-tsar ()
Ответ на: комментарий от php-tsar

Да и что такое «эмуляция CISC»

RISC ядро выполняет за несколько тактов инструкцию выполняемую на CISC ядре за меньшее колличество тактов.

Это было очень заметно когда я сравнивал работу warcraft 3 на Celeron 900 МГц и Pentium 3 1100 МГц. Точно не помню, но частота Pentium 3 был повыше. На Pentium 3 игра во время высоких нагрузок была более дёрганной и больше тормозила чем на Celeron меньшей частоты. Я стал узнавать почему так происходит и узнал что несмотря на большую частоту, на многих операциях из за эмуляции CISC ядра RISC ядром теряется 30% вычислительной мощности.

rezedent12 ☆☆☆ ()
Ответ на: комментарий от rezedent12

Почитай про это больше, то, что ты пишешь, не соответствует действительности.

Deleted ()
Ответ на: комментарий от geks

Ты бы узнал, что эти инструкции значат.

addss это сложение single precision значений, которые находятся в младших 32 битах xmm регистров, к векторизации она не имеет никакого отношения. Векторизация  — это addps, как в 3 версии.

cvtsi2ss это вообще перевод кол-ва векторов (n) в single float и запись в младшие биты xmm1

php-tsar ()
Ответ на: комментарий от rezedent12

ты слышал звон, и теперь пересказываешь его нам как понял (неправильно)

thesame ★★★★ ()

вангую слишко мало операций в ссе регистрах. весь профит пропадает от того, что их надо загружать/выгружать. где-то в мануалах интел есть об этом.

anonymous ()
Ответ на: комментарий от anonymous

хрен с пхп, но остальные могли подтянуться и накрапать нормальное пятничное чтиво по теме, а не как обычно «лор, я абассался, отговори менять штаны» или «лор, зацени мой супер рабочий стол/яумамыхаккир»

anonymous ()
Ответ на: комментарий от anonymous

скажем так

А если говорить прямо, без, скажем так, увёрток?

anonymous ()
Ответ на: комментарий от anonymous

Ты как чувак, который тут про RISC с видом знатока разглагольствовал

anonymous ()

Собственно вся суть ламерков. Ты взываешь ко мне, когда даже не попытался погуглить. Если ты взываешь не ко мне, а к этим ламоклоунам, то собственно удачи. Они же так разбираются в теме, что кроме как насрать в штанишки ничего не могут.

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

Далее, ты нихрена не умеешь писать код. Хреначь на жабке лет 15, потом авось что-то сможешь.

Берём поиск и ищем: «илитный запил». Производительность; илитный запил оптимальных реализаций и основы матчасти. - я там всё разбирал и если ты это прочитаешь - там есть все ответы.

Захреначил #define N 100000000 и #define N 400000, но алёша сравнивает. Какой жопой ты сравниваешь полтора гига и полтора метра?

Если ты не понял разницу между метром и гигом, то мне тебя жаль. Ещё лет 15 на жабке. В моём том посте всё это расписано и про трупут fp и про трупут кешей/памяти.

Тебе ещё лет 20хреначить на жабке, что бы хоть чутка понять одну штуку - что-то меря надо понимать что ты меряешь. Пока этого понимания нет - жрать говно на жабке единственный вариант.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.