Czy w programowaniu byłoby możliwe obciążenie procesora i GPU 100%?

43

To jest ogólne pytanie na temat, który uważam za interesujący jako gracz: wąskie gardła procesora / GPU i programowanie. Jeśli się nie mylę, doszedłem do wniosku, że zarówno CPU, jak i GPU obliczają różne rzeczy, ale ten jest lepszy w niektórych obliczeniach niż drugi ze względu na różnicę w architekturze. Na przykład łamanie skrótów lub wydobywanie kryptowalut wydaje się znacznie wydajniejsze na GPU niż na procesorach.

Zastanawiałem się więc: czy posiadanie karty graficznej przy obciążeniu 100%, a procesor przy 50% (na przykład) jest nieuniknione?

Lub ściślej: czy niektóre obliczenia, które zwykle wykonywane są przez GPU, mogą być wykonywane przez CPU, jeśli pierwszy jest obciążony w 100%, aby oba osiągnęły 100% obciążenia?

Szukałem trochę na ten temat, ale wróciłem z pustymi rękami. Myślę i mam nadzieję, że ma to swoje miejsce w tym podrozdziale i jestem otwarty na wszelkie dokumenty lub wykłady, które możesz mi dać!

MadWard
źródło
53
Zarówno procesor, jak i GPU mogą w nieskomplikowany sposób uruchamiać nieskończoną pętlę NO-OPs, co spowoduje obciążenie obu urządzeń w 100%.
Jörg W Mittag
17
Zgodnie z punktem @ Jörga, jedyną rzeczą mierzoną przez% procesora jest to, jaka część czasu nie jest poświęcana na oczekiwanie na inne procesory. 100% może być dobrą rzeczą, jeśli program jest wydajny, lub złą, jeśli program jest nieefektywny. Zbyt często ludzie koncentrują się na% procesora, jakby to była miara wydajności - nie jest.
Mike Dunlavey,
22
Oryginalny Crysis zrobił to dobrze.
CubicleSoft,
5
@MikeDunlavey przywołujesz dobry punkt. W samochodach nie mierzymy ich osiągów przez RPM, mierzymy prędkość.
Captain Man
1
@ JörgWMittag: Może procesor. Ale systemy operacyjne i procesory graficzne wstrzymują rozwiązywanie problemów, aby radzić sobie z nieskończonymi pętlami. Mianowicie, jeśli moduł cieniujący nie ukończy się w rozsądnym czasie, umiera, a procesor graficzny resetuje się.
Nicol Bolas,

Odpowiedzi:

62

Teoretycznie tak, ale praktycznie rzadko warto.

Zarówno procesory, jak i GPU są kompletne , więc każdy algorytm, który może być obliczony przez jeden, może być również obliczony przez drugi. Pytanie brzmi, jak szybko i jak wygodnie.

Podczas gdy GPU wyróżnia się wykonywaniem tych samych prostych obliczeń na wielu punktach danych dużego zestawu danych, procesor jest lepszy w bardziej złożonych algorytmach z dużą ilością rozgałęzień. Przy większości problemów różnica w wydajności między implementacjami procesora i GPU jest ogromna. Oznacza to, że użycie jednego do zabrania pracy drugiemu, gdy jest on przeciągany, tak naprawdę nie doprowadziłoby do zauważalnego wzrostu wydajności.

Jednak cena, którą musisz za to zapłacić, polega na tym, że musisz wszystko zaprogramować dwa razy, raz dla procesora i raz dla GPU. To ponad dwa razy więcej pracy, ponieważ będziesz musiał zaimplementować logikę przełączania i synchronizacji. Ta logika jest niezwykle trudna do przetestowania, ponieważ jej zachowanie zależy od bieżącego obciążenia. Spodziewaj się bardzo niejasnych i niemożliwych do odtworzenia błędów z tego wyczynu.

Philipp
źródło
1
Wspomniałeś, że przy większości problemów różnica wydajności między procesorem a implementacją GPU jest ogromna , jestem właściwie bardzo zainteresowany, w jakim stopniu idzie różnica w wydajności. Czy masz jakieś liczby lub artykuły na ten temat (na przykład na przykładzie renderowania tekstur 3D)? Dziękujemy za odpowiedź i poświęcony czas!
MadWard
2
Możesz dodać, że koszty synchronizacji między procesorem a GPU wiążą się z obniżeniem wydajności, więc ogólnie chcesz zminimalizować liczbę transferów między nimi. Ponadto naiwne dodawanie gałęzi dla „nie wykonuj elementów, na których CPU już pracował” nic by ci nie kupiło, ponieważ wątki GPU działają w trybie blokowania.
Ethan
3
@gardenhead Nic we wszechświecie nie obsługuje nieograniczonej rekurencji, ponieważ wszechświat ma skończony rozmiar i ma skończoną gęstość informacji. „Kompletność Turinga” systemu jest ogólnie dyskusją na temat tego, co byłoby możliwe przy usunięciu takich ograniczeń.
Random832
3
Nie mam wątpliwości, że współczesny procesor graficzny jest technicznie co najmniej tak samo kompletny jak Turing jak komputer z lat 80-tych ... jeśli jednak spróbujesz uruchomić ogólne algorytmy na GPU, zwykle przerodzi się w sekwencyjny procesor, który również nie będzie szybszy niż komputer z lat 80-tych, więc kompletność Turinga GPU jest w praktyce niewiele bardziej przydatna niż kompletność Turinga Brainfuck .
leftaroundabout
7
@leftaroundabout Nowoczesne układy GPU są w trywialny sposób kompletne jak każdy procesor . Kompletność Turinga nie ma nic wspólnego z: 1) wydajnością 2) czytelnością źródła. Procesory z lat 80. były tak blisko TC, że ma wszystko inne: albo były TC, albo nie były (ta druga opcja to nonsens).
Margaret Bloom,
36

Nie ma to związku z programowaniem gier. Niektóre kody naukowe mogą także wykorzystywać zarówno procesor graficzny, jak i procesor.

Dzięki starannemu i bolesnemu programowaniu, np. Przy użyciu OpenCL lub CUDA , możesz załadować zarówno GPU, jak i procesor prawie w 100%. Najprawdopodobniej będziesz musiał napisać różne fragmenty kodu dla GPU (tak zwany kod „jądra”) i dla procesora oraz trochę nudnego kodu kleju (zwłaszcza, aby wysłać do GPU skompilowany kod jądra).

Jednak kod byłby skomplikowany i prawdopodobnie musisz go dostroić do konkretnego sprzętu, na którym pracujesz, w szczególności dlatego, że transmisja danych między GPU a procesorem jest kosztowna.

Przeczytaj więcej o heterogenicznym przetwarzaniu .

Zobacz także OpenACC , obsługiwany przez najnowsze wersje GCC (np. GCC 6 w czerwcu 2016 r.)

Basile Starynkevitch
źródło
1
Masz rację, moje tagi i tytuł wprowadzały w błąd, usuwały gry i dodawały wydajność / optymalizację. Nie chodziło mi o to, że dotyczy wyłącznie gier, ale właśnie to zauważyłem. Pomyślałem, że to też musi być bardzo specyficzne dla sprzętu. Dziękujemy za odpowiedź i linki!
MadWard
3
To prawie kończy się na dwóch algorytmach. Próbowałem raz: cały obraz na raz dla GPU i wiele obrazów na raz dla CPU (w celu nadużycia dużej pamięci podręcznej). To jest naprawdę bolesne, szczególnie w utrzymaniu.
PTwr
11

Z punktu widzenia superkomputerów lepiej nie myśleć procentowo o obciążeniu CPU / GPU, ale raczej określić, ile operacji potrzebuje dany problem, a następnie porównać to z maksymalną wydajnością systemu.

Jeśli uzyskasz 100% wykorzystanie procesora, niekoniecznie oznacza to, że cała wydajność jest uzyskiwana z systemu. Procesory często mogą wykonywać wiele różnych rzeczy jednocześnie, powiedzmy podział i dodatek. Jeśli możesz rozpocząć podział wcześniej, możliwe, że może się on nakładać z dodatkiem. Komputer stacjonarny najprawdopodobniej ma jednostkę poza kolejnością, która zmieni kolejność instrukcji, aby skorzystać z takich nakładek. Lub jeśli masz następujący program:

if (expr1)
    expr2;
else
    expr3;

Procesor zmieniający kolejność spróbuje obliczyć trzy wyrażenia w tym samym czasie, a następnie wyrzucić wynik jednego z nich. To sprawia, że ​​ogólnie szybciej. Jeśli masz program blokujący i nie możesz zmienić kolejności, oznacza to, że korzystasz z mniejszej liczby linii procesora, ale prawdopodobnie nadal będzie wyświetlać 100%.

Następnie masz funkcje SIMD w procesorach, które są operacjami wektorowymi. To jest jak GPGPU-light w tym sensie, że zwykle masz tylko cztery lub osiem operacji w tym samym czasie, GPU robią jak 32 lub 64. Nadal musisz tego użyć, aby rozwinąć FLOPS.

Rzeczy takie jak fałszywe udostępnianie może prowadzić do dużych kosztów synchronizacji, które zwykle pojawiają się jako obciążenie jądra w Linuksie. Procesor jest w pełni wykorzystywany, ale nie masz zbyt dużej użytecznej przepustowości.

Zrobiłem trochę programowania na maszynie IBM Blue Gene / Q. Ma wiele poziomów hierarchii ( schemat przestarzałych Blue Gene / L ) i dlatego jest trudny do wydajnego programowania. Będziesz musiał użyć pełnej hierarchii do SIMD i SMT (Intel nazywa to HyperThreading), aby uzyskać wydajność.

A potem sieć często Cię ogranicza. Dlatego okazuje się, że szybszy jest czas (zegar ścienny), aby obliczyć rzeczy na wielu procesorach jednocześnie, zamiast komunikować je przez sieć. Spowoduje to większe obciążenie procesorów i przyspieszy działanie programu. Ale rzeczywista przepustowość programu nie jest tak dobra, jak się wydaje na podstawie liczb surowych.

Jeśli dodasz GPU do miksu, będzie jeszcze trudniej zorganizować to wszystko, aby uzyskać wydajność. To będzie jedna z rzeczy, które zacznę robić w mojej pracy magisterskiej QCD Lattice za kilka miesięcy.

Martin Ueding
źródło
1

Być może zainteresuje Cię silnik przeglądarki Servo opracowywany w Mozilla Research, a dokładniej jego Web Render (wideo) .

Chociaż dynamiczne przenoszenie zadań z procesora na procesor graficzny może być niepraktyczne, jak wspomniano w innych odpowiedziach (zwłaszcza @ Philipa), praktyczne może być wcześniejsze zbadanie obciążenia procesora / karty graficznej przy typowych obciążeniach i przełączenie niektórych zadań na ogólnie mniej obciążone jeden.

W przypadku Web Render nowość polega na tym, że przeglądarki zazwyczaj wykonują większość operacji renderowania na procesorze (tj. Procesor służy do obliczania, które obiekty mają być wyświetlane, gdzie wycinać itp.). GPU jest zwykle w tym lepsza ... poza tym, że nie wszystkie przypadki użycia są trywialne w implementacji (częściowe wygaszanie, cienie, ... i tekst).

Początkowa wersja Web Render okazała się bardzo skuteczna we wzroście wydajności, ale nie próbowała rozwiązać problemu renderowania tekstu (i miała kilka innych ograniczeń). Mozilla Research pracuje obecnie nad drugą wersją, która ma mieć mniej ograniczeń, a zwłaszcza do obsługi renderowania tekstu.

Oczywiście celem jest odciążenie procesora graficznego w jak największym stopniu, pozostawiając procesorowi swobodę wykonywania Javascript, aktualizacji DOM i wszystkich innych zadań.

Tak więc, choć nie tak ekstremalna, jak sugerujesz, idzie w kierunku projektowania strategii obliczeniowej z uwzględnieniem zarówno procesora, jak i GPU.

Matthieu M.
źródło
0

Koncentrując się na grach (ponieważ wspomniałeś o tym konkretnie w swoim poście), istnieje kilka sposobów na zrównoważenie obciążenia. Jednym z przykładów jest „skórowanie”, tj. Animowanie modelu. Aby renderować każdą klatkę, musisz wygenerować macierze transformacji dla każdej klatki animacji i zastosować ją do wierzchołków modelu, aby przekształcić ją w pozę, w której musi być. Musisz także interpolować klatki, aby uzyskać płynny ruch , chyba że chcesz, aby animacja wyglądała jak oryginalny Quake (tzn. gwałtowny).

W tej sytuacji możesz to zrobić na CPU i przesłać wyniki do GPU w celu renderowania lub wykonać obliczenia i renderowanie na GPU. Wierzę, że obecnie odbywa się to na GPU (znanym jako „skórowanie sprzętu”): ma to sens, biorąc pod uwagę, że masz stosunkowo proste obliczenia, które należy wykonać tysiące razy, a każdy wierzchołek można obliczyć jednocześnie od wyniku wierzchołka A nie ma wpływu na wynik wierzchołka B.

Teoretycznie jednak możesz dynamicznie przełączać się między robieniem tego na CPU lub GPU, w zależności od tego, jak obciążone są GPU i CPU.

Głównym czynnikiem blokującym robienie tego we wszystkich obliczeniach jest jednak to, że CPU i GPU mają różne mocne i słabe strony. Znacznie równoległe zadania są lepiej wykonywane na GPU, podczas gdy intensywne zadania liniowe z rozgałęzianiem są lepiej wykonywane na CPU. Tylko kilka zadań można realistycznie wykonać na obu bez poważnego spadku wydajności.

Ogólnie rzecz biorąc, głównym problemem w programowaniu GPU (przynajmniej w OpenGL i DirectX 11 i starszych) jest to, że masz niewielką kontrolę nad tym, jak GPU interpretuje kod modułu cieniującego. Rozgałęzienie w module cieniującym jest ryzykowne, ponieważ jeśli przypadkowo utworzysz zależność między obliczeniami, GPU może zdecydować o rozpoczęciu renderowania pikseli jeden po drugim, zmieniając 60 klatek na sekundę w 10 klatek na sekundę w mgnieniu oka, mimo że rzeczywiste dane, które mają być renderowane, są identyczne.

Richard Greenlees
źródło
0

Jednym z prawdziwych przykładów jest silnik renderujący LuxRender typu open source , który jest w stanie w pełni załadować procesor i GPU w tym samym czasie. Ponadto może ładować wiele procesorów graficznych jednocześnie, a także może dystrybuować na wielu komputerach.

LuxRender korzysta z OpenCL, aby to ułatwić, chociaż istnieją również kompilacje bez OpenCL.

Jest to praktyczne, ponieważ algorytmy używane przez LuxRender są wysoce równoległe. Najpopularniejszym algorytmem stosowanym przez LuxRender jest śledzenie ścieżek , w którym wiele indywidualnych ścieżek światła może być obliczanych niezależnie od siebie - idealna sytuacja dla obliczeń na GPU i taka, która nie wymaga złożonej synchronizacji między węzłami obliczeniowymi. Jednak ograniczenia procesorów graficznych (mniejsze ilości pamięci, brak obsługi niektórych złożonych funkcji renderowania i ogólny brak dostępności dla niektórych artystów) zapewniają, że obsługa procesora jest nadal niezbędna.

PythonNut
źródło
jaki jest sens wyświetlania tego obrazu, w jaki sposób ma on znaczenie dla zadanego pytania?
komar
1
Ech, w porządku. Usunę to. Myślałem, że łatwo pokaże, jakie to oprogramowanie. Ale może to naprawdę rozprasza. (Istnieje wiele różnych rodzajów silników renderujących; ten jest przeznaczony do fotorealistycznych zdjęć).
PythonNut,
0

Tak, z pewnością jest to możliwe.

Dowolne obliczenia, które może wykonać procesor, GPU, i odwrotnie.

Ale jest to rzadkie, ponieważ:

  • Złożoność inżynierska Chociaż możliwe jest uruchomienie tego samego kodu na CPU i GPU (np. CUDA), procesory mają różne możliwości i cechy wydajnościowe. Jednym z nich jest MIMD; drugi, SIMD. To, co jest szybkie w jednym, jest wolne w drugim (np. Rozgałęzienie), dlatego musisz napisać osobny kod, aby zmaksymalizować wydajność.

  • Efektywność kosztowa Procesory graficzne są znacznie mocniejsze niż procesory. Cała idea procesorów graficznych polega na wykorzystaniu tańszych, wolniejszych, ale liczniejszych procesorów, aby wykonywać obliczenia znacznie szybciej niż procesory przy takim samym koszcie. Procesory graficzne są bardziej wydajne pod względem kosztów o jeden lub dwa rzędy wielkości.

Jeśli Twój algorytm działa na GPU, sensowniej jest zoptymalizować go i dodać tyle, ile potrzebujesz.

Paul Draper
źródło