2011-12-08 3 views
14

요즘은 재미있게 x86 어셈블리에 글을 올렸고 프리픽스 문자열 명령어가 실제로 현대 프로세서에서 성능상의 우위를 차지하고 있는지 궁금해하고있었습니다. 이전 버전과의 호환성을 위해 구현되었습니다.현대 (파이프 라인/슈퍼 스칼라) 프로세서에서의 x86 명령어의 성능

프로세서가 한 번에 하나의 명령 만 실행했을 때 Intel이 원래 rep 명령을 구현 한 이유를 알 수 있습니다 만, 지금은 그 이점이 있습니까?

자세한 지침에 따라 컴파일되는 루프를 사용하면 파이프 라인을 채우거나 순서가 잘못 될 수 있습니다. 현대의 프로세서는 이러한 접두사가 붙은 지시를 위해 최적화되어 있습니까? 아니면 담당자가 제조사에게 중요하지 않은 최신 코드에서는 거의 사용되지 않습니다.

+0

나는 이것을 5 년 동안 들여다 보지 않았다. 그러나 그때 나의 개인적인 경험은 적어도 회상 변이가없는 반면 movsd와 rep stosd는 단순한 루프보다 빠르다는 것이었다. 그것은 이후 크게 바뀔 수있었습니다. –

+0

다른 프로세서에서 테스트를 수행하고 직접 확인하십시오. –

+0

입력 해 주셔서 감사합니다. Alex : 아마 결국은되지만, 다른 procs를 많이 사용하지는 않으므로 파이프 라인이없는 에뮬레이터와 비교할 때 실제 proc에있을 것입니다. 또한, 게으르다. 누군가 다른 사람이 이미 그 일을했다면 오히려 그 일을하지 않을 것이다. :) – RyanS

답변

33

AMD와 Intel의 최적화 가이드에는 이와 같은 질문에 많은 공간이 있습니다.

  • AMD Software Optimization Guide (Sep/2005), 8.3 절, 페이지 : 다른 CPU의 세대 예를 들어, 다르게 동작 -이 지역에 주어진 충고의 유효성은 "반감기"이있다. 167 :
    문자열 연산을 수행 할 때, 특히 메모리 블록을 복사 할 때 REP 접두어을 사용하지 마십시오.
  • AMD Software Optimization Guide (Apr/2011), 9.3, pg. 148 :
    문자열 작업을 수행 할 때주의 깊게 REP 접두어을 사용하십시오.

Intel Architecture Optimization Manual는 표 7-2 (rep stosd 포함)의 다양한 블록 복사 기술의 성능 비교 수치를 제공한다. 메모리 복사 루틴의 상대적 성능, 페이지. 7-37f., 다른 CPU에 대해, 그리고 가장 빠른 것은 다른 것에 가장 빠르지 않을 수 있습니다.

많은 경우에 "문자열"SSE4.2 작업이있는 최신 x86 CPU는 this investigation을 참조하여 SIMD 장치를 통해 문자열 작업을 수행 할 수 있습니다.

모든 사항을 철저히 조사하고 (필연적으로 상황이 다시 바뀌면 스스로 업데이트해야 함) Agner Fog's Optimization guides/blogs을 읽어보십시오.

+0

+1 훌륭한 답변입니다. Agner Fog의 사이트에는 좋은 정보가 가득합니다. –

+4

Agner Fog를 언급하기 위해 +1 – hirschhornsalz

+0

'rep movs'와'rep stos'는 일반적으로 훌륭하고 (중간에서 큰 정렬 된 버퍼의 경우),'repeat/repne scas/cmps'는 보통 좋지 않습니다. –

8

FrankH의 뛰어난 대답 외에도, 나는 어떤 방법이 스트링의 길이, 정렬, 그리고 길이가 고정되어 있거나 가변적인지에 따라 가장 잘된다는 것을 지적하고 싶다.

작은 문자열 (어쩌면 최대 약 16 바이트)의 경우 간단한 지침을 사용하여 수동으로 수행하는 것이 더 복잡한 기술의 설치 비용을 피할 수 있으며 (고정 크기 문자열은 쉽게 풀 수 있습니다). 중간 크기 문자열 (16 바이트에서 4KB까지)의 경우 "REP MOVSD"(정렬 불일치가 발생할 수있는 경우 "MOVSB"지침이 일부 표시됨)와 같은 것이 가장 좋을 수 있습니다.

SSE/AVX 및 프리 페치 (prefetching) 등으로 들어가기를 원하는 사람들이 있습니다. 더 좋은 방법은 발신자를 수정하여 복사 (또는 strlen() 등)하지 않도록하는 것입니다. 처음부터 필요했다. 열심히 노력하면 거의 항상 길을 찾을 수 있습니다. 참고 : 빠른 mempcy() 루틴에 대해서도 매우주의하십시오. 일반적으로 대용량 문자열에서 테스트되었으며 훨씬 더 작은/작은/중간 문자열에서 테스트되지 않았습니다.

이러한 모든 차이 (길이, 정렬, 고정 또는 가변 크기, CPU 유형 등)로 인해 (편의성보다는 최적화 목적으로) 하나의 다목적 "memcpy) "매우 다른 경우 모두가 근시안입니다.

+2

Ack. 최적화 가이드 (Intel/AMD와 Agner Fog의 자료 및 많은 다른 것들)는 이러한 것들을 언급합니다; 많은 경우, 전략 : 1. 짧은 문자열, 인라인 기본 명령어 2.중간 크기의 경우, 큰 피연산자 크기의 'rep movs'3. 알려진 큰 블록의 경우 SIMD 단위를 사용하십시오. 그리고 대부분의 문자열이 <8 바이트 인 경우 '초고속 VVX'성능이 저하되므로 _your_ 데이터에서 항상 테스트합니다. –

+0

IIRC'REP MOVSD'는 현대의 하드웨어에서 종종'REP MOVSB'보다 훨씬 느립니다. 아마도 현대 CPU는'REP MOVSB'보다 훨씬 더 자주 사용되기 때문에'REP MOVSB'에 대해서만 특별한 최적화를하기 때문일 것입니다. –

+0

@PaulGroke : 아마도'rep movsb'가'rep movsd'보다 더 좋은 CPU가있을 수 있습니다. 그러나 대부분은'rep movsd' /'movsq'에 대한 모든 ERMSB 마법을 구현합니다. 그리고 IvyBridge의 향상된 Rep MovSB 기능 이전의 Intel CPU에서는'rep movsb'가 대개 * 더 나빴습니다. [memcpy에 대한 향상된 REP MOVSB] (https://stackoverflow.com/questions/43343231/enhanced-rep-movsb-for-memcpy)를 참조하십시오. x86 메모리 대역폭에 대한 자세한 내용은 훌륭합니다. –

0

아무도 당신에게 아무 숫자도주지 않았기 때문에, 나는 매우 memcpy-heavy 인 가비지 컬렉터를 벤치마킹하여 찾은 것을 몇 가지 알려줄 것입니다. 복사 할 객체는 길이가 60 % 16 바이트이고 나머지 30 %는 500 - 8000 바이트 정도입니다.

  • 전제 조건 : 두 dst, srcn는 8
  • 프로세서의 배수는 다음과 같습니다 AMD 페넘 (TM) II X6의 1090T 프로세서 64 비트/리눅스
여기

내 세 memcpy 변종은 다음과 같습니다

손으로 코딩 된 while 루프 :

if (n == 16) { 
    *dst++ = *src++; 
    *dst++ = *src++; 
} else { 
    size_t n_ptrs = n/sizeof(ptr); 
    ptr *end = dst + n_ptrs; 
    while (dst < end) { 
     *dst++ = *src++; 
    } 
} 

(ptruintptr_t의 별명입니다.) 시간 : 101.16 %

rep movsb

if (n == 16) { 
    *dst++ = *src++; 
    *dst++ = *src++; 
} else { 
    asm volatile("cld\n\t" 
       "rep ; movsb" 
       : "=D" (dst), "=S" (src) 
       : "c" (n), "D" (dst), "S" (src) 
       : "memory"); 
} 

시간 : 103.22 %

rep movsq

if (n == 16) { 
    *dst++ = *src++; 
    *dst++ = *src++; 
} else { 
    size_t n_ptrs = n/sizeof(ptr); 
    asm volatile("cld\n\t" 
       "rep ; movsq" 
       : "=D" (dst), "=S" (src) 
       : "c" (n_ptrs), "D" (dst), "S" (src) 
       : "memory"); 
} 

시간 : 100.00 %의 작은 차이로

req movsq 승리.

+1

RCX 레지스터는 REP MOVS에 의해 변경됩니다. –