2014-11-08 3 views
3

내 이전 question에 따르면 제 생각은 계수 m_a, m_b가 1.0 또는 0.0 일 때 계산을 제거하여 알고리즘을 최적화하는 것이 었습니다. 이제 알고리즘을 최적화하려고 시도하고 설명 할 수없는 흥미로운 결과를 얻었습니다.SSE FP 장치가 0.0 피연산자를 감지합니까?

첫 번째 분석기는 100,000 개의 샘플에 대해 실행됩니다. 파라미터 값은 파일로부터 판독된다 (!)

B0 = 1.0 B1 = -1.480838022915731 B2 = 1.0

A0 = 1.0 A1 = -1.784147570544337 A2 = 0.854309980957510

Slow

둘째 분석기 런 동일한 100k 샘플. 파라미터 값은 파일로부터 판독된다 (!)

B0 = 1.0 = -1.480838022915731 B1 B2 = 1.0

A0 = 1.0 A2 A1 = -1.784147570544337 = 0.0 --- <는 전용 A2가 다르다!

Fast

는 수치 내에서 왼쪽에있는 번호 (회색 배경) 필요한 CPU 사이클을 나타냅니다. 매개 변수 a2 = 0.0으로 명확하게 보이는 두 번째 실행은 훨씬 빠릅니다.

디버그 코드와 릴리스 코드의 차이점을 확인했습니다. 릴리스 코드가 더 빠릅니다 (예상대로). 디버그 및 릴리스 코드는 매개 변수 a2가 수정 될 때 동일한 이상한 동작을합니다.

그런 다음 ASM 코드를 확인했습니다. SSE 지침이 사용 된 것으로 나타났습니다. 이것은/arch : SSE2로 컴파일 되었기 때문에 유효합니다. 따라서 나는 SSE를 사용하지 않았다. 결과 코드는 SSE를 더 이상 사용하지 않으며 성능은 매개 변수 값 a2에 더 이상 의존하지 않습니다 (예상대로)

따라서 SSE가 사용될 때 성능 이점이 있다는 결론을 얻었습니다 a2가 0.0임을 감지하고 쓸모없는 곱셈과 뺄셈을 생략합니다. 나는 이것에 대해 결코 들어 보지 못했고 정보를 찾지 만 성공하지는 못했습니다.

내 성능 결과에 대한 설명이 누구에게 있습니까?

00F43EC0 mov   edx,dword ptr [ebx] 
00F43EC2 movss  xmm0,dword ptr [eax+edi*4] 
00F43EC7 cmp   edx,dword ptr [ebx+4] 
00F43ECA je   $LN419+193h (0F43F9Dh) 
00F43ED0 mov   esi,dword ptr [ebx+4] 
00F43ED3 lea   eax,[edx+68h] 
00F43ED6 lea   ecx,[eax-68h] 
00F43ED9 cvtps2pd xmm0,xmm0 
00F43EDC cmp   ecx,esi 
00F43EDE je   $LN419+180h (0F43F8Ah) 
00F43EE4 movss  xmm1,dword ptr [eax+4] 
00F43EE9 mov   ecx,dword ptr [eax] 
00F43EEB mov   edx,dword ptr [eax-24h] 
00F43EEE movss  xmm3,dword ptr [edx+4] 
00F43EF3 cvtps2pd xmm1,xmm1 
00F43EF6 mulsd  xmm1,xmm0 
00F43EFA movss  xmm0,dword ptr [ecx] 
00F43EFE cvtps2pd xmm4,xmm0 
00F43F01 cvtps2pd xmm3,xmm3 
00F43F04 mulsd  xmm3,xmm4 
00F43F08 xorps  xmm2,xmm2 
00F43F0B cvtpd2ps xmm2,xmm1 
00F43F0F movss  xmm1,dword ptr [ecx+4] 
00F43F14 cvtps2pd xmm4,xmm1 
00F43F17 cvtps2pd xmm2,xmm2 
00F43F1A subsd  xmm2,xmm3 
00F43F1E movss  xmm3,dword ptr [edx+8] 
00F43F23 mov   edx,dword ptr [eax-48h] 
00F43F26 cvtps2pd xmm3,xmm3 
00F43F29 mulsd  xmm3,xmm4 
00F43F2D subsd  xmm2,xmm3 
00F43F31 movss  xmm3,dword ptr [edx+4] 
00F43F36 cvtps2pd xmm4,xmm0 
00F43F39 cvtps2pd xmm3,xmm3 
00F43F3C mulsd  xmm3,xmm4 
00F43F40 movss  xmm4,dword ptr [edx] 
00F43F44 cvtps2pd xmm4,xmm4 
00F43F47 cvtpd2ps xmm2,xmm2 
00F43F4B xorps  xmm5,xmm5 
00F43F4E cvtss2sd xmm5,xmm2 
00F43F52 mulsd  xmm4,xmm5 
00F43F56 addsd  xmm3,xmm4 
00F43F5A movss  xmm4,dword ptr [edx+8] 
00F43F5F cvtps2pd xmm1,xmm1 
00F43F62 movss  dword ptr [ecx+4],xmm0 
00F43F67 mov   edx,dword ptr [eax] 
00F43F69 cvtps2pd xmm4,xmm4 
00F43F6C mulsd  xmm4,xmm1 
00F43F70 addsd  xmm3,xmm4 
00F43F74 xorps  xmm1,xmm1 
00F43F77 cvtpd2ps xmm1,xmm3 
00F43F7B movss  dword ptr [edx],xmm2 
00F43F7F movaps  xmm0,xmm1 
00F43F82 add   eax,70h 
00F43F85 jmp   $LN419+0CCh (0F43ED6h) 
00F43F8A movss  xmm1,dword ptr [ebx+10h] 
00F43F8F cvtps2pd xmm1,xmm1 
00F43F92 mulsd  xmm1,xmm0 
00F43F96 xorps  xmm0,xmm0 
00F43F99 cvtpd2ps xmm0,xmm1 
00F43F9D mov   eax,dword ptr [ebp-4Ch] 
00F43FA0 movss  dword ptr [eax+edi*4],xmm0 
00F43FA5 mov   ecx,dword ptr [ebp-38h] 
00F43FA8 mov   eax,dword ptr [ebp-3Ch] 
00F43FAB sub   ecx,eax 
00F43FAD inc   edi 
00F43FAE sar   ecx,2 
00F43FB1 cmp   edi,ecx 
00F43FB3 jb   $LN419+0B6h (0F43EC0h) 

편집 : 대체 디버그 ASM 코드 릴리스 코드에 의해

완성도를 들어이 릴리스 버전에 대한 관련 ASM 코드입니다.

+3

"해당 디버그 버전의 ASM 코드"관련성이있는 이유는 무엇입니까? 최적화되지 않은 코드의 성능 측정은 무의미합니다. –

+0

이미 설명한 바와 같이 : 릴리스 버전은 빠르지 만 디버그 및 릴리스 버전의 동작은 동일합니다. 읽을 수 있기 때문에 디버그 ASM 코드를 첨부했습니다. 릴리스 ASM 코드를 선호하는 경우 첨부 할 수도 있습니다. – Mark

+0

어셈블리 목록을 게시하거나 컴파일 가능한 코드를 게시하는 대신 컴파일러를 완벽하게 실행할 수 있습니다. –

답변

7

SSE에 대한 FP 곱셈에 대한 초기 단계는 없습니다. 짧은 대기 시간으로 완벽하게 파이프 라인 된 작업이므로 일찍 추가하는 것은 명령 퇴직을 복잡하게하는 동시에 성능상의 이점을 제 공합니다. 현대 프로세서에서 일반적으로 데이터 종속적 인 실행 특성을 갖는 유일한 명령어는 나누기 및 제곱근입니다 (서브 노트를 무시하면 더 많은 명령어가 적용됩니다). 이것은 Intel과 AMD 모두에 의해 광범위하게 문서화되었으며 Agner Fog에 의해 독립적으로 문서화되었습니다.

왜 성능이 어떻게 변하는 걸까요? 가장 가능성있는 설명은 비정상적인 입력이나 결과로 인해 마구간에 마주 치고 있다는 것입니다. 이것은 DSP 필터 및 지연과 함께 매우 일반적입니다. 코드와 입력 데이터를 보지 않고도 이것이 일어난다는 것을 확신 할 수는 없지만 가장 가능성있는 설명입니다. 그렇다면 MXCSR에서 DAZ 및 FTZ 비트를 설정하여 문제를 해결할 수 있습니다.

인텔 문서 : http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf (mulssmulsd에 대한 고정 값 거기에 있습니다, 부록 대기 시간 테이블을 참조하십시오.)

AMD에서 16 시간 명령 대기 시간 (엑셀 스프레드 시트) : http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2012/10/AMD64_16h_InstrLatency_1.1.xlsx

Agner 안개의 Intel 및 AMD의 명령어 대기 시간 표 : http://www.agner.org/optimize/instruction_tables.pdf

+0

Intel, AMD 문서에 대한 링크를 게시 할 수 있습니까? – VAndrei

+0

@VAndrei : 몇 가지 링크를 추가했습니다. –

4

FP HW 곱셈 단위가 조기 출력을 수행하는 경우 이는 정상적인 동작입니다. 당신은 here 자세한 내용을 볼 수 있습니다. 즉, HW가 0.0 값을 감지하면 전체 파이프 라인을 통과하지 못합니다.

그러나 SSE mulsd 명령을 사용하고 있습니다. 스티븐 캐논 (Stephen Canon) 지국장은 Intel 및 AMD 구현에서 mulsd 명령어의 지연 시간이 고정되어 있다고 지적했습니다. 이것은 SSE와 관련된 초기 기능이 없음을 나타냅니다.

또한 Stephen Canon은 비정기 숫자를 사용할 때 성능 문제가 발생한다고 지적했습니다.이 post에서 무엇이 그 원인인지 자세히 읽을 수 있습니다.

그러나 모든 계수는 빈번한 값이며 은 비정상적인 것으로 보이지 않습니다. 문제는 어딘가에있을 수 있습니다. 코드의 모든 ASM 명령어는 대기 시간이 고정되어 있다고 기록되어 있지만 큰 사이클 차이는 무언가 진행되고 있음을 나타냅니다.

0.0 계수가 몇 곱셈으로 나타나는 경우에도 프로파일 출력 결과 모든 대기 시간이 변경되었음을 알 수 있습니다. 결과가 올바르게 계산 되었습니까? Ar 실행 중에 다른 모든 변수가 일정합니까?

+0

@VAndrei :이 유용한 답변에 감사드립니다. . 나는이 중요한 정보를 찾지 못했던 것에 약간 놀랐다. 이전에 http://x86.renejeschke.de/html/file_module_x86_id_213.html 대기 시간과 처리량이 상수 값으로 나열된이 페이지를 확인했습니다. 참고 : 제안 된대로 제목을 업데이트했습니다. – Mark

+0

SSE **에는 FP 곱셈을위한 초기 조달이 없습니다 **. 이는 Intel, AMD 및 Agner Fog에서 잘 설명되어 있으며 Gamasutra보다 훨씬 신뢰할 수있는 출처입니다. –

+0

@StephenCanon 나는 내 게시물을 개정하여 자신을 상향 조정했습니다. 링크를 제공 해주셔서 대단히 감사합니다. OP가 귀하의 대답을 올바른 것으로 표시합니다. 그러나 나는 값이 비정상적으로 보이지 않는다는 사실에 대해 우려하고 있습니다. – VAndrei