IT Share you

인텔 컴파일러를 사용하는 Windows와 Linux의 성능 차이 : 어셈블리 살펴보기

shareyou 2020. 11. 18. 21:48
반응형

인텔 컴파일러를 사용하는 Windows와 Linux의 성능 차이 : 어셈블리 살펴보기


Windows와 Linux (x86-64)에서 프로그램을 실행하고 있습니다. 동일한 옵션으로 동일한 컴파일러 (Intel Parallel Studio XE 2017)로 컴파일되었으며 Windows 버전은 Linux 버전보다 3 배 빠릅니다. 범인은 std::erf두 경우 모두에 대해 Intel 수학 라이브러리에서 해결되는 호출입니다 (기본적으로 Windows에서는 동적으로 연결되고 Linux에서는 정적으로 연결되지만 Linux에서 동적 연결을 사용하면 동일한 성능이 제공됨).

다음은 문제를 재현하는 간단한 프로그램입니다.

#include <cmath>
#include <cstdio>

int main() {
  int n = 100000000;
  float sum = 1.0f;

  for (int k = 0; k < n; k++) {
    sum += std::erf(sum);
  }

  std::printf("%7.2f\n", sum);
}

vTune을 사용하여이 프로그램을 프로파일 링 할 때 Windows와 Linux 버전간에 어셈블리가 약간 다릅니다. 다음은 Windows의 호출 사이트 (루프)입니다.

Block 3:
"vmovaps xmm0, xmm6"
call 0x1400023e0 <erff>
Block 4:
inc ebx
"vaddss xmm6, xmm6, xmm0"
"cmp ebx, 0x5f5e100"
jl 0x14000103f <Block 3>

그리고 Windows에서 호출되는 erf 함수의 시작

Block 1:
push rbp
"sub rsp, 0x40"
"lea rbp, ptr [rsp+0x20]"
"lea rcx, ptr [rip-0xa6c81]"
"movd edx, xmm0"
"movups xmmword ptr [rbp+0x10], xmm6"
"movss dword ptr [rbp+0x30], xmm0"
"mov eax, edx"
"and edx, 0x7fffffff"
"and eax, 0x80000000"
"add eax, 0x3f800000"
"mov dword ptr [rbp], eax"
"movss xmm6, dword ptr [rbp]"
"cmp edx, 0x7f800000"
...

Linux에서는 코드가 약간 다릅니다. 호출 사이트는 다음과 같습니다.

Block 3
"vmovaps %xmm1, %xmm0"
"vmovssl  %xmm1, (%rsp)"
callq  0x400bc0 <erff>
Block 4
inc %r12d
"vmovssl  (%rsp), %xmm1"
"vaddss %xmm0, %xmm1, %xmm1"   <-------- hotspot here
"cmp $0x5f5e100, %r12d"
jl 0x400b6b <Block 3>

호출 된 함수 (erf)의 시작은 다음과 같습니다.

"movd %xmm0, %edx"
"movssl  %xmm0, -0x10(%rsp)"   <-------- hotspot here
"mov %edx, %eax"
"and $0x7fffffff, %edx"
"and $0x80000000, %eax"
"add $0x3f800000, %eax"
"movl  %eax, -0x18(%rsp)"
"movssl  -0x18(%rsp), %xmm0"
"cmp $0x7f800000, %edx"
jnl 0x400dac <Block 8>
...

나는 Linux에서 시간이 손실되는 두 가지 지점을 보여주었습니다.

누구든지 2 코드의 차이점과 Linux 버전이 3 배 느린 이유를 설명 할만큼 어셈블리를 충분히 이해하고 있습니까?


두 경우 모두 인수와 결과는 Windows 및 GNU / Linux의 각 호출 규칙에 따라 레지스터 에서만 전달 됩니다 .

GNU / Linux 변형에서는 xmm1합계를 누적하는 데 사용됩니다. 호출 차단 레지스터 (또는 호출자 저장)이기 때문에 각 호출에서 호출자의 스택 프레임에 저장 (및 복원)됩니다.

Windows 변형에서는 xmm6합계를 누적하는 데 사용됩니다. 이 레지스터는 Windows 호출 규칙 ( GNU / Linux에서는 아님)에 피 호출자에 저장됩니다 .

요약하면, GNU / Linux 버전은 xmm0(피 호출자 [1])와 xmm1(호출자에서 ) 모두 저장 / 복원하는 반면 Windows 버전은 xmm6(피 호출자 에서만) 저장 / 복원합니다 .

[1] std::errf이유를 알아 내야합니다.


Using Visual Studio 2015, Win 7 64 bit mode, I find the following code for some of the paths used in erf() (not all paths shown). Each path involves up to 8 (maybe more for other paths) constants read from memory, so a single store / load to save a register seems unlikely to result in a 3x speed differential between Linux and Windows. As far for save / restores, this example saves and restores xmm6 and xmm7. As for the time, the program in the original post takes about 0.86 seconds on an Intel 3770K (3.5ghz cpu) (VS2015 / Win 7 64 bit). Update - I later determined the overhead for a save and restore of a xmm register is about 0.03 seconds in the case of the programs 10^8 loops (about 3 nanoseconds per loop).

000007FEEE25CF90  mov         rax,rsp  
000007FEEE25CF93  movss       dword ptr [rax+8],xmm0  
000007FEEE25CF98  sub         rsp,48h  
000007FEEE25CF9C  movaps      xmmword ptr [rax-18h],xmm6  
000007FEEE25CFA0  lea         rcx,[rax+8]  
000007FEEE25CFA4  movaps      xmmword ptr [rax-28h],xmm7  
000007FEEE25CFA8  movaps      xmm6,xmm0  
000007FEEE25CFAB  call        000007FEEE266370  
000007FEEE25CFB0  movsx       ecx,ax  
000007FEEE25CFB3  test        ecx,ecx  
000007FEEE25CFB5  je          000007FEEE25D0AF  
000007FEEE25CFBB  sub         ecx,1  
000007FEEE25CFBE  je          000007FEEE25D08F  
000007FEEE25CFC4  cmp         ecx,1  
000007FEEE25CFC7  je          000007FEEE25D0AF  
000007FEEE25CFCD  xorps       xmm7,xmm7  
000007FEEE25CFD0  movaps      xmm2,xmm6  
000007FEEE25CFD3  comiss      xmm7,xmm6  
000007FEEE25CFD6  jbe         000007FEEE25CFDF  
000007FEEE25CFD8  xorps       xmm2,xmmword ptr [7FEEE2991E0h]  
000007FEEE25CFDF  movss       xmm0,dword ptr [7FEEE298E50h]  
000007FEEE25CFE7  comiss      xmm0,xmm2  
000007FEEE25CFEA  jbe         000007FEEE25D053  
000007FEEE25CFEC  movaps      xmm2,xmm6  
000007FEEE25CFEF  mulss       xmm2,xmm6  
000007FEEE25CFF3  movaps      xmm0,xmm2  
000007FEEE25CFF6  movaps      xmm1,xmm2  
000007FEEE25CFF9  mulss       xmm0,dword ptr [7FEEE298B34h]  
000007FEEE25D001  mulss       xmm1,dword ptr [7FEEE298B5Ch]  
000007FEEE25D009  addss       xmm0,dword ptr [7FEEE298B8Ch]  
000007FEEE25D011  addss       xmm1,dword ptr [7FEEE298B9Ch]  
000007FEEE25D019  mulss       xmm0,xmm2  
000007FEEE25D01D  mulss       xmm1,xmm2  
000007FEEE25D021  addss       xmm0,dword ptr [7FEEE298BB8h]  
000007FEEE25D029  addss       xmm1,dword ptr [7FEEE298C88h]  
000007FEEE25D031  mulss       xmm0,xmm2  
000007FEEE25D035  mulss       xmm1,xmm2  
000007FEEE25D039  addss       xmm0,dword ptr [7FEEE298DC8h]  
000007FEEE25D041  addss       xmm1,dword ptr [7FEEE298D8Ch]  
000007FEEE25D049  divss       xmm0,xmm1  
000007FEEE25D04D  mulss       xmm0,xmm6  
000007FEEE25D051  jmp         000007FEEE25D0B2  
000007FEEE25D053  movss       xmm1,dword ptr [7FEEE299028h]  
000007FEEE25D05B  comiss      xmm1,xmm2  
000007FEEE25D05E  jbe         000007FEEE25D076  
000007FEEE25D060  movaps      xmm0,xmm2  
000007FEEE25D063  call        000007FEEE25CF04  
000007FEEE25D068  movss       xmm1,dword ptr [7FEEE298D8Ch]  
000007FEEE25D070  subss       xmm1,xmm0  
000007FEEE25D074  jmp         000007FEEE25D07E  
000007FEEE25D076  movss       xmm1,dword ptr [7FEEE298D8Ch]  
000007FEEE25D07E  comiss      xmm7,xmm6  
000007FEEE25D081  jbe         000007FEEE25D08A  
000007FEEE25D083  xorps       xmm1,xmmword ptr [7FEEE2991E0h]  
000007FEEE25D08A  movaps      xmm0,xmm1  
000007FEEE25D08D  jmp         000007FEEE25D0B2  
000007FEEE25D08F  mov         eax,8000h  
000007FEEE25D094  test        word ptr [rsp+52h],ax  
000007FEEE25D099  je          000007FEEE25D0A5  
000007FEEE25D09B  movss       xmm0,dword ptr [7FEEE2990DCh]  
000007FEEE25D0A3  jmp         000007FEEE25D0B2  
000007FEEE25D0A5  movss       xmm0,dword ptr [7FEEE298D8Ch]  
000007FEEE25D0AD  jmp         000007FEEE25D0B2  
000007FEEE25D0AF  movaps      xmm0,xmm6  
000007FEEE25D0B2  movaps      xmm6,xmmword ptr [rsp+30h]  
000007FEEE25D0B7  movaps      xmm7,xmmword ptr [rsp+20h]  
000007FEEE25D0BC  add         rsp,48h  
000007FEEE25D0C0  ret  

참고URL : https://stackoverflow.com/questions/40522841/performance-difference-between-windows-and-linux-using-intel-compiler-looking-a

반응형