"1 블록 x 32 스레드"구성으로 시작하려는 커널이 있습니다. 병렬성을 높이려면 "1 블록 x 32 스레드"보다 더 큰 "작업 패키지"를 실행하는 대신 여러 스트림을 시작하고 싶습니다. 데이터가 네트워크에서 오는 프로그램에서 GPU를 사용하고 싶습니다. 더 큰 "작업 패키지"가 나올 때까지 기다릴 필요가 없습니다. 실제 코드를 훨씬 더 복잡하지만 (15 개 CPU의 스레드가 GPU를 사용) 간단하게 할여러 스레드 (스레드/블록 대신) 병렬 실행
Thread(i=0..14) {
- copy data Host -> GPU [cudaMemcpyAsync(.., stream i)]
- run kernel(stream i)
- copy data GPU -> Host [cudaMemcpyAsync(.., stream i)]
}
: 같은 코드입니다.
코드는 작동하지만 스트림이 예상대로 동시에 실행되지 않습니다. GTX 480에는 15 개의 SM이 있으며 각 SM에는 32 개의 쉐이더 프로세서가 있습니다. 커널을 15 번 시작하면 15 개의 스트림이 모두 병렬로 실행되지만, 그렇지는 않습니다. 저는 Nvidia Visual Profiler를 사용했으며 병렬로 실행되는 최대 5 개의 스트림이 있습니다. 종종 하나의 스트림 만 실행됩니다. 성능이 정말 안좋아.
"64 블록 x 1024 스레드"구성으로 최상의 결과를 얻었습니다. 대신 "32 블록 x 1024 스레드"구성을 사용하지만 두 개의 스트림이 서로 차례로 실행되고 성능이 떨어지면 Cuda Toolkit 5.5와 Ubuntu 12.04를 사용하고 있습니다.
누군가 이것이 왜 그런지 설명하고 배경 정보를 줄 수 있습니까? 더 새로운 GPU에서 더 잘 작동해야합니까? 데이터를 버퍼링하지 않으려는 시간에 비판적인 애플리케이션에서 GPU를 사용하는 가장 좋은 방법은 무엇입니까? 아마도 이것은 가능하지 않지만 해결책을 찾도록하는 기술을 찾고 있습니다.
뉴스
:는 좀 더 많은 연구를했다. 문제는 마지막 cudaMemcpyAsync (..) (GPU-> 호스트 복사) 호출입니다. 제거하면 모든 스트림이 동시에 실행됩니다. 나는 그 문제가 슬라이드 21의 http://on-demand.gputechconf.com/gtc-express/2011/presentations/StreamsAndConcurrencyWebinar.pdf에 삽화되어 있다고 생각한다. 그들은 페르미 (Fermi)에 2 개의 복사 대기열이 있다고 말하고 있지만 이것은 테슬라와 쿼드로 카드에 대해서만 유효하다. 문제는 GTX 480에 하나의 복사 대기열이 있고 모든 복사 명령 (호스트 -> GPU 및 GPU -> 호스트)이이 대기열에 들어 있다고 생각합니다. 모든 것이 non-blocking이며 첫 번째 스레드의 GPU-> 호스트 memcopy는 다른 스레드의 호스트 -> GPU memcopy 호출을 차단합니다. 여기에 일부 관찰 :
Thread(i=0..14) {
- copy data Host -> GPU [cudaMemcpyAsync(.., stream i)]
- run kernel(stream i)
}
-> 작품은 : 스트림을 동시에
Thread(i=0..14) {
- copy data Host -> GPU [cudaMemcpyAsync(.., stream i)]
- run kernel(stream i)
- sleep(10)
- copy data GPU -> Host [cudaMemcpyAsync(.., stream i)]
}
실행 -> 동작 : 스트림을 동시에 실행
Thread(i=0..14) {
- copy data Host -> GPU [cudaMemcpyAsync(.., stream i)]
- run kernel(stream i)
- cudaStreamSynchronize(stream i)
- copy data GPU -> Host [cudaMemcpyAsync(.., stream i)]
}
-> 작동하지 않습니다! 어쩌면 cudaStreamSynchronize가 복사 대기 행렬에 놓여 있습니까?
누군가이 문제에 대한 해결책을 알고 있습니까? 블로킹 커널 호출과 같은 것이 멋질 것입니다. 마지막 cudaMemcpyAsync() (GPU-> 장치)는 커널이 끝나면 호출되어야합니다.
Edit2가 : 첫 번째 스트림이 시작
Stream1:
------------
HostToGPU1
kernel1
GPUToHost1
Stream2:
------------
HostToGPU2
kernel2
GPUToHost2
: 우리는 2 개 스트림을 간단하게하기 위해 : 여기 예를 들어 내 문제를 명확히한다. HostToGPU1이 실행되면 kernel1이 시작되고 GPUToHost1이 호출됩니다. kernel1이 실행 중이기 때문에 GPUToHost1이 차단됩니다. 그 동안 Stream2가 시작됩니다.HostToGPU2가 호출되면 Cuda는 큐에 넣지 만 커널 1이 완료 될 때까지 GPUToHost1을 차단하기 때문에 실행할 수 없습니다. 현재로서는 데이터 전송이 없습니다. Cuda는 GPUToHost1을 기다립니다. 그래서 제 생각은 kernel1이 끝났을 때 GPUToHost1을 호출하는 것이 었습니다. GPUToHost1은 커널이 끝났을 때 호출되기 때문에이 연결은 절전 (..)과 함께 작동하는 이유입니다. CPU 스레드를 자동으로 차단하는 커널 실행은 멋지다. GPUToHost1이 대기열에서 차단되지 않습니다. (다른 경우에는 데이터 전송이 없지만 데이터 전송에는 시간이 많이 걸리지 않습니다.)
Windows 또는 Linux에 있습니까? –
우분투 12.04를 사용하고 있습니다. – user4811
CUDA [concurrent kernels sample] (http://docs.nvidia.com/cuda/cuda-samples/index.html#concurrent-kernels)을 실행하면 어떤 결과가 나타 납니까? (그것은/usr/local/cuda/samples/6_Advanced/concurrentKernels' 시스템에서 이미 사용 가능해야합니다.) 테스트의 결과로 질문을 편집 할 수 있습니까? –