문제

메모리 주변의 큰 데이터 덩어리를 복사 해야하는 C에서 이미지 처리를 수행하고 있습니다. 소스와 대상은 결코 겹치지 않습니다.

x86 플랫폼 에서이 작업을 수행하는 가장 빠른 방법은 무엇입니까? GCC (어디 SSE, SSE2이지만 SSE3는 사용할 수 있습니까?)?

솔루션이 어셈블리에 있거나 GCC 내재를 사용하고있을 것으로 기대합니까?

다음 링크를 찾았지만 그것이 가장 좋은 방법인지 전혀 모른다 (저자는 몇 가지 버그가 있다고한다). http://coding.derkeiler.com/archive/assembler/comp.lang.asm.x86/2006-02/msg00123.html

편집 : 사본이 필요하고 데이터를 복사 할 필요가 없습니다 (이유를 설명 할 수는 있지만 설명을 아끼지 않겠습니다 :)).

도움이 되었습니까?

해결책

예의 윌리엄 찬 그리고 구글. Microsoft Visual Studio 2005의 Memcpy보다 30-70% 빠릅니다.

void X_aligned_memcpy_sse2(void* dest, const void* src, const unsigned long size)
{

  __asm
  {
    mov esi, src;    //src pointer
    mov edi, dest;   //dest pointer

    mov ebx, size;   //ebx is our counter 
    shr ebx, 7;      //divide by 128 (8 * 128bit registers)


    loop_copy:
      prefetchnta 128[ESI]; //SSE2 prefetch
      prefetchnta 160[ESI];
      prefetchnta 192[ESI];
      prefetchnta 224[ESI];

      movdqa xmm0, 0[ESI]; //move data from src to registers
      movdqa xmm1, 16[ESI];
      movdqa xmm2, 32[ESI];
      movdqa xmm3, 48[ESI];
      movdqa xmm4, 64[ESI];
      movdqa xmm5, 80[ESI];
      movdqa xmm6, 96[ESI];
      movdqa xmm7, 112[ESI];

      movntdq 0[EDI], xmm0; //move data from registers to dest
      movntdq 16[EDI], xmm1;
      movntdq 32[EDI], xmm2;
      movntdq 48[EDI], xmm3;
      movntdq 64[EDI], xmm4;
      movntdq 80[EDI], xmm5;
      movntdq 96[EDI], xmm6;
      movntdq 112[EDI], xmm7;

      add esi, 128;
      add edi, 128;
      dec ebx;

      jnz loop_copy; //loop please
    loop_copy_end:
  }
}

정확한 상황과 귀하가 할 수있는 가정에 따라 더 최적화 할 수 있습니다.

Memcpy 소스 (memcpy.asm)를 확인하고 특별한 케이스 처리를 제거 할 수도 있습니다. 더 최적화 할 수 있습니다!

다른 팁

모든 최적화 수준에서 -O1 또는 위의 GCC는 다음과 같은 기능에 대한 내장 정의를 사용합니다. memcpy - 오른쪽으로 -march 매개 변수 (-march=pentium4 언급 한 기능 세트의 경우) 매우 최적의 아키텍처 별 인라인 코드를 생성해야합니다.

나는 그것을 벤치마킹하고 무엇이 나오는지 볼 것입니다.

Hapalibashi가 게시 한 SSE 코드는 갈 길입니다.

더 많은 성능이 필요하고 장치 드라이버 작성의 길고 구불 구불 한 도로에서 부끄러워하지 않는다면 : 요즘 모든 중요한 플랫폼에는 CPU 코드와 더 빠르고 병렬로 복사 작업을 수행 할 수있는 DMA 컨트롤러가 있습니다. 할 수 있습니다.

그래도 드라이버를 쓰는 것이 포함됩니다. 보안 위험으로 인해이 기능을 사용자 측에 노출시키는 큰 OS는 없습니다.

그러나 지구상의 코드가 그러한 작업을 수행하도록 설계된 하드웨어를 능가 할 수 없기 때문에 (성능이 필요한 경우) 가치가있을 수 있습니다.

이 질문은 지금 4 살이되었고 아직 아무도 메모리 대역폭을 언급 한 사람이 거의 없다는 것에 약간 놀랐습니다. CPU-Z는 내 기계에 PC3-10700 RAM이 있다고보고합니다. RAM은 10700 mbytes/sec의 피크 대역폭 (일명 전송 속도, 처리량 등)을 갖습니다. 내 컴퓨터의 CPU는 I5-2430m CPU이며 피크 터보 주파수는 3GHz입니다.

이론적으로는 무한히 빠른 CPU와 내 램으로 Memcpy는 5300 Mbytes/sec, Memcpy는 RAM에 읽은 다음 쓸 수 있기 때문에 10700의 절반. (편집 : v.oddou가 지적했듯이 이것은 단순한 근사치입니다).

반면에, 우리는 무한히 빠른 RAM과 사실적인 CPU를 가지고 있다고 상상해보십시오. 우리는 무엇을 달성 할 수 있습니까? 내 3GHz CPU를 예로 사용합시다. 32 비트 읽기와 32 비트 각 사이클을 작성할 수 있다면 3E9 * 4 = 전송할 수 있습니다. 12000 Mbytes/sec. 이것은 현대적인 CPU에 쉽게 도달 할 수있는 것 같습니다. 이미 CPU에서 실행되는 코드가 실제로 병목 현상이 아니라는 것을 알 수 있습니다. 이것이 현대 기계에 데이터 캐시가있는 이유 중 하나입니다.

데이터가 캐시됨을 알 때 Memcpy를 벤치마킹하여 CPU가 실제로 수행 할 수있는 일을 측정 할 수 있습니다. 이 작업을 정확하게하는 것은 어리석은 일입니다. 나는 임의의 숫자를 배열에 작성한 간단한 앱을 만들었고, 다른 배열에 memcpy를 만들고, 복사 된 데이터를 확인했습니다. Debugger의 코드를 통해 영리한 컴파일러가 사본을 제거하지 않았는지 확인했습니다. 배열의 크기를 변경하면 캐시 성능이 변경됩니다. 작은 배열은 캐시에 맞습니다. 큰 배열은 큰 배열이 적습니다. 다음 결과를 얻었습니다.

  • 40 KBYTE 어레이 : 16000 MBYTES/SEC
  • 400 KBYTE 어레이 : 11000 MBYTES/SEC
  • 4000 KBYTE 어레이 : 3100 MBYTES/SEC

분명히 CPU는 16000이 이론적으로 계산 한 12000보다 많기 때문에 주기당 32 비트 이상을 읽고 쓸 수 있습니다. 이것은 CPU가 이미 생각했던 것보다 병목 현상이 훨씬 적다는 것을 의미합니다. Visual Studio 2005를 사용하여 표준 Memcpy 구현에 들어서서 컴퓨터에서 MOVQDA 명령을 사용한다는 것을 알 수 있습니다. 사이클 당 64 비트를 읽고 쓸 수 있다고 생각합니다.

올바른 코드 Hapalibashi 게시물은 내 컴퓨터에서 4200mbbytes/sec를 달성합니다. VS 2005 구현보다 약 40% 더 빠릅니다. 프리 페치 명령어를 사용하여 캐시 성능을 향상시키기 때문에 더 빠르다고 생각합니다.

요약하면 CPU에서 실행되는 코드는 병목 현상이 아니며 코드가 작은 개선 만 할 수 있다는 조정이 아닙니다.

인텔 프로세서에 특화된 경우 혜택을 누릴 수 있습니다. IPP. NVIDIA GPU와 함께 실행한다는 것을 알고 있다면 아마도 사용할 수 있습니다. 쿠다 - 두 경우 모두 memcpy ()를 최적화하는 것보다 더 넓게 보일 수 있습니다 - 그들은 더 높은 수준에서 알고리즘을 개선 할 수있는 기회를 제공합니다. 그러나 둘 다 특정 하드웨어에 의존합니다.

창문에있는 경우 사용하십시오 Directx 구체적인 API GPU-그래픽 처리를위한 최적화 된 루틴 (얼마나 빨리있을 수 있습니까? CPU가로드되지 않았습니다. GPU가 다른 일을하는 동안 다른 일을하십시오).

OS Agnostic이되고 싶다면 시도하십시오 Opengl.

어셈블러와 함께 피지 마십시오. 10 년+ 능숙한 라이브러리 제작 소프트웨어 엔지니어를 비참하게 수행하는 데 비참하게 실패 할 가능성이 높기 때문입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top