2017-04-22 61 views
6

Mam dość program, aby pokazać wydajność 2 podobnych programów, oba używa 2 wątków do obliczeń. Różnica rdzeń jest to, że wykorzystuje zmienną globalną, inny używa „nowy” obiekt, jak poniżej:C++ przy użyciu zmiennej globalnej pokazuje 100% wolniej niż wskaźnik, podczas korzystania z pthread?

#include<pthread.h> 
#include<stdlib.h> 
struct M{ 
    long a; 
    long b; 
}obj; 
size_t count=2000000000; 
void* addx(void*args){ 
    long*pl=(long*)args; 
    for(size_t i=0;i<count;++i) 
     (*pl)*=i; 
    return NULL; 
} 
int main(int argc,char*argv[]){ 
    pthread_t tid[2]; 
    pthread_create(&tid[0],NULL,addx,&obj.a); 
    pthread_create(&tid[1],NULL,addx,&obj.b); 
    pthread_join(tid[0],NULL); 
    pthread_join(tid[1],NULL); 
    return 0; 
} 

clang++ test03_threads.cpp -o test03_threads -lpthread -O2 && time ./test03_threads 

real 0m3.626s 
user 0m6.595s 
sys 0m0.009s 

Jest to dość wolno, potem zmodyfikowany OBJ być tworzone dynamicznie (spodziewałem się, że będzie jeszcze wolniej) :

#include<pthread.h> 
#include<stdlib.h> 
struct M{ 
    long a; 
    long b; 
}*obj;//difference 1 
size_t count=2000000000; 
void* addx(void*args){ 
    long*pl=(long*)args; 
    for(size_t i=0;i<count;++i) 
     (*pl)*=i; 
    return NULL; 
} 
int main(int argc,char*argv[]){ 
    obj=new M;//difference 2 
    pthread_t tid[2]; 
    pthread_create(&tid[0],NULL,addx,&obj->a);//difference 3 
    pthread_create(&tid[1],NULL,addx,&obj->b);//difference 4 
    pthread_join(tid[0],NULL); 
    pthread_join(tid[1],NULL); 
    delete obj;//difference 5 
    return 0; 
} 

clang++ test03_threads_new.cpp -o test03_threads_new -lpthread -O2 && time ./test03_threads_new 

real 0m1.880s 
user 0m3.745s 
sys 0m0.007s 

To zadziwiająco 100% szybciej niż poprzednie. Próbowałem też g ++ na Linuksie, ten sam wynik. Ale jak to wyjaśnić? Wiem, że jest zmienną globalną, ale * obiekt jest wciąż zmienną globalną, dynamicznie tworzoną. Jaka jest główna różnica?

+0

Nie można odtworzyć testu [test1] (http://ideone.com/jDOQ0b) (3.54s) i [test2] (http://ideone.com/C9R9ja) (3.55s). Również nie powinno się umieszczać '-O2' przed ścieżką .cpp? – VTT

+0

Może mieć coś wspólnego z fałszywym udostępnianiem, ale można by oczekiwać, że fałszywe udostępnianie będzie problemem w obu implementacjach. – Unimportant

+0

Czy Twoje pliki wykonywalne są 32- czy 64-bitowe? –

Odpowiedz

1

Myślę, że tak jest z powodu fałszywego udostępniania, jak sugeruje Nieważne.

Po co więc ta różnica, możesz zapytać?

Ze względu na zmienną count! Ponieważ jest to zmienna typu zmienna i size_t dla ciebie, kompilator nie może zoptymalizować go (ponieważ pl może wskazywać na count). Jeśli count byłby int, z powodu ścisłych reguł aliasingu, kompilator może je zoptymalizować (lub po prostu może to być const size_t).

Tak wygenerowany kod musi przeczytać count za każdym razem w pętli.

W pierwszym przykładzie, count i obj obie zmienne globalne, są one umieszczone blisko siebie. Istnieje więc duże prawdopodobieństwo, że linker umieści te zmienne w tej samej linii pamięci podręcznej. Napisanie do obj.a lub obj.b spowoduje unieważnienie linii pamięci podręcznej count. Zatem procesor musi zsynchronizować odczyty count.

W drugim przykładzie, obj jest przydzielany do sterty, jego adres będzie wystarczająco duży od count, więc nie będą zajmować tej samej linii pamięci podręcznej. Brak synchronizacji dla count.