2013-08-26 11 views
5

Przenoszę kod do okien i stwierdzam, że wątki są bardzo powolne. Zadanie trwa 300 sekund w oknach (z dwoma xeon E5-2670 8 core 2.6ghz = 16 core) i 3.5 sekund na linuxie (xeon E5-1607 4 core 3ghz). Korzystanie z ekspresu vs2012.Przenoszenie wątków do okien. Sekcje krytyczne są bardzo powolne.

Mam 32 wątki wszystkich wywoływanie EnterCriticalSection(), popping 80 bajtów std :: stos, LeaveCriticalSection i wykonanie niektórych pracy (łącznie 250k zadań).

Przed i po każdym krytycznym wywołaniu sekcji drukuję identyfikator wątku i aktualny czas.

  • Czas oczekiwania na blokadę jeden wątek jest ~ 160ms
  • pop pracę ze stosu zajmuje ~ 3ms
  • Wywołanie urlop trwa ~ 3ms
  • Zadanie wykonuje ~ 1ms

(w przybliżeniu to samo dla debugowania/wydania, debugowanie zajmuje trochę dłużej. Chciałbym móc poprawnie profilować kod: P)

Komentowanie wywołanie zadania sprawia, że ​​cały proces trwa 2 sekundy (wciąż więcej niż linux).

Próbowałem już zarówno queryperformancecounter i timeGetTime, oba dają w przybliżeniu taki sam wynik.

AFAIK zadanie nigdy nie wykonuje żadnych połączeń synchronizacyjnych, ale nie mogę wytłumaczyć spowolnienia, chyba że to zrobi.

Nie mam pojęcia, dlaczego kopiowanie ze stosu i wywoływanie muzyki pop trwa tak długo. Inną bardzo mylącą rzeczą jest to, że wywołanie metody leave() trwa tak długo.

Czy ktoś może spekulować, dlaczego działa tak wolno?

Nie sądziłbym, że różnica w procesorze dałaby 100-krotną różnicę wydajności, ale czy w ogóle mogła być związana z dwoma procesorami? (konieczność synchronizacji pomiędzy oddzielnymi procesorami niż wewnętrznymi rdzeniami).

Nawiasem mówiąc, jestem świadomy std :: thread, ale chcę, aby mój kod biblioteki działał z pre C++ 11.

edit

//in a while(hasJobs) loop... 

EVENT qwe1 = {"lock", timeGetTime(), id}; 
events.push_back(qwe1); 

scene->jobMutex.lock(); 

EVENT qwe2 = {"getjob", timeGetTime(), id}; 
events.push_back(qwe2); 

hasJobs = !scene->jobs.empty(); 
if (hasJobs) 
{ 
    job = scene->jobs.front(); 
    scene->jobs.pop(); 
} 

EVENT qwe3 = {"gotjob", timeGetTime(), id}; 
events.push_back(qwe3); 

scene->jobMutex.unlock(); 

EVENT qwe4 = {"unlock", timeGetTime(), id}; 
events.push_back(qwe4); 

if (hasJobs) 
    scene->performJob(job); 

a klasa mutex, z linux #ifdef rzeczy usunięte ...

CRITICAL_SECTION mutex; 

... 

Mutex::Mutex() 
{ 
    InitializeCriticalSection(&mutex); 
} 
Mutex::~Mutex() 
{ 
    DeleteCriticalSection(&mutex); 
} 
void Mutex::lock() 
{ 
    EnterCriticalSection(&mutex); 
} 
void Mutex::unlock() 
{ 
    LeaveCriticalSection(&mutex); 
} 
+0

Czego używałeś w Linuksie? Czy chronisz tylko dostęp do std :: stack z krytycznymi sekcjami? – xanatos

+2

Gdzie drukujesz identyfikator wątku i bieżący czas? – avakar

+0

Wybierz język. I wydaje się to dziwne. To na pewno * brzmi * wystarczająco proste, aby [SSCCE] (http://www.sscce.org) było wykonalne. Zgadzam się z tym, że moje doświadczenie w Windowsie jest nieco słabsze w porównaniu do porównywalnie wyposażonej dystrybucji Linuksa, ale wydaje mi się, że jest to dość szeroka przepaść. – WhozCraig

Odpowiedz

0

Wydaje się swoim Windows wątki stoją super-twierdzenia. Wydają się być całkowicie serializowane. Masz około 7 ms całkowitego czasu przetwarzania w sekcji krytycznej i 32 wątków. Jeśli wszystkie wątki zostaną umieszczone w kolejce na zamku, ostatni wątek w kolejce nie będzie działał, dopóki nie spocznie około 217 ms. To nie jest zbyt daleko od 160ms obserwowanego czasu oczekiwania.

Tak więc, jeśli nici nie mają nic więcej do roboty, niż wejście do sekcji krytycznej, wykonaj pracę, a następnie opuść sekcję krytyczną, takie zachowanie się spodziewam.

Postaraj się scharakteryzować zachowanie profilowania linuxa i sprawdź, czy zachowanie programu jest naprawdę, a porównanie jabłek z jabłkami.

+0

Zgadzam się, wydaje się, że działają one luźno sekwencyjnie (sporadycznie występuje niewielka różnica w kolejności wykonywania). Nie ma kodu, który by je serializował, a 80-bajtowa kopia i pop powinny być WAY WAY szybsze niż moja praca. To, co naprawdę nie ma sensu, to czas potrzebny na połączenie się z LeftCriticalSection. Wierzę, że serializacja jest symptomem podstawowej kwestii z krytycznymi sekcjami. Sprawdzę podwójnie rywalizację na linuxie. – jozxyqk

1

Okna CRITICAL_SECTION obracają się w ciasnej pętli przy pierwszym wejściu. Nie zawiesza wątku, który wywołał EnterCriticalSection, chyba że upłynął znaczny okres w pętli spinu. Zatem posiadanie 32 wątków rywalizujących o tę samą sekcję krytyczną spowoduje spalenie i zmarnowanie wielu cykli procesora. Wypróbuj zamiast tego muteksa (patrz CreateMutex).

+3

[Podejrzewam to samo] (http://stackoverflow.com/questions/18442574/porting-threads-to-windows-critical-sections-are-very-slow#comment27103010_18442574), ale nie dostosowałbym liczby obrotów bardziej odpowiednie/szybsze niż przy użyciu muteksu? – dyp

Powiązane problemy