2011-01-20 3 views
1

저는 cuda를 사용하여 GPU를 준비 할 때 최적화 및 알고리즘을 연구 중입니다.한 번에 조금씩 읽는 것보다 조금 더 느린 입출력

입출력 부분은 3 개의 다른 이미지에서 한 번에 한 행을 읽습니다. 이것은 이미지 위로 필터를 실행하는 루프 중간에있었습니다. I/O를 자체 루프에 제거하고 이미지를 보유하고있는 배열에 값을 덤핑하여 계산에 사용 된 값을 미리로드하려고했습니다.

이제는 데이터가 완전히로드 된 버퍼로 인해 응용 프로그램이 느리게 실행되고 모든 반복마다 새 데이터를 디스크로 이동해야 할 때 문제가 발생합니다.

이 문제의 원인은 무엇일까요? 더 큰 버퍼의 캐시 미스가 성능을 크게 저하시킬까요? 메모리 문제가 아닙니다.이 머신의 24GB에는 많은 RAM이 있습니다.

아니, 그것은 될 수있는 다른 무엇인지 생각

+3

실제로 저는이 이미지가 첫 번째 반복에서 읽을 때 OS에서 미리 읽기 캐시에 미리 가져온 것으로 생각합니다. –

+0

컴파일러 최적화가이 작업을 수행합니까? – Derek

+0

@Derek : 일반적으로 운영체제입니다. 첫 번째 읽기가 완료되면 디스크 헤드가 위에있는 동안 전체 섹터 (또는 파일이 조각화되지 않은 경우에도 다음 섹터)를 읽는 것이 편리합니다 (데이터를 "무료"로 얻음). 일반적으로 OS에 이런 종류의 물건을위한 특별한 캐시. 또한'stdio'와'iostream'은 캐시를 가지고 있지만, 여기서는 그들이 많은 영향을 미치지 않는다고 생각합니다. –

답변

0

예를 듣고 열려, 당신은 두 번 L2 캐시에 이미지를로드 - 메모리에서 다음 파일을로드 할 때. 또한 캐시에서 메모리로 데이터를 이동하는 데 약간의 시간을 소비해야합니다. 당신이 2-8Mb 같은 일부 부품을로드 할 수있는 옵션으로

2

@Derek는 다음과 같은 추가 정보를 제공합니다 (L2 캐시 크기의 따라) :

(실행 시간) ... . "은 과 비교하여 1 분 넘습니다 .특정 스레딩을 수행하지 않았습니다. 일부 OpenMP pragma가 있습니다. I/O가 필터 루프 외부로 이동하지 않았습니다. any any change 그 중에서도 CentOS를 실행하는 입니다. 5.5. 이미지 크기는 OpenMP를 우리가 여러 스레드 만의 데이터의 72메가바이트와 내가 할 수 다루고 있기 때문에. 거기 가정 할 수 있습니다 사용하기 때문에 실행 시간에 차이가.입니다 약 72메가바이트 "

입니다 I/O 시간의 차이가 얼마나 커질지를 확인하십시오. 우리는 읽기 시간이 원래의 10-14 초보다 작은 것을 긍정적으로 생각할 수 있습니다. 코드의 해당 부분에 버그가 없으면 여분의 시간이 필터에 있습니다. @Satya가 코드 프로파일 링을 제안했거나 타이밍 출력을 추가하는 것이 문제가있는 부분을 식별하는 데 도움이 될 수 있습니다.

t에서 읽기의 "이점" 루프는 다음과 같을 수 있습니다 :

  1. OS는 계산과 병렬로 I/O의 일부를 수행 할 수 있기 때문에 일부 병렬 처리를 제공합니다. 앞서 읽고. 모든 것을 미리 읽고 효과적으로 읽는 동안 차단하면 평행법을 잃게됩니다.
  2. 필터가 데이터에 액세스 할 때 읽은 데이터가 캐시에 있습니다. 프로세싱이 메모리 대역폭에 비해 경량이라면 캐시 미스 (cache miss)는 성능을 실제로 죽일 수 있습니다. 디스크 I/O가 메모리보다 훨씬 느리기 때문에이 사용 사례에서 이것이 중요한 차이를 만들 것이라고 믿는 것은 어렵습니다.

최신 업데이트가 제공되면 2 위를 처리 할 가능성이 높아 보입니다.주의해야 할 점은 메모리 액세스 패턴 (모든 스레드 포함)입니다. 주 메모리에서 인접 해 있던 데이터가 더 멀리 떨어져 있기 때문에 캐시 스 래싱이 표시 될 가능성이 있습니다. 이것은 많은 영향을 미칠 수 있습니다. 왜냐하면 많은 메모리 액세스가 있고 모두 캐시 미스이기 때문에 데이터에 액세스하는 데 드는 비용이 항상 큰 차이를 나타낼 수 있기 때문입니다.

이 해결책은 메모리를 줄무늬로 배열하는 것입니다. 첫 번째 이미지에서 n 줄, 두 번째 이미지에서 n 줄, 세 번째 이미지에서 n 줄이 뒤 따른다. IIRC이 기술은 "스트라이핑"이라고합니다. 정확한 스트라이프 크기는 CPU에 따라 다르지만 실험 할 수있는 것입니다 (또는 충분히 큰 경우 내부 루프에서 읽던 것과 동일한 양의 데이터로 시작).

예컨대 : 당신이 앞뒤로 드라이브에 추구하지 않는, 그래서 한 번에

stripe_number = 0; 
do 
{ 
    count = fread(striped_buffer+(STRIPE_SIZE*stripe_number*NUM_IMAGES), 1, STRIPE_SIZE, image_file); 
    stripe_number++; 
} while(count != 0); 

읽기 하나 개의 파일.

성능을 최대화하려면 비동기/중복 입출력을 사용하여 이전 비트를 처리하는 동안 다음 비트의 이미지 데이터를 가져 오는 것이 좋습니다. 당신이 Windows에서 개발하는 경우

이 당신에게 중복 일을 시작을 줄 수있는 I/O : 당신이 당신의 병목 현상이있는 경우 당신이 알아낼 수 병렬에서 I/O를 수행되면 http://msdn.microsoft.com/en-us/library/ms686358%28v=vs.85%29.aspx

입출력 또는 처리 중. 최적화 방법은 여러 가지가 있습니다.

0

@Guy : 대답 외에도 메모리 매핑 된 파일에 대해 언급해야합니다. 두 접근법 중 가장 좋은 부분을 가지고 있습니다. 그러나 70Mb를 읽으려면 약 1 초가 걸리기 때문에 문제는 다른 곳에서 발생합니다.

코어 캐시의 일관성으로 인해 발생할 수 있습니다. 나는 이것에 대해 많이 알지는 못하지만, 동시에 두 개의 쓰레드가 같은 메모리 페이지 (또는 더 나쁜 것은 같은 캐시 라인)에 쓰기 액세스를한다면, 캐시는 동기화되어야한다. 한 번에 전체 이미지를 읽으면 모든 처리 스레드가 동시에 이미지를 처리합니다. 결과를 가까운 메모리 주소에 기록합니까? 이미지를 한 줄씩 읽는 경우, I/O가 완료 될 때까지 기다리는 데 약간의 시간이 소요되므로 너무 자주 발생하지는 않습니다.

관련 문제