- Efektywny algorytm.
- Jeszcze efektywniejszy algorytm.
- Na pewno da się lepiej - ulepszyć algorytm.
- Uruchomić profiler i zobaczyć gdzie muli.
- A mówiłem, że te zagnieżdżone pętle będą się mulić - użyć lepszego algorytmu.
- Nie da się zrobić lepszego algorytmu? Zoptymalizować struktury danych i goto 1.
- Zrównoleglić algorytm i goto 1.
- Dla zaawansowanych: Jeśli struktury danych i algorytmy są w porządku, to można się pobawić w mikrooptymalizacje.
Mikroooptymalizacje w Javie:
- Unikać alokacji obiektów przez new.
- Nie stosować blokad i synchronizacji.
- W alg. wielowątkowych wyrównywać rozmiar obiektów do wielokrotności 32 lub 64 bajtów (false sharing).
- Uważać na autoboxing.
- Dla bardzo zaawansownaych: W przypadku wątpliwości obejrzeć sobie kod maszynowy (nie bajtkod) i zobaczyć, czy HotSpot nie robi jakiś głupot.
- Upychać struktury danych tak aby było jak najmniej referencji a rozmiar jak najmniejszy (dodatkowa zaleta - mniej wywołań new).
- W przypadku obróbki dużych ilości surowych danych, warto wyrzucić je poza stertę JVM, aby odciążyć GC.
- Stosować odpowiednio wydajne biblioteki np. Javolution zamiast kolekcji standardowych.
- Starać się unikać zbyt wielu poziomów abstrakcji i wywołań wirtualnych. JVM jest ogólnie niezły w zwijaniu funkcji wirtualnych, ale jak ma tego za dużo to jednak czasem lepiej mu pomóc.
- Starać się uporządkować dane tak, aby jak najefektywniej wykorzystać cache, ułatwić pracę prefetchera i jednostki przewidywania skoków. Tu też jednak na ogół cudów nie ma, ale wszystko zależy od konkretnego algorytmu. W skrajnych przypadkach optymalizacje tego typu mogą dać zysk 3-5x.
- W bardzo szczególnych przypadkach zaimplementować fragmenty w C/C++ i wywoływać przez JNA/JNI (ale uwaga na narzut samego JNA/JNI), jednak jeśli przyłożyliśmy się do wszystkich poprzednich punktów, zysk z tego na ogół jest mizerny (można urwać kilka %).
Jeżeli szybkość działania jest kluczowa to i tak bez wstawek w C(lub całości w C) się nie obędzie
Tu bym bardzo, ale to bardzo uważał. W 99% przypadków, jeśli nie jest super ekspertem od pisania wydajnego kodu w C/C++, i przeniesiesz kod bezpośrednio tylko dopasowując skłądnię, to tylko pogorszysz wydajność a nie poprawisz. W C/C++ może Cię ugryźć bardzo mocno aliasing, fragmentacja pamięci, powolność new/delete (malloc/free), gorszy inliner wywołań wirtualnych.
Używanie C/C++ ma sens tylko jeśli:
-
chcesz wykorzystać ręcznie specjalne instrukcje procesora (np. SSE4), których HotSpot nie wykorzystał (ale musisz najpierw sprawdzić, czy faktycznie tak się stało). Tu raczej bez schodzenia do poziomu asma się nie obędzie, bo kompilatory C wcale już nie są takie lepsze w wektoryzowaniu pętli niż serwerowy HotSpot (tj. jedne i drugie są dość cienkie). Tu jest fajny przykład: http://lemire.me/blog/archives/2012/07/23/is-cc-worth-it/
-
musisz mieć pełną kontrolę nad ułożeniem danych w pamięci tak aby zmaksymalizować wykorzystanie cache (C++ placement new, eliminacja wskaźników, precyzyjne dopasowywanie rozmiaru obiektów do rozmiaru linii cache itp).
-
Chesz utrzymać wysoki poziom abstrakcji a zarazem mocno specjalizować kod - wtedy używasz mocno C++ templates i olewasz polimorfizm czasu wykonania.
W każdym razie wiara, że po przepisaniu 1:1 kodu Javy na C/C++ kompilator automagicznie przyspieszy go o rząd wielkości, jest wielce naiwna.