Asembler x86/Optymalizacja
Historia
edytujW przypadku starszych procesorów X86 (szczególnie tych bez kolejkowania instrukcji oraz przewidywania skoku) duże znaczenie miały optymalizacje na poziomie pojedynczych instrukcji. Wśród procesorów 286 popularne było zastępowanie zerowania rejestru (MOV $0, %AX) wykonaniem na nim operacji XOR (XOR %AX, %AX), gdyż operacje arytmetyczne były o kilka taktów szybsze. Obecnie takie postępowanie jest niezalecane i spowalnia kod. Często zdarzało się również zastępowanie operacji zmniejszania/zwiększania o pewną małą wartość (1-2) taką samą liczbą instrukcji INC/DEC, co umożliwiało zyskanie jednego bajtu pamięci i małe przyspieszenie kodu. Obecnie tego typu optymalizacje mają sens jedynie w przypadku bardzo często wyknywanych fragmentów kodu.
Rady
edytujNależy rozsądnie stosować optymalizację, gdyż w większości przypadków zmniejsza czytelność i estetykę kodu lub zwiększa jego rozmiar. Gdy kod jest bardzo rzadko wykonywany, nie ma sensu go optymalizować, gdyż może to zwiększyć prawdopodobieństwo popełnienia błędu.
Metody
edytujWyróżniamy dwa rodzaje optymalizacji: optymalizację czasową i pamięciową.
Optymalizacja czasowa
edytujOptymalizacja mająca na celu zmniejszenie czasu wykonywania się programu.
Najważniejsze techniki optymalizacyjne:
- Zastępowanie mnożenia/dzielenia przez potęgi dwójki operacjami przesunięcia bitowego. Czasami również da się zastąpić operacje mnożenia przez 3, 5 i 9 operacjami postaci: LEA (EAX, EAX, 2), EAX dla mnożenia przez 3, LEA (EAX, EAX, 4), EAX dla mnożenia przez 5 i LEA (EAX, EAX, 8), EAX dla mnożenia przez 9.
- Wklejenie kodu funkcji w żądane miejsce zamiast jej wywoływania (np. przez makro).
- Rozwijanie krótkich pętli do postaci kilku powtórzeń - metoda ta umożliwia zaoszczędzenie na instrukcjach sprawdzenia warunku oraz instrukcjach skoku. Ułatwia także procesorom równoległe obliczenie niektórych wartości, gdyż nie muszą one wtedy przewidywać kierunku skoku.
- Wykorzystanie nowoczesnych zestawów instrukcji: MMX i SSE*.
- Używanie rejestrów zamiast pamięci - co prawda nakłada to na programistę obowiązek pamiętania która zmienna jest w którym rejestrze, ale odwołanie do rejestru jest dużo szybsze od odwołania do pamięci (a nawet do cache procesora).
Pomijam tu oczywiste metody, takie jak wyczyszczenie kodu z niepotrzebnych instrukcji.
Optymalizacja pamięciowa
edytujOptymalizacja mająca na celu zmniejszenie wymagań pamięciowych programu.
- Używanie rejestrów zamiast pamięci
- Rozsądne zmniejszenie rozmiaru danych, w krytycznych strukturach zalecane jest zapisywanie zmiennych za pomocą pól bitowych (przykład zapisu za pomocą pól bitowych: rejestry statusu kontrolera przerwań, DMA, klawiatury).