Asembler x86/Optymalizacja
Historia
[edytuj]W 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
[edytuj]Należ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
[edytuj]Wyróżniamy dwa rodzaje optymalizacji: optymalizację czasową i pamięciową.
Optymalizacja czasowa
[edytuj]Optymalizacja 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
[edytuj]Optymalizacja 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).