Assembly HOWTO pl 2 (2)


Assembly HOWTO: CZY POTRZEBUJESZ ASEMBLACJI? Następna strona Poprzednia strona Spis treści 2. CZY POTRZEBUJESZ ASEMBLACJI? No, nie chciałbym przeszkadzać w tym co robisz, ale tu jest kilka porad ciężko zarobionego doświadczenia. 2.1 Za i Przeciw Korzyści Assemblacji Assemblacja może wyrazić mocno niskopoziomowe rzeczy: masz dostęp do zależnych-od-maszyny rejestrów i I/O. możesz kontrolować dokładnie zachowanie kodu w krytycznych sekcjach które mogą wywołać martwe punkty pomiędzy wieloma wątkami programowymi lub urządzeniami. możesz złamać ustalenia zwykłego kompilatora, który może pozwalać na pewne optymalizacje (jak chwilowe łamanie zasad o przydzielaniu pamięci, wątkach, konwencji wywołań, itd). możesz budować interfejsy pomiędzy fragmentami kodu używającego pewnych niekompatybilnych konwencji (np. produkowanego przez różne kompilatory, lub oddzielonego nisko-poziomowym interfejsem). masz dostęp do nieużywanych trybów twojego procesora (np. 16 bitowy tryb interfejsu startowego, instrukcji chip-owych (przyp.tłum.) lub dziedziczonego kodu na Intel PC) możesz produkować rozsądnie szybki kod dla zwartych pętli by poradzić sobie ze złym nie-zoptymalizowanym kompilatorem (po co, są przecież dostępne wolne zoptymalizowane kompilatory!) możesz produkować kod gdzie ale tylko na procesorach ze znanym czasem instrukcji, który ogólnie wyłącza cały przepływ .... możesz produkować ręcznie-zoptymalizowany kod który jest perfekcyjnie dostosowany do twojej szczególnej konfiguracji sprzętowej, a zatem do nikogo więcej. możesz pisać pewien kod dla twojego kompilatora nowego języka (to jest coś którzy mogą zrobić nieliczni, i także oni, nie często). Niekorzyści Assemblacji Assemblacja jest bardzo nisko-poziomowym językiem (najniższym jest ręczne-kodowanie w kodach binarnych instrukcji). To znaczy jest długo i monotonnie pisać wszystko od początku, jest mocno podatna na błędy, błędy będą bardzo trudne do wyśledzenia, jest to bardzo trudno zrozumieć i modyfikować, np. utrzymywać rezultat jest bardzo nie-przenośny na inne architektury, aktualne i przyszłe, twój kod będzie zoptymalizowany tylko w pewnych implementacjach na tej samej architekturze: dla przykładu, pośród platform Intelowskich, każdy wariant CPU i jego odmian (względy ukryte, przepustowość, pojemność jednostek obliczeniowych, cache'y, RAM-u, szyny, dysków, obecności FPU, rozszerzeń MMX, itd) daje potencjalnie całkowicie różne techniki optymalizacji. Warianty CPU już włączone Intel 386, 486, Pentium, PPro, Pentium II; Cyrix 5x86, 6x86; AMD K5, K6. Nowe warianty pojawiają się więc nie spodziewaj się, że każdy listing twojego kodu będzie na czasie. twój kod może być także nieprzenośny przez różne platformy systemowe na tej samej architekturze, przez brak właściwych narzędzi (no, GAS wydaje się pracować na wszystkich platformach; NASM wydaje się pracować lub być w stanie pracować na platformach intelowskich). spędzisz więcej czasu na kilku detalach, i nie będziesz mógł skoncentrować się na małych i dużych algorytmach, które są w stanie przynieść największą część przyspieszenia. [np. możesz spędzić trochę czasu budując bardzo szybkie prymitywy manipulacji na listach/tablicach w assemblerze; tylko hash-tablice (przyp.tłum.) mogą mocno przyspieszyć twój program; lub i innym przypadku, drzewka binarne; lub pewne wysokopoziomowe struktury rozprowadzane przez klaster CPU] mała zmiana w konstrukcji algorytmu mogłaby całkowicie unieważnić twój cały istniejący assemblowany kod. Tak więc także ty masz być gotowy (i w stanie) by przepisać to wszystko, lub będziesz przywiązany do poszczególnych rozwiązań algorytmicznych; W kodzie który nie wypada daleko od standardowych testów, komercyjne zoptymalizowane kompilatory wykonują prawe ręcznie-kodowany assembler (no, to jest mniejszą prawdą na architekturze x86 niż na architekturach RISC-owych; i być może mniejszą prawdą niż dla szeroko dostępnych/wolnych kompilatorach; jakkolwiek, dla typowego kodu w C, GCC jest całkiem dobry); I w dowolnym przypadku, jak powiedział wstrzemięźliwy John Levine na comp.compilers, ``kompilatory mocno ułatwiają używanie złożonych struktur danych, i kompilatory nie dają znudzenia w połowie drogi i generują całkiem dobry kod.'' One także będą prawidłowo przechodzić transformacje kodu poprzez cały (olbrzymi) program podczas optymalizacji kodu pomiędzy procedurami i granicami modułów. Ocenianie Podsumowując, chociaż możesz uznać że użycie assemblacji jest czasami konieczne, a nawet pożyteczne w kilku przypadkach gdzie nie jest konieczne, będziesz chciał: minimalizować użycie kodu assemblera, hermetyzować ten kod w dobrze zdefiniowanych interfejsach mieć kod assemblera generowany automatycznie ze wzorców wyrażonych w wysokopoziomowym języku niż w assemblerze (np. assemblerowe makra GCC inline) mieć narzędzia automatyzujące tłumaczenie tych programów w kod assemblera mieć ten kod zoptymalizowany jeśli jest to możliwe Nade wszystko, np. pisać (rozszerzać do) zoptymalizowanych wnętrzności kompilatora. Nawet w przypadkach kiedy Assemblacja jest konieczna (np. rozwój OS) możesz uznać, że nie aż do tego stopnia i trzymać się w/w zasad. Obejrzyj źrodła jądra Linux-a zwracając uwagę: jak mało assemblacji jest konieczne, by uzyskać szybki, niezawodny, przenośny, utrzymywalny OS. Także udana gra taka jak DOOM została prawie całkowicie napisana w C, z mała częścią napisaną w assemblerze tylko do przyśpieszenia jej działania. 2.2 Jak NIE używać Assemblera Ogólne zasady uzyskania efektywnego kodu Jak rzekł Charles Fiterman na comp.compilers o 'człowieku kontra kod assemblera wygenerowany przez komputer', ``Człowiek powinien zawsze wygrać i oto przyczyna. Po pierwsze człowiek pisze całość w języku wysokiego poziomu. Po drugie zarysowuje gdzie mogą wystąpić gorące punkty gdzie program spędza swój czas. Po trzecie ma kompilator produkujący kod assemblera dla tych małych sekcji kodu. Po czwarte ręcznie dostosowuje je by znaleźć małe korzyści nad wygenerowanym przez maszynę kodem. Człowiek wygrywa poniewaz umie używać maszyny.'' Języki ze zoptymalizowanymi kompilatorami Języki takie jak ObjectiveCAML, SML, CommonLISP, Scheme, ADA, Pascal, C, C++, wsród innych, wszystkie mają wolne zoptymalizowane kompilatory, które zoptymalizują masę twoich programów, i często będą lepsze niż ręczny kod assemblera nawet dla szczelnych pętli, umożliwiając ci skoncentrowanie się na wysokopoziomowych szczegółach, i bez zakazywania ci złapania kilku procent wykonania w wyżej wymieniony sposób w momencie gdy osiągniesz stabilny rozwój. Oczywiście, są także komercyjne zoptymalizowane kompilatory dla większości z tych języków. Pewne języki mają kompilatory produkujące kod w C, który może być dalej zoptymalizowany przez dany kompilator C. Takimi są LIST, Scheme, Perl i wiele innych. Prędkość jest całkiem dobra. Ogólne zasady przyśpieszania twojego kodu W celu przyspieszenia kodu powinieneś robić zrobić to tylko dla fragmentów programu które narzędzie profilujące konsekwentnie określa jako wąskie gardło wykonania. Stąd, jeśli określisz fragmenty kodu jako zbyt wolne, powinieneś najpierw spróbować lepszego algorytmu; następnie spróbować skompilować go zamiast interpretować; następnie spróbować włączyć optymalizacje twojego kompilatora; następnie dać kompilatorowi wskazówki jak optymalizować (wypisywanie informacji w LISP-ie; używanie rejestrów w GCC; i pełno innych opcji w większości kompilatorów, itd). następnie można cofnąć się do programowania w assemblerze Na końcu, przed zejściem do pisania w assemblerze, powinieneś prześledzić wygenerowany kod, sprawdzając czy problem nie leży faktycznie w złej generacji kodu, co jest możliwe ale nie w wypadkach: kod wygenerowany przez kompilator może być lepszy niż mógłbyć napisać, w szczególności na nowoczesnych architekturach! Wolne części programu mogą być równie zagmatwane. Największym problemem nowoczesnych architektur z szybkimi procesorami są pewne opóźnienia dostępu do pamięci, nietrafiony dostęp do cache, i TLB oraz błędy stronnicowania; optymalizacja z użyciem rejestrów staje się wtedy mniej użyteczna, i zyskałbyć więcej po przemyśleniu struktury danych oraz wykorzystując wątkowanie gdyż uzyskałbyś lepsze umiejscowienie w dostępie do pamięci. Być może poźniej dopiero całkowicie odmienne spojrzenie na problem, pomoże go rozwiązać. Sprawdzanie kodu generowanego przez kompilator Jest wiele powodów do sprawdzenia kodu generowanego przez kompilator. Tu jest zawarte co robić z takim kodem: sprawdzić czy generowany kod może być wzmocniony ręcznym kodem assemblera (lub przełączaniem przełączników kompilatora) gdy zachodzi taka możliwość rozpocząć z tak wygenerowanego kodu i zmodyfikować go; zamiast rozpoczynać wszystko od początku bardziej ogólnie, używać generowanego kodu jako kawałków do modyfikacji, który co najmniej daje właściwą drogę twoim funkcjom w assemblerze interfejs do świata zewnętrznego wyłapać błędy w kompilatorze (oby jak najrzadziej) Standardową metodą uzyskania kodu assemblera jest wywołanie twojego kompilatora z flagą -S. Działa to dla większości Unix-owych kompilatorów, włączając w to GNU C Compiler (GCC), ale YMMV. Dla GCC, bardziej zrozumiały kod assemblera będzie wyprodukowany po użyciu opcji -fverbose-asm. Oczywiście, jeśli chcesz dostać dobry kod assemblera, nie zapomnij użyć opcji optymalizacji i wskazówek! Następna strona Poprzednia strona Spis treści

Wyszukiwarka

Podobne podstrony:
Assembly HOWTO pl 5 (2)
Assembly HOWTO pl 4 (2)
assembly howto pl
Assembly HOWTO pl 7 (2)
Assembly HOWTO pl (2)
Assembly HOWTO pl 6 (2)
assembly howto pl 3
Assembly HOWTO pl 1 (2)
bootdisk howto pl 8
PPP HOWTO pl 6 (2)
NIS HOWTO pl 1 (2)
cdrom howto pl 1
jtz howto pl 5
Keystroke HOWTO pl (2)
PostgreSQL HOWTO pl 14
printing howto pl 5
debian apt howto pl
Kernel HOWTO pl 12 (2)
XFree86 HOWTO pl (3)

więcej podobnych podstron