2014-10-17 8 views
2

주로 멀티 코어 CPU에 쓰루 GPU 라이브러리를 사용하여 작성한 코드를 이식하는 데 관심이 있습니다. 고맙게도 the website은 추력 코드가 OpenMP/Intel TBB와 같은 스레딩 환경에서 사용될 수 있다고 말합니다.openmp에서 추진력 사용 : 실질적인 속도 향상 없음

최대 16 개의 MP 스레드를 지원할 수있는 컴퓨터를 사용하여 큰 배열을 정렬하기위한 간단한 코드를 작성했습니다. 크기의 임의의 배열을 정렬이 시스템에서 얻은

타이밍 16000000

STL 있습니다 : 1.47의
추력 (16 개 스레드) : 1.21의

거의 모든 속도 -이있는 것 같습니다 쪽으로. GPU와 마찬가지로 OpenMP를 사용하여 배열을 정렬하는 속도를 높이는 방법을 알고 싶습니다.

코드는 아래에 있습니다 (sort.cu 파일).

NVCC -O2 -o 정렬 sort.cu -Xcompiler -fopenmp -DTHRUST_DEVICE_SYSTEM = THRUST_DEVICE_BACKEND_OMP -lgomp

NVCC 버전이 사용되는 스러스트 라이브러리 버전 5.5 V1 이며 다음과 같이 편집을 실시 하였다. 7.0

+0

clock()을 사용하지 말고'omp_get_wtime()'을 사용하십시오. 정렬은 내가 본 것을 의미하지만, nlog (n)이기 때문에 연산은 메모리 대역폭에 제한되어 있으므로 여러 개의 빠른 코어에서 많은 이점을 얻을 수 없다고 생각합니다. "코어"속도와 메모리 속도 간의 비율이 훨씬 낮기 때문에 GPU (또는 XeonPhi)의 상황은 다릅니다. –

답변

2

device backend refers to the behavior of operations performed on a thrust::device_vector 또는 유사한 참조 번호. 추력은 호스트 포인터로 전달하는 배열/포인터를 해석하고 장치 백엔드 설정의 영향을받지 않는 호스트 기반 작업을 수행합니다.

이 문제를 해결하는 방법에는 여러 가지가 있습니다. 디바이스 백엔드 문서를 읽으면 일반 예제와 omp 특정 예제를 찾을 수 있습니다. 내 생각에 코드와 함께 원하는 동작 (OMP 사용)을 가져야하는 다른 host backend을 지정할 수도 있습니다.

이 문제를 해결하면 예상치 못한 결과가 발생할 수 있습니다. 추력은 배열을 빠르게 정렬하지만 매우 긴 실행 시간을보고합니다. 나는 이것이 (리눅스상의 어쨌든) the clock() function being affected by the number of OMP threads in use에 달려 있다고 생각한다.

다음 코드/샘플 실행에는 해결 된 문제가 있으며 4 스레드에 대해 3 배 속도 향상을 제공합니다.

$ cat t592.cu 
#include <iostream> 
#include <iomanip> 
#include <cmath> 
#include <cstdlib> 
#include <stdio.h> 
#include <algorithm> 
#include <ctime> 
#include <sys/time.h> 
#include <time.h> 
#include <thrust/device_ptr.h> 
#include <thrust/sort.h> 

int main(int argc, char *argv[]) 
{ 
    int N = 16000000; 
    double* myarr = new double[N]; 

    for (int i = 0; i < N; ++i) 
    { 
     myarr[i] = (1.0*rand())/RAND_MAX; 
    } 
    std::cout << "-------------\n"; 

    timeval t1, t2; 
    gettimeofday(&t1, NULL); 
    std::sort(myarr,myarr+N); 
    gettimeofday(&t2, NULL); 
    float et = (((t2.tv_sec*1000000)+t2.tv_usec)-((t1.tv_sec*1000000)+t1.tv_usec))/float(1000000); 

    std::cout << "Time taken for sorting the array with STL is " << et << std::endl;; 

    //-------------------------------------------- 

    srand(1); 
    for (int i = 0; i < N; ++i) 
    { 
     myarr[i] = (1.0*rand())/RAND_MAX; 
     //std::cout << myarr[i] << std::endl; 
    } 
    thrust::device_ptr<double> darr = thrust::device_pointer_cast<double>(myarr); 
    gettimeofday(&t1, NULL); 
    thrust::sort(darr,darr+N); 
    gettimeofday(&t2, NULL); 
    et = (((t2.tv_sec*1000000)+t2.tv_usec)-((t1.tv_sec*1000000)+t1.tv_usec))/float(1000000); 

    std::cout << "------------------\n"; 


    std::cout << "Time taken for sorting the array with Thrust is " << et << std::endl ; 
    return 0; 
} 

$ nvcc -O2 -o t592 t592.cu -Xcompiler -fopenmp -DTHRUST_DEVICE_SYSTEM=THRUST_DEVICE_BACKEND_OMP -lgomp 
$ OMP_NUM_THREADS=4 ./t592 
------------- 
Time taken for sorting the array with STL is 1.31956 
------------------ 
Time taken for sorting the array with Thrust is 0.468176 
$ 

귀하의 마일리지는 다를 수 있습니다. 특히, 4 스레드 이상으로 올라가면 어떤 개선도 보이지 않을 수도 있습니다. OMP 코드가 특정 수의 스레드 이상으로 확장되지 못하도록하는 여러 가지 요인이있을 수 있습니다. 정렬은 일반적으로 메모리 바운드 알고리즘 인 경향이 있으므로 메모리 하위 시스템이 포화 상태가 될 때까지 증가를 관찰 한 다음 추가 코어를 추가로 증가시키지 않을 것입니다. 시스템에 따라 OMP 스타일의 멀티 스레딩에서 어떤 개선점도 보이지 않을 수도 있습니다.

+0

'nlog (n)'연산을 정렬하지 않으므로 메모리 대역폭이 제한되고 여러 개의 고속 코어 (단일 소켓 시스템에서)의 이점이 많이 없어야합니다. 하지만 네 결과가 내가 틀렸다는 것을 보여줄 것 같아. –

+0

실제로 메모리 대역폭은 성능이 약 4 코어까지 증가하지만 그 다음에는 수평이 될 가능성이 가장 큰 이유입니다. 최신 Intel Xeon은 단일 코어에서 발생하는 요청으로부터 메모리 버스를 포화시킬 수 없습니다. 단일 Xeon 소켓에서 사용 가능한 전체 메모리 대역폭을 사용하려면 여러 코어에서 요청을 발급 받아야합니다. 그러나 약 4 개의 코어가 단일 소켓에 연결된 버스를 포화 시키려면 충분해야합니다. 이 경우 제 프로세서는 인텔 Ivybridge Xeon이었습니다. –

+0

단일 소켓 시스템에서도 대역폭을 최대화하기 위해 다중 스레드가 필요하다는 데 동의합니다. [측정 - 메모리 대역폭 -에서 - 두 - 제품 - 중 - 두 배열] (http : // stackoverflow .com/questions/25179738/dot-product-of-two-array에서 측정 메모리 대역폭). 그러나 제 경험상 다중 스레드는 대역폭을 2 배 미만으로 증가시키고 예상보다 많은 3 배의 인수를 얻습니다. –