2014-02-19 2 views
4

C++ Amp로 응용 프로그램을 최적화하려고 할 때 다음과 같은 문제가 발생했습니다. 데이터가 전송됩니다. 나에게는 CPU에서 GPU로 데이터를 복사하는 데 문제가 없다 (애플리케이션의 초기 상태에서 할 수있는 것처럼). 더 나쁜 것은 C++ Amp 커널에 의해 계산 된 결과에 대한 빠른 액세스가 필요하기 때문에 GPU와 CPU 간의 병목 현상이 발생하는 것입니다. Windows 8.1에서 성능이 향상되었지만 Windows 7을 사용하고 있으며이를 변경하려고하지는 않습니다. 스테이징 어레이에 대해서는 읽었지만 어떻게 문제를 해결할 수 있을지 모르겠습니다. 호스트에 단일 부동 소수점 값을 반환해야하며 시간이 많이 소요되는 작업 인 것으로 보입니다. C++ Amp에서 GPU-CPU 데이터 전송 감소

float Subset::reduction_cascade(unsigned element_count, concurrency::array<float, 1>& a) 
{ 
static_assert(_tile_count > 0, "Tile count must be positive!"); 
//static_assert(IS_POWER_OF_2(_tile_size), "Tile size must be a positive integer power of two!"); 

assert(source.size() <= UINT_MAX); 
//unsigned element_count = static_cast<unsigned>(source.size()); 
assert(element_count != 0); // Cannot reduce an empty sequence. 

unsigned stride = _tile_size * _tile_count * 2; 

// Reduce tail elements. 
float tail_sum = 0.f; 
unsigned tail_length = element_count % stride; 
// Using arrays as a temporary memory. 
//concurrency::array<float, 1> a(element_count, source.begin()); 
concurrency::array<float, 1> a_partial_result(_tile_count); 

concurrency::parallel_for_each(concurrency::extent<1>(_tile_count * _tile_size).tile<_tile_size>(), [=, &a, &a_partial_result] (concurrency::tiled_index<_tile_size> tidx) restrict(amp) 
{ 
    // Use tile_static as a scratchpad memory. 
    tile_static float tile_data[_tile_size]; 

    unsigned local_idx = tidx.local[0]; 

    // Reduce data strides of twice the tile size into tile_static memory. 
    unsigned input_idx = (tidx.tile[0] * 2 * _tile_size) + local_idx; 
    tile_data[local_idx] = 0; 
    do 
    { 
     tile_data[local_idx] += a[input_idx] + a[input_idx + _tile_size]; 
     input_idx += stride; 
    } while (input_idx < element_count); 

    tidx.barrier.wait(); 

    // Reduce to the tile result using multiple threads. 
    for (unsigned stride = _tile_size/2; stride > 0; stride /= 2) 
    { 
     if (local_idx < stride) 
     { 
      tile_data[local_idx] += tile_data[local_idx + stride]; 
     } 

     tidx.barrier.wait(); 
    } 

    // Store the tile result in the global memory. 
    if (local_idx == 0) 
    { 
     a_partial_result[tidx.tile[0]] = tile_data[0]; 
    } 
}); 

// Reduce results from all tiles on the CPU. 
std::vector<float> v_partial_result(_tile_count); 
copy(a_partial_result, v_partial_result.begin()); 
return std::accumulate(v_partial_result.begin(), v_partial_result.end(), tail_sum); 
} 

내가 가장 시간이 많이 걸리는 작업 위의 예에서 copy(a_partial_result, v_partial_result.begin()); 것을 확인. 나는 더 나은 접근법을 찾고있다.

+1

데이터 복사본과 코드의 계산 부분을 어떻게 타이밍을 맞추고 계십니까? C++ AMP 호출은 비동기식이며, DMA 버퍼에 항목을 대기시키고 필요한 경우에만 차단합니다. 타이밍에 대한 자세한 내용은 다음 답변을 참조하십시오. http://stackoverflow.com/questions/13936994/copy-data-from-gpu-to-cpu/14013053#14013053 –

+0

타이밍이 같아 타이밍이 맞지 않습니다. -parrallel 방법. copy() 메소드를 주석 처리했을 때, 800-900 ms에서 300 ms까지 증가했다. –

+0

@up 복사 기능을 주석 처리 할 때 <200ms가됩니다. –

답변

1

그래서 나는 여기에 뭔가가 있다고 생각합니다. 코드가 기반이되는 원본 샘플을 실행 해 보셨습니까? 이것은 available on CodePlex입니다.

샘플 솔루션을로드하고 릴리스 모드에서 축소 프로젝트를 작성한 다음 디버거를 연결하지 않고 실행합니다. 이런 출력을 보게 될 것입니다.

Running kernels with 16777216 elements, 65536 KB of data ... 
Tile size:  512 
Tile count: 128 
Using device : NVIDIA GeForce GTX 570 

                  Total : Calc 

SUCCESS: Overhead           0.03 : 0.00 (ms) 
SUCCESS: CPU sequential          9.48 : 9.45 (ms) 
SUCCESS: CPU parallel          5.92 : 5.89 (ms) 
SUCCESS: C++ AMP simple model        25.34 : 3.19 (ms) 
SUCCESS: C++ AMP simple model using array_view    62.09 : 20.61 (ms) 
SUCCESS: C++ AMP simple model optimized     25.24 : 1.81 (ms) 
SUCCESS: C++ AMP tiled model        29.70 : 7.27 (ms) 
SUCCESS: C++ AMP tiled model & shared memory    30.40 : 7.56 (ms) 
SUCCESS: C++ AMP tiled model & minimized divergence  25.21 : 5.77 (ms) 
SUCCESS: C++ AMP tiled model & no bank conflicts   25.52 : 3.92 (ms) 
SUCCESS: C++ AMP tiled model & reduced stalled threads  21.25 : 2.03 (ms) 
SUCCESS: C++ AMP tiled model & unrolling     22.94 : 1.55 (ms) 
SUCCESS: C++ AMP cascading reduction      20.17 : 0.92 (ms) 
SUCCESS: C++ AMP cascading reduction & unrolling   24.01 : 1.20 (ms) 

예를 들어 코드 작성 시간이 가까워지면 어느 곳에서도 사용하지 않는 점에 유의하십시오. CPU가 더 빨라지고 데이터 복사 시간이 큰 기여 요인이라고 말하는 것은 공평합니다.

이것은 예상됩니다. GPU를 효과적으로 사용하려면 축소와 같은 작업을 GPU로 이동해야합니다. 복사 오버 헤드를 보충하기 위해 상당한 양의 계산을 이동해야합니다. 고려해야 할

몇 가지 : 당신과 함께 어떻게됩니까

  • 이는 CodePlex에서 샘플을 실행?
  • 최적화가 활성화 된 릴리스 빌드를 실행하고 있습니까?
  • WARP (소프트웨어 에뮬레이터) 가속기가 아닌 실제 GPU 하드웨어에서 실행되고 있습니까?

사용하고있는 하드웨어

  • 도움이 될 것입니다 일부 자세한 내용은?
  • 입력 데이터와 부분 결과 배열의 크기가 얼마나 큰 데이터 세트입니까?
+1

도움이 되었습니까? 아니면 아직도 느린 복사본이 있습니까? –

+0

예, 많은 도움이되었습니다. 내가 실행하고있는 테스트는 밀리 초가 아니라 마이크로 초 (microseconds)로 측정된다는 것이 밝혀졌습니다. 그것이 사실이었습니다. 두 가지 방법 (회선 계산 및 또 다른 매우 간단한 수학적 방정식)을 최적화하고 싶습니다. CPU의이 수학 방정식은 매우 빠릅니다 (약 50 마이크로 초 ~ = 0.05 밀리 초). 동시성 :: 배열 <...>에서 하나의 플로트를 CPU에 복사하는 데는 0.05ms가 걸리므로 적어도 0.9ms라고 생각합니다. 따라서 값을 복사하면 CPU 가속화 연산이 10 배 이상 느려집니다. 아니면 내가 틀렸어? –

관련 문제