Piszę małą bibliotekę do rzadkich obliczeń macierzowych, aby nauczyć się jak najlepiej korzystać z programowania obiektowego. Bardzo ciężko pracowałem nad stworzeniem ładnego modelu obiektowego, w którym części (rzadkie macierze i wykresy opisujące ich strukturę połączeń) są bardzo luźno połączone. Moim zdaniem kod jest znacznie bardziej rozszerzalny i łatwiejszy w utrzymaniu.
Jest to jednak nieco wolniejsze niż w przypadku zastosowania tępego podejścia. Aby przetestować kompromisy związane z posiadaniem tego modelu obiektowego, napisałem nowy rzadki typ matrycy, który przerwał enkapsulację podstawowego wykresu, aby zobaczyć, o ile szybciej by to działało.
Z początku wyglądało to dość ponuro; kod, z którego byłem kiedyś dumny, działał o 60% wolniej niż wersja bez eleganckiego oprogramowania. Ale byłem w stanie dokonać kilku optymalizacji na niskim poziomie - wprowadzając funkcję i zmieniając trochę pętlę - bez zmiany API. Dzięki tym zmianom jest teraz tylko 20% wolniejszy niż u konkurencji.
Co prowadzi mnie do pytania: ile strat wydajności powinienem zaakceptować, jeśli oznacza to, że mam ładny model obiektowy?
źródło
Odpowiedzi:
Bardzo niewielu twórców oprogramowania naukowego rozumie dobre zasady projektowania, więc przepraszam, jeśli ta odpowiedź jest nieco długa. Z punktu widzenia inżynierii oprogramowania celem naukowego twórcy oprogramowania jest zaprojektowanie rozwiązania, które spełnia zestaw ograniczeń, które często są ze sobą sprzeczne .
Oto kilka typowych przykładów tych ograniczeń, które można zastosować do projektu biblioteki rzadkich macierzy:
Naukowcy stopniowo zwracają większą uwagę na inne wspólne wymagania inżynierii oprogramowania:
Możesz potrzebować mniej więcej jednego z tych wymagań. Jeśli próbujesz wygrać nagrodę Gordona Bella za wydajność, nawet ułamki procent są istotne, a niewielu sędziów ocenia jakość twojego kodu (o ile tylko możesz przekonać ich, że ma rację). Jeśli próbujesz uzasadnić uruchomienie tego kodu na współdzielonym zasobie, takim jak klaster lub superkomputer, często musisz bronić twierdzeń dotyczących wydajności kodu, ale rzadko są one bardzo rygorystyczne. Jeśli próbujesz opublikować artykuł w czasopiśmie opisujący wzrost wydajności swojego podejścia, musisz być prawowitym szybszy niż konkurenci, a 20% wydajności to kompromis, który z przyjemnością zapewniłbym lepszą konserwację i możliwość ponownego użycia.
Wracając do pytania: „dobry projekt”, który ma wystarczająco dużo czasu na opracowanie, nigdy nie powinien poświęcać wydajności. Jeśli celem jest, aby kod działał tak szybko, jak to możliwe, kod powinien być zaprojektowany w oparciu o te ograniczenia. Możesz skorzystać z takich technik, jak generowanie kodu, asembler lub skorzystaj z dobrze dostrojonych bibliotek, które pomogą Ci rozwiązać problem.
Ale co, jeśli nie masz wystarczająco dużo czasu na rozwój? Co jest wystarczająco dobre? Cóż, to zależy i nikt nie będzie w stanie udzielić ci dobrej odpowiedzi na to pytanie bez większego kontekstu.
FWIW: Jeśli naprawdę interesuje Cię pisanie wysokowydajnych rzadkich jąder matrycowych, powinieneś porównać się ze zoptymalizowaną instalacją PETSc i współpracować z ich zespołem, jeśli ich pokonujesz, chętnie wprowadzą dostrojone jądra do biblioteki.
źródło
To pytanie, na co spędzasz czas. Dla większości z nas spędzamy 3/4 czasu na programowaniu i 1/4 czasu na oczekiwaniu na wyniki. (Twoje liczby mogą się różnić, ale myślę, że liczba nie jest całkowicie pozbawiona zalet.) Jeśli więc masz projekt, który pozwala ci zaprogramować dwa razy szybciej (3/4 jednostki czasu zamiast 1,5 jednostki czasu), to może wytrzymać 300% wydajności (od 1/4 do 1 jednostki czasu), a ty nadal masz przewagę, jeśli chodzi o czas spędzony na rozwiązaniu problemu.
Z drugiej strony, jeśli wykonujesz ciężkie obliczenia, twoje obliczenia mogą wyglądać inaczej i możesz poświęcić więcej czasu na optymalizację kodu.
Dla mnie 20% wydaje się dość dobrym kompromisem, jeśli w końcu będziesz bardziej produktywny.
źródło
IMHO kara do 50% (z jakiegokolwiek powodu) nie jest taka zła.
W rzeczywistości widziałem różnicę wydajności 0-30% w zależności od rodzaju kompilatora. Dotyczy to rzadkiej procedury PETMc MatMult dotyczącej matryc wynikającej z dyskretyzacji FE niskiego rzędu.
źródło
Projekt oprogramowania nie poprawi się automatycznie w miarę upływu czasu. Spektakl będzie. Otrzymasz 20% z powrotem przy następnym procesorze. Poza tym dobry projekt oprogramowania ułatwi rozbudowę lub ulepszenie biblioteki w przyszłości.
źródło
Ogólną zasadą jest, aby najpierw wybrać dobry projekt, a następnie zoptymalizować wydajność tylko w razie potrzeby . Przypadki użycia, w których naprawdę potrzebny jest wzrost wydajności o 20%, są raczej rzadkie, jeśli w ogóle się pojawią.
źródło