Używanie różnych strumieni dla jądra CUDA umożliwia równoczesne wykonywanie jądra. Zatem strumienie n
na strumieniach n
mogłyby teoretycznie działać jednocześnie, jeśli pasują do sprzętu, prawda?Równoczesne wykonywanie jądra CUDA z wieloma jądrami na strumień
Teraz mam do czynienia z następującym problemem: Nie ma n
odrębnych jąder, ale n*m
gdzie jądra m
muszą być wykonane w kolejności. Na przykład n=2
i m=3
doprowadzi do następującego schematu wykonania strumieni:
Stream 1: <<<Kernel 0.1>>> <<<Kernel 1.1>>> <<<Kernel 2.1>>>
Stream 2: <<<Kernel 0.2>>> <<<Kernel 1.2>>> <<<Kernel 2.2>>>
My to naiwny założenie, że ziarna i x.0 Y.1 powinien wykonywać jednocześnie (z teoretycznego punktu widzenia) lub co najmniej nie kolejno (z praktycznego punktu widzenia). Ale moje pomiary pokazują mi, że tak nie jest i wydaje się, że wykonywane jest kolejne wykonanie (tj. K0.0, K1.0, K2.0, K0.1, K1.1, K2.1). Samo jądro jest bardzo małe, więc jednoczesne wykonywanie nie powinno stanowić problemu.
Teraz moim podejściem byłoby dokonanie pewnego rodzaju wysyłki, aby upewnić się, że jądra są umieszczane w układzie przeplatanym w harmonogramie na GPU. Ale gdy mamy do czynienia z dużą liczbą strumieni/ziaren, może to przynieść więcej szkody niż pożytku.
W porządku, przechodząc od razu do punktu: Jakie byłoby odpowiednie (lub przynajmniej odmienne) podejście do rozwiązania tej sytuacji?
Edytuj: Pomiary są wykonywane przy użyciu zdarzeń CUDA. Zmierzyłem czas potrzebny do pełnego rozwiązania obliczeń, mi. GPU musi obliczyć wszystkie jądra n * m
. Założeniem jest: W przypadku równoczesnego uruchamiania jądra czas wykonania jest z grubsza (idealnie) czas potrzebny do wykonania wszystkich ziaren w kolejności, przy czym musi istnieć możliwość jednoczesnego wykonywania dwóch lub większej liczby ziaren. Zapewniam to, używając teraz tylko dwóch różnych strumieni.
Mogę zmierzyć wyraźną różnicę w zakresie czasów wykonania między wykorzystaniem strumieni zgodnie z opisem i wysyłaniem przeplatanych jąder, i. E .:
Loop: i = 0 to m
EnqueueKernel(Kernel i.1, Stream 1)
EnqueueKernel(Kernel i.2, Stream 2)
porównaniu
Loop: i = 1 to n
Loop: j = 0 to m
EnqueueKernel(Kernel j.i, Stream i)
ostatnie prowadzi do dłuższych okresów pracy.
Edytuj nr 2: Zmieniono numery Strumienia na początek o 1 (zamiast 0, patrz komentarze poniżej).
Edit # 3: Sprzęt jest NVIDIA Tesla M2090 (tj Fermi, obliczyć zdolność 2.0)
Prawdopodobnie potrzebujesz pewnych operacji podstawowych synchronizacji strumienia, aby wymusić żądaną kolejność wykonywania. Ale czy mógłbyś nieco poszerzyć swoje pomiary w pytaniu i czy możesz również potwierdzić, że kiedy piszesz "Strumień 0", nie oznacza to dosłownie strumienia 0 CUDA? – talonmies
Wyjaśniłem pomiar (przynajmniej mam taką nadzieję). W przypadku strumieni mam na myśli instancje 'cudaStream_t' opisane w [CUDA C Programming Guide] (http://developer.download.nvidia.com/compute/DevZone/docs/html/C/doc/CUDA_C_Programming_Guide.pdf), sekcja 3.2.5 (Asynchronous Concurrent Execution). –
Być może źle zrozumiałeś to, o co prosiłem - mam na myśli jeden z twoich strumieni CUDA 0, ponieważ strumień 0 (strumień domyślny) jest synchroniczny. – talonmies