C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 Q&A
C++Builder Programming Q&A
[60105] Re:YUV데이터를 Surface에 쓸때 CPU를 줄이는 방법이 있을까요 ?
Nibble [gameover] 1457 읽음    2010-02-01 23:42
안녕하세요 4비트 입니다.
난처한 질문이로군요. 흠.

예제로 보여주신 for문은 memmove로 채워져 있어 크게 성능향상을 기대할 여지가 없습니다.
포인터 연산중, 라인시작점에 대한 옵셋 부분을 전체 라인 수 만큼 배열에 넣어놨다가
매번 샘플이 들어올 때 마다 우려 먹으면 CPU 처리량은 조금 감소하겠죠.
그렇지만 가로 픽셀당의 처리량이 월등하므로 성능향상 폭은 미미하게 됩니다.

CPU의 부하를 줄인다는 말과 성능을 높인다는 말은 어떤 의미에선 반대의 의미인데요.
성능을 높이기 위해선 대개의 경우 CPU에 풀로드를 걸게 됩니다.
DMA를 사용할 수 있는 경우에는 CPU로드를 줄일 수 있겠지만 말이죠.

DMA의 도움을 받을 수 없는 대개의 어플리케이션에서, 이 경우에 선택할 수 있는 여지는 아주 궁색합니다.
목표를 최단시간에 작업을 끝내자. 로 잡는다면, 이런 방법은 있을 수 있겠죠.

0.1 준비 : memmove를 분할 구현할 thread를 엽니다. (Core 갯수만큼)
0.2 샘플이 결정되었을 때, 샘플의 각 라인별 시작 주소의 옵셋들을 미리 계산해 배열에 넣어둡니다.

1. 가속 memmove 구현
1.1. Block Prefetch 를 수행합니다. (캐시 메모리 허용범위 내에서 적당히)
1.2. 64비트 단위로 복사를 합니다.

Block Prefetch 란 녀석의 메카니즘은 간단합니다.
CPU 내에 존재하는 캐쉬컨트롤러에게 작업량을 할당하고, 그만큼 CPU 의 메모리 컨트롤러에 대한 직접 제어는
한가하게 만들어 주는 것이죠.

가령 이렇게 합니다. (하드웨어 마다 최적 상황이 다르겠지요)
int cacher;
static const void inline blockPrefetch4K(void* addr)
{
    int* a = (int*) addr;
    cacher += a[0] + a[16] + a[32] + a[48] ... a[240]; // 1K
    a += 256;
    cacher += a[0] + a[16] + a[32] + a[48] ... a[240]; // 2K
    a += 256;
    cacher += a[0] + a[16] + a[32] + a[48] ... a[240]; // 3K
    a += 256;
    cacher += a[0] + a[16] + a[32] + a[48] ... a[240]; // 4K
}

즉 16개의 배열, 16 * 4 = 64바이트 간격으로 메모리를 4바이트씩 읽어들입니다. 이로써, 캐쉬 메모리는
4KByte 분량을 Core내부에 로딩해 두게 됩니다. 이 이후 4K 범위 내에서 메모리 복제를 수행하면,
CPU <-> 주메모리 가 아니라,
CPU <-> 캐쉬 간의 처리가 일어나, memory IO 만큼의 delay가 줄게 됩니다.

for(라인들)
    for(캐쉬 단위 가로들)
    {
         blockPrefetch4K(src시작주소 - 블럭크기);
         for(캐쉬내 8바이트 단위) *tgt-- = *src--; // tgt, src 는 double pointer
    }

처럼 수행하는 memmove를 구현하는거죠.
(여기서 *tgt-- = *src-- 은 루프를 확장해 여러번 수행할 수록 비교와 점프로 부터 유리할 수 있겠죠
코드가 캐싱되는 범위 내에서 말이죠)
여기서 double pointer들은 mmx 레지스터들로 대체 가능합니다.
대용량 복사가 아닐 경우는 SIMD가 memmove를 이기기 힘들지만,
movq mm0, qword ptr ...., movq mm1, .... movq mm7, .... 해서 레지스터들로 옮겨 놓고
movq qword ptr .... , mm0 등등등 (8회) 해서 타겟 주소로 복사하는 식이죠. (혹은 movntq)
이 과정중엔 float연산이 개입할 수 없으므로, 다른 프로세스나 쓰레드에서 부동소수점 연산이 들어가게 되면
오히려 성능이 떨어지게 됩니다. 고로, 다른 프로세스의 처리명령에 대해 확신할 수 없다면
그냥 double *가 나을지도 모릅니다. (하긴 그정도면 memmove가 더 나을 상황이겠군요)

Decoder에서 직접 surface로 YUV를 뿌려주는게 물론 제일 경제적이긴 한데
그러면 Decoder를 직접 구현해야 하고, DirectShow의 컨셉상 활용도가 떨어지니까...
궁하다면 저런 방법이 있겠지요.
        
경호 님이 쓰신 글 :
: 안녕하세요 ?
: 경호입니다.
:
: directdraw를 이용해서 화면에 동영상을 play하고 있습니다.
: 여기저기 최적화를 하다가 이쪽에 지식을 가지신 분들이 있으면 도움을 받을까 해서
: 간단하게 올려 봅니다
:
: 일단 Codec에서 YUV를 뽑아내고 있는 방식은
: 1. 버퍼 1개에 YUV데이터를 모두 붙여서 얻어온다.
:      (Y전체 쓰고  U쓰고 V쓰고 : 일반적으로 파일에 YUV데이터를 쌓는 형태)
: 2. YUV를 각각의 개별버퍼를 만들어 얻어 온다
:      (즉 3개의 버퍼에 개별적으로 Y와 U,V를 얻어 온다)
:
: 위쪽은 MMX 및 ASM으로 이미 최적화를 한상태 입니다.
:
: 제가 줄이고 싶은 부분은 Directdraw부분인대 즉 YUV데이터를 Surface에 쓸때 사용되는 for문을 줄일 수 있을까
: 하는 것입니다.
:
: 실제 사용되는 소스는
: for (DWORD j=0 ; j<dwHeight/2; ++j)
:  {
:      memmove((BYTE*)m_ddsd.lpSurface + j*m_ddsd.lPitch, pSrcData + j*dwWidth, dwWidth);
:      memmove((BYTE*)m_ddsd.lpSurface + j*m_ddsd.lPitch + dwHeight/2*m_ddsd.lPitch, pSrcData + dwHeight/2*dwWidth + j*dwWidth, dwWidth);
:      memmove((BYTE*)m_ddsd.lpSurface + m_ddsd.lPitch*m_ddsd.dwHeight*5/4 + j*m_ddsd.lPitch/2, pSrcData + dwWidth*dwHeight + j*dwWidth/2, dwWidth/2);
:     memmove((BYTE*)m_ddsd.lpSurface + m_ddsd.lPitch*m_ddsd.dwHeight + j*m_ddsd.lPitch/2, pSrcData + dwWidth*dwHeight*5/4 + j*dwWidth/2, dwWidth/2);
: }
: 입니다. 현재는 버퍼 하나에 쌓인 YUV데이터를 surface에 그리면서 위와 같이 처리하고 있는대
: 이 부분을 처리하면서 CPU부하를 적게 먹게 할 방법이 있을까요 ?
:
: 물론 위코드에서 for문 안에 있는 * / 부분은 전부 변수로 빼서 따로 계산하도록은 할것 입니다.
:
: 논리적으로나 또는 surface에 데이터를 쓸때 YUV를 따로 가지고 처리하면 부하를 적게 먹는다던지
: 이런 부분이 있을 수 있는지 도움을 받을 수 있으면 감사 드리겠습니다.

+ -

관련 글 리스트
60101 YUV데이터를 Surface에 쓸때 CPU를 줄이는 방법이 있을까요 ? 경호 1385 2010/02/01
60116     Re:YUV데이터를 Surface에 쓸때 CPU를 줄이는 방법이 있을까요 ? 남병철.레조 1551 2010/02/02
60105     Re:YUV데이터를 Surface에 쓸때 CPU를 줄이는 방법이 있을까요 ? Nibble 1457 2010/02/01
60110         Re:Re:YUV데이터를 Surface에 쓸때 CPU를 줄이는 방법이 있을까요 ? 경호 1205 2010/02/02
60113             Re:Re:Re:YUV데이터를 Surface에 쓸때 CPU를 줄이는 방법이 있을까요 ? Nibble 1065 2010/02/02
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.