2015-05-25 47 views
10

Zrobiłem prosty eksperyment, wprowadzając naiwny algorytm przeszukiwania znaków, przeszukując 1.000.000 wierszy po 50 znaków (50 mil na mapie) na procesor i GPU (przy użyciu iOS8 Metal compute rurociąg).iOS Metalowy rurociąg obliczeniowy wolniejszy niż implementacja CPU dla zadania wyszukiwania

Implementacja procesora używa prostej pętli, implementacja Metal daje każdemu jądrowi 1 wiersz do przetworzenia (kod źródłowy poniżej).

Ku mojemu zaskoczeniu, implementacja Metalu jest średnio 2-3 razy wolniejsza niż prosty, liniowy procesor (jeśli używam 1 rdzenia) i 3-4 razy wolniejszy, jeśli używam 2 rdzenie (każdy z nich szuka połowy bazy danych) ! Eksperymentowałem z różnymi wątkami na grupę (16, 32, 64, 128, 512), ale wciąż uzyskuję bardzo podobne wyniki.

iPhone 6:

CPU 1 core: approx 0.12 sec 
CPU 2 cores: approx 0.075 sec 
GPU: approx 0.35 sec (relEase mode, validation disabled) 

widzę Metal shader wydawać więcej niż 90% od dostępu do pamięci (patrz niżej).

Co można zrobić, aby ją zoptymalizować?

Wszelkie spostrzeżenia będą doceniane, ponieważ w Internecie nie ma wielu źródeł (oprócz standardowych przewodników po programowaniu Apple), dostarczających szczegółów na temat wewnętrznych elementów dostępu do pamięci & kompromisów właściwych dla szkieletu Metal.

METAL REALIZACJI INFORMACJE: kod

hosta GIST: https://gist.github.com/lukaszmargielewski/0a3b16d4661dd7d7e00d

jądra (moduł cieniujący) Kod: https://gist.github.com/lukaszmargielewski/6b64d06d2d106d110126

graficzny wychwytywania ramki wyniki profilowania:

enter image description here

+7

nie wklejaj zrzutów ekranu z kodem. są w zasadzie bezużyteczne ... wytnij i wklej rzeczywisty kod. –

+0

@MarcB Zastąpiłem zrzut ekranu gISTem github. Mam nadzieję, że jest w porządku (miał duże problemy z prawidłowym sformatowaniem tego fragmentu kodu). – Lukasz

+0

Pierwszą rzeczą, którą chciałbym spróbować, jest przeniesienie searchPhrase do pamięci urządzenia. Apple mówi, żeby nie używać stałej przestrzeni dla tablic. Daj nam znać, jeśli to coś da. – Jessy

Odpowiedz

0

Przyjmę też moje przypuszczenia, gpu nie jest zoptymalizowane pod kątem, czy/else, nie przewiduje rozgałęzień (prawdopodobnie wykonuje oba), spróbuj przepisać algorytm w bardziej liniowy sposób bez żadnych warunkowych lub sprowadzić je do minimum.

+0

Narzędzia do profilowania wyraźnie pokazują (widoczne na załączonym zrzucie ekranu), że nie jest to wąskie gardło. Ponad 90% czasu przeznaczane jest na dostęp do pamięci. – Lukasz

3

Moduł cieniujący GPU również krąży w pionie przez pamięć, podczas gdy procesor przesuwa się w poziomie. Rozważ adresy faktycznie dotknięte mniej więcej w tym samym czasie przez każdy wątek wykonywany w lockstep w twoim module cieniującym, gdy czytasz charTable. Procesor GPU prawdopodobnie uruchomi się znacznie szybciej, jeśli macierz charTable zostanie transponowana.

Ponadto, ponieważ ten kod jest wykonywany w sposób SIMD, każdy wątek GPU będzie prawdopodobnie musiał uruchomić pętlę do pełnej długości frazy wyszukiwania, podczas gdy procesor będzie korzystał z wczesnych outów. Kod GPU może działać nieco szybciej, jeśli usuniesz wczesne outy i po prostu utrzymasz prosty kod. Wiele zależy od długości frazy wyszukiwania i prawdopodobieństwa dopasowania.