2013-11-25 2 views
0

저는 현재 추력 라이브러리를 사용하여 GPU에서 벡터의 합계와 최대 감소를 수행하는 CUDA 어플리케이션을 보유하고 있습니다. 특정 벡터 길이의 경우 벡터를 호스트로 보내고 C++의 합계 및 최대 감소를 계산하면 훨씬 더 빠릅니다.gcc-via-nvcc가이 합계와 최대 감소를 벡터화합니까?

합계와 최대 감소는 호스트에서 벡터화 할 수 있어야합니다. 호스트의 메모리는 선형/연속적이며 컴파일러는 이것을 지원합니다 (GCC). 주어진 타이밍을 감안할 때, 컴파일러가 코드를 벡터화하는 것 같지만 어떻게 확인할 수 있습니까? 컴파일러 최적화에 대한 경험이 없지만 사용할 수있는 일부 pragma 문이 있다는 것을 알고 있습니다. 인터넷 검색으로 정보를 거의 찾을 수 없습니다. 또한 이해할 수 없으므로 확인을 위해 어셈블리를 파헤 치지 않을 것입니다. 컴파일러 설정 (GCC 또는 NVCC에서)을 사용하여 호스트에서 벡터화를 강제 실행하거나 코드가 벡터화되었다는 확인을 찾을 수 있습니까?

합계와 최대 감소에 대해 작성한 함수는 다음과 같습니다. nvcc 컴파일러는 함수가 CUDA 코드를 포함하기 때문에 궁극적으로이를 컴파일합니다.

void calc_vector_max_host(double& maxval, double *const vec_h, const double *const vec_d, int len) 
{ 
    //copy device vector to host 
    gpuErrchk(cudaMemcpy(vec_h, vec_d, len*sizeof(double), cudaMemcpyDeviceToHost)); 

    //vectorized? max 
    maxval = *vec_h; 
    double* temp = vec_h; 
    for(int i = 1; i < len; i++, temp++) 
    { 
     if(*temp > maxval) 
     { 
      maxval = *temp; 
     } 
    } 
} 

void calc_vector_sum_host(double& sum, double *const vec_h, const double *const vec_d, int len) 
{ 
    //copy device vector to host 
    gpuErrchk(cudaMemcpy(vec_h, vec_d, len*sizeof(double), cudaMemcpyDeviceToHost)); 

    //vectorized? sum 
    sum = 0.0; 
    double* temp = vec_h; 
    for(int i = 0; i < len; i++, temp++) 
    { 
     sum += *temp; 
    } 
} 

편집 : 다음은 gcc가 자동 벡터화하는 데 필요한 수정 사항입니다. 주석에 나열된 컴파일러 옵션도 필요했습니다.

void calc_vector_max_host(double& maxval, double *const __restrict__ vec_h, const double *const __restrict__ vec_d, int len) 
{ 
    //copy device vector to host 
    gpuErrchk(cudaMemcpy(vec_h, vec_d, len*sizeof(double), cudaMemcpyDeviceToHost)); 

    //vectorized? max 
    double local_maxval = vec_h[0]; 
    for(int i = 1; i < len; i++) 
    { 
     double val = vec_h[i]; 
     if(val > local_maxval) 
     { 
      local_maxval = val; 
     } 
    } 
    maxval = local_maxval; 
} 

void calc_vector_sum_host(double& sum, double *const __restrict__ vec_h, const double *const vec_d, int len) 
{ 
    //copy device vector to host 
    gpuErrchk(cudaMemcpy(vec_h, vec_d, len*sizeof(double), cudaMemcpyDeviceToHost)); 

    //vectorized? sum 
    double local_sum = 0.0; 
    for(int i = 0; i < len; i++) 
    { 
     local_sum += vec_h[i]; 
    } 
    sum = local_sum; 
} 

답변

2

가장 중요한 점은 nvcc가 컴파일러가 아니라는 것입니다. 컴파일러 드라이버입니다. 호스트 컴파일러를 사용하여 실제 GPU 코드를 분리하고 GPU 도구 체인에 전달하는 몇 가지 사용자 정의 사전 처리 도구와 함께 컴파일을 사용하면됩니다. 일반적인 프로그램의 작은 부분 만 GPU 컴파일러와 어셈블러에 의해 처리됩니다. 나머지 빌드는 호스트 컴파일러와 링커에서 직접 수행됩니다.

게시 한 모든 코드는 gcc에 의해 컴파일되며 (nvcc를 사용하지 않고 직접 컴파일 할 수 있음) nvcc에는 호스트 컴파일 궤도에 원하는 옵션을 전달하는 데 사용할 수있는 -Xcompiler 옵션이 있습니다. 벡터화를 위해 gcc의 버전이 지원하는 here 옵션 중 하나를 전달할 수 있습니다. 또한 SSE 스타일 내장 함수를 직접 사용하여 컴파일러의 작업을 쉽게 할 수 있습니다.

벡터화가 호스트 코드에서 이미 발생하는지 확인하려면 objdump/otool과 같은 것을 사용하십시오. Linux 또는 OS X를 사용하여, 당신은 말하지 않았다). 컴파일러가 생성 한 코드의 디스 어셈블리를 볼 수 있으며 벡터화 된 명령어가 있으면 즉시 질문에 응답합니다.

마지막으로, nvcc가 요즘 꽤 좋은 documentation을 가질 가치가 없습니다. 그리고 이것에 대한 답변과 nvcc에 익숙해 져서 nvcc에 관한 모든 다른 질문을 찾을 수 있습니다.

+0

몇 가지 의견은 기록 용으로 만 제공됩니다. gcc 옵션 웹 페이지에 대한 링크가 도움이되었습니다. 결국 게시 된 코드는 자동 벡터 라이징이 아니 었습니다. 이것은 일부 누락 된 컴파일러 옵션 때문이었습니다. 특히, -xcompiler 플래그를 사용하여 -ftree-vectorize -msse2와 -fast-math를 모두 전달해야만 벡터화 할 코드를 얻을 수 있었고 ftree-vectorize-verbose = 6을 사용하여 자동 벡터화 컴파일러 출력을 얻을 수있었습니다. 나는 리눅스를 사용 중이며 objdump를 시도했지만이 문제에 대해 어셈블리 덤프를 찾지 못했습니다. 또한 편집 된 기능에 몇 가지 문제가있었습니다. –