2017-10-16 8 views
1

다음 코드는보다 1 개 스레드와 더 좋은 성능을 가진 느린 2 (4 개 스레드를 사용하는 것처럼, 속도 제공) : 내 노트북에2 개 스레드

#include <stdlib.h> 
#include <stdio.h> 
#include <omp.h> 

int main(int argc, char **argv) { 
    int n = atoi(argv[1]); 
    int num_threads = atoi(argv[2]); 
    omp_set_num_threads(num_threads); 

    unsigned int *seeds = malloc(num_threads * sizeof(unsigned int)); 
    for (int i = 0; i < num_threads; ++i) { 
    seeds[i] = 42 + i; 
    } 

    unsigned long long sum = 0; 
    double begin_time = omp_get_wtime(); 
    #pragma omp parallel 
    { 
    unsigned int *seedp = &seeds[omp_get_thread_num()]; 
    #pragma omp for reduction(+ : sum) 
    for (int i = 0; i < n; ++i) { 
     sum += rand_r(seedp); 
    } 
    } 
    double end_time = omp_get_wtime(); 

    printf("%fs\n", end_time - begin_time); 
    free(seeds); 
    return EXIT_SUCCESS; 
} 

(2 코어

$ gcc -fopenmp test.c && ./a.out 100000000 1 
0.821497s 
$ gcc -fopenmp test.c && ./a.out 100000000 2 
1.096394s 
$ gcc -fopenmp test.c && ./a.out 100000000 3 
0.933494s 
$ gcc -fopenmp test.c && ./a.out 100000000 4 
0.748038s 

문제는 drand48_r는 차이가 동적 스케줄링은 상황이 더 악화하지 않습니다 제공, 감소하지 않고 계속 : HT 나는 다음과 같은 결과를 얻을 수)를 활성화. 그러나 루프의 본문을 무작위로 연결되지 않은 무언가로 교체하면 i. 이자형. sum += *seedp + i;, 모든 것이 예상대로 작동합니다.

답변

3

이것은 허위 공유의 교과서 예제입니다. 각 스레드가 하나의 요소를 취하는 시드 배열을 사용하면 논리적으로 사적인 변수가 물리적으로 서로의 메모리 옆에 위치하게됩니다. 따라서 모두 동일한 캐시 라인에 있습니다. 즉, 스레드가 다른 스레드의 시드를 수정하려고 시도하지는 않지만 캐시 라인 자체는 각 반복마다 각 스레드에 의해 수정됩니다. 그리고 실제 문제는 시스템이 캐시 일관성에 대한 변수 수정을 감지 할 수 없으며 캐시 라인 수정 만 감지한다는 것입니다. 따라서 각 스레드의 반복마다 캐시 라인은 다른 스레드에 의해 수정되었으며 더 이상 시스템의 관점에서 유효하지 않습니다. 메모리에서 다시로드해야합니다 (여기서는 공유 L3 캐시에서 발생). 코드 속도가 느려집니다.

#include <stdlib.h> 
#include <stdio.h> 
#include <omp.h> 

int main(int argc, char **argv) { 
    int n = atoi(argv[1]); 
    int num_threads = atoi(argv[2]); 
    omp_set_num_threads(num_threads); 

    unsigned long long sum = 0; 
    double begin_time = omp_get_wtime(); 
    #pragma omp parallel 
    { 
    unsigned int seed = 42 + omp_get_thread_num(); 
    #pragma omp for reduction(+ : sum) 
    for (int i = 0; i < n; ++i) { 
     sum += rand_r(&seed); 
    } 
    } 
    double end_time = omp_get_wtime(); 

    printf("%fs\n", end_time - begin_time); 
    return EXIT_SUCCESS; 
} 
+0

아 :

대신 (테스트하지)이 하나를 시도! 나는 rand_r이 실제로 주어진 매개 변수를 수정하는 것을 생략했다. 좋은 대답 :) – Harald