-
Data: 2014-04-05 05:20:27
Temat: C vs. ASM na przykładzie PIC18F
Od: Sylwester Łazar <i...@a...pl> szukaj wiadomości tego autora
[ pokaż wszystkie nagłówki ]Tak jak opisałem wcześniej, przygotowałem procedurę, która sortuje mi
kilka napięć metodą zliczania:
http://edu.i-lo.tarnow.pl/inf/alg/003_sort/0023.php
Jako, że ostatnio toczą się dyskusje o kompilatorach C,
pozwoliłem sobie zrobić prosty test.
Napisałem procedurę w ASM i w C.
Oczywiście obie działają poprawnie.
1) Objętość kodu ma się następująco (dla otymalizacji Debug):
470 bajty kodu w C
128 bajty kodu w ASM
3,67x więcej w C
Poniżej wklejam oba kody.
Kodu w C po kompilacji z oczywistych względów nie wklejam.
2) Testów czasowych _nie robiłem_, ale główna pętla przepisywania rekordów
ma w asm: 20 instrukcji,
a w C po przekompilowaniu: 121 instrukcji.
Wygląda na to, że w C program działa jakieś 6x wolniej.
3) Ciekawe jest, że prosta procedura, która kasuje wstępnie tablicę typu
char,
ma w pętli 10 rozkazów na samo kasowanie
i 16 rozkazów na obsługę pętli.
No i jest taka perełka:
MOVLW 0
ADDWFC 0xfea, F, ACCESS
Najpierw do w wpisuje 0, a potem dodaje do rejestru 0xFEA, czyli do
starszego bajtu FSR0H.
Operacja kompletnie bezsensowna.
4) Kompilator to MPLAB C18 v3.12 (demo)
5) Po włączeniu optymalizacji "Enable on" kod zmniejszył się do 342 bajtów
i w ten sposób współczynnik ilości bajtów C vs. ASM wyniósł: 2,67.
Główna pętla zwiększyła się ze 121instrukcji na 182!
Przypominam: w asm 20 instrukcji.
Możliwe, że ma to swoje umotywowanie czasowe, ale trudno mi sobie je
wytłumaczyć,
skoro da się to ze spokojem przeprowadzić w 20 instrukcjach, a niech będzie,
że i w 40,
jeśli jakiś student by się pokusił o nieoptymalne napisanie kodu.
Ale 182 to już gruba przesada.
Wnioski:
1) Wydaje mi się, że takie wyniki to porażka, jeśli chodzi o możliwości
kompilatora C.
2) Ja w swoim kodzie nie używałem żadnych sztuczek.
Wszystkie ewentualne optymalizację, mógłby wykonać kompilator -
mechanicznie.
3) Być może są jakieś inne kompilatory, które potrafią wydusić z siebie coś
więcej.
4) Ten przykład sortował 5 liczb.
Nie jestem w stanie sobie wyobrazić sprawnego sortowania 5000 liczb,
pobieranych np. z pendrive'a,
za pomocą kodu napisanego w C.
5) Podglądnąłem też wcześniej kod po kompilacji dla 32-bitowego
mikrokontrolera MX32. Też byłem załamany,
ale nie analizowałem wtedy tak dokładnie, co tam za cuda się dzieją.
--
-- .
pozdrawiam
Sylwester Łazar
http://www.alpro.pl Systemy elektroniczne.
http://www.rimu.pl -oprogramowanie do edycji schematów
i projektowania PCB.
Kod w C:
void zlicz(void);
const char k = 7; // elementami tablicy VDIOD są liczby całkowite z
przedziału 0..6
const char n = 5;
char VDIOD[5]; // tablica zawierająca elementy do posortowania
char VDOUT[5]; // tablica zawierająca elementy posortowane
char ADRDIOD[5][2];//tablica adresów diod
char ADRDOUT[5][2];//tablica adresów diod po posegregowaniu
char LICZV[5]; // zawiera liczbę elementów o danej wartości
void main (void){
VDIOD[0]=1;
VDIOD[1]=2;
VDIOD[2]=6;
VDIOD[3]=4;
VDIOD[4]=3;
ADRDIOD[0][0]=1;
ADRDIOD[0][1]=0;
ADRDIOD[1][0]=1;
ADRDIOD[1][1]=1;
ADRDIOD[2][0]=1;
ADRDIOD[2][1]=2;
ADRDIOD[3][0]=2;
ADRDIOD[3][1]=0;
ADRDIOD[4][0]=2;
ADRDIOD[4][1]=1;
zlicz();
}
void zlicz(){
char i; // zmienna pomocnicza
char j; // zmienna pomocnicza
for(i = 0 ; i < k ; ++i)
LICZV[i] = 0; // zerowanie tablicy
for(i = 0 ; i < n ; ++i)
++LICZV[VDIOD[i]]; // po tych operacjach LICZV[i] będzie
zawierała
// liczbę wystąpień elementów o kluczu i
for(i = 1 ; i < k ; ++i)
LICZV[i] += LICZV[i-1]; // teraz LICZV[i] zawiera pozycje w
posortowanej
// tablicy ostatniego elementu o kluczu i
for(i = n-1 ; i >= 0 ; --i)
{
j=--LICZV[VDIOD[i]]; // aktualizacja LICZV
VDOUT[j] = VDIOD[i]; //wstawienie elementu na odpowiednią pozycję
ADRDOUT[j][0] = ADRDIOD[i][0]; // sortowanie adresów
ADRDOUT[j][1] = ADRDIOD[i][1]; // sortowanie adresów
}
}
Kod w asm:
;***************************************************
************************
;PROJEKT: TDIODA
;DATA: 2014-04-04
;PROCESOR: PIC18F2320
;PROCEDURA:ZLICZ
;PLIK:ZLICZ201446.SDA
;DANE WE: TABLICA NAPIĘĆ DIODY
;KMIN-wartość minimalna napięcia
;KMAX-wartość maksymalna napięcia
;N-liczba diod
;
;DVOLT- tablica napięć diod (1 bajt)
;LICZV - tablica ilości takich samych próbek napięć
;ADRDIOD - ADRES <PAR PORT;PIN> (2 bajty)
;
;DANE WY: posortowane obie tablica:
;DWOLT2
;ADRDIOD2
;OPIS:
;Procedura sortuje diody w kolejności rosnącego
;napięcia.
;METODA: ZLICZAJĄCA
;Uwagi:
;1) Dla dłuższych danych należy zastosować mikrokontroler 16 lub 32 lub 64
bitowy.
;2) TABLICE wyników muszą następować bezpośrednio po tablicy
nieposortowanej.
;np. ADRDIOD2 musi być po ADRDIOD
;3) pozycje tablicy numerujemy od 1
;4) Sortowane elementy mogą mieć maksymalnie 128 pozycji (dwubajtowe dane).
;Tutaj N to liczba diod.
;Muszą się zaczynać na adresie pamięci xx00. (ALIGNED)
;Trochę to bez sensu, gdyż dla N=128 pozycji to sortowanie szybkie byłoby
szybsze.
; Jednak po przeniesieniu na większy uC liczba N może ulec zmianie.
;***************************************************
************************
;ZLICZ.
ZLICZ
MOVF KMIN,w ;zacznij zerować tablicę liczników od KMIN
SUBWF KMAX,w ;oblicz rozpiętość napięć
MOVWF COUNTER ;zapisz rozpiętość na stosie
INCF WREG ;liczba bajtów do sumowania wystąpień o 1 większa
MOVWF CNT ;zapisz do CNT
LFSR 1,LICZV ;zapisz do wskaźnika początek tablicy zliczającej
ZCLR
CLRF POSTINC1 ;LICZV[CNT++]:=0
DECFSZ CNT ;Czy cała tablica wyzerowana?
BRA ZCLR ;NIE
LFSR 1,VDIOD ;początek tablicy napięć diod
LFSR 2,LICZV ;początek tablicy liczników wartości
movlf NR,CNT ;ustal liczbę działań równą liczbie diod
ZLICZN
MOVF KMIN,w ;od każdej wartości odejmiemy KMIN
SUBWF POSTINC1,w ;odczytaj klucz z tablicy VDIOD++[]
INCF PLUSW2,F ;zwiększ o 1 licznik dla tego napięcia
DECFSZ CNT ;Czy wszystkie napięcia zliczone?
BRA ZLICZN ;NIE
LFSR 1,LICZV ;początek tablicy liczb wartości napięć
LFSR 2,LICZV+1 ;następna pozycja
ZSUMUJ
MOVF POSTINC1,w ;odczytaj poprzednią sumę
ADDWF POSTINC2,F ;dodaj do bieżącej
DECFSZ COUNTER ;Czy wszystkie wartości posumowane?
BRA ZSUMUJ ;NIE
LFSR 0,NR+VDIOD-1;koniec tablicy napięć diod
LFSR 1,LICZV ;POCZĄTEK tablicy liczników wartości
LFSR 2,ADRDIOD ;adres początku tablicy adresów diod
movlf 2*NR,CNT ;ustal liczbę działań (po 2 bajty adresu) liczbie diod*2
NEGF KMIN ;zaneguj KMIN, aby w pętli móc dodawać zamiast odejmować
ZSORTUJ
MOVF POSTDEC0,w ;odczytaj wartość napięcia i cofnij wskaźnik
MOVWF VOLTAGE ;zapamiętaj bieżącą wartość napięcia
ADDWF KMIN,w ;zrób klucz: dodaj zanegowaną wartość minimalna
DECF PLUSW1,F ;zmniejsz ostatnią POZYCJĘ dla tego napięcia w LICZV[VOLTAGE]
MOVF PLUSW1,w ;odczytaj nową pozycję dla tej wartości
MULLW 2 ;zapamiętaj numer nowej pozycji*2 w rejestrze wyniku mnożenia
;----------------------
ADDLW -NR ;przesuń wskaźnik do tablicy wyników VDOUT[]- musi być
koniecznie przed ADRDIOD[]
MOVFF VOLTAGE,PLUSW2;zapisz wartość napięcia
VDOUT[ADRDIOD-NR+LICZV[klucz]:=VOLTAGE
;----------------------
DECF CNT,F ;zmniejsz pozycję z tablicy ADRESÓW
MOVF CNT,w ;przepisz do w
;-------------TUTAJ KOPIOWANIE CAŁEGO REKORDU - ODCZYT:
MOVFF PLUSW2,BIT ;odczytaj ADRES BITU
DECF WREG,F ;zmniejsz wskaźnik
MOVFF PLUSW2,PORT ;odczytaj ADRES PORTU
;-------------TUTAJ KOPIOWANIE CAŁEGO REKORDU - ZAPIS:
MOVF PRODL,w ;odzyskaj numer nowej pozycji
ADDLW 2*NR ;dodanie offsetu, aby uzyskać adres tablicy wynikowej ADRDOUT
MOVFF PORT,PLUSW2 ;zapisz ADRES BITU na nowej pozycji
INCF WREG,F ;zmniejsz wskaźnik
MOVFF BIT,PLUSW2 ;zapisz ADRES PORTU na nowej pozycji
DECFSZ CNT ;Czy wszystkie wartości posortowane?
BRA ZSORTUJ ;NIE
NEGF KMIN ;przywróć poprawna wartość dla porządku
RETURN
Następne wpisy z tego wątku
- 05.04.14 06:40 John Smith
- 05.04.14 10:02 Sylwester Łazar
- 05.04.14 10:10 Marek
- 05.04.14 10:15 Marek
- 05.04.14 10:25 Marek
- 05.04.14 10:32 Marek
- 05.04.14 11:01 Sylwester Łazar
- 05.04.14 11:04 Marek
- 05.04.14 11:10 Sylwester Łazar
- 05.04.14 11:10 jacek pozniak
- 05.04.14 11:34 Michał Lankosz
- 05.04.14 11:43 jacek pozniak
- 05.04.14 11:49 Sylwester Łazar
- 05.04.14 12:28 Marek
- 05.04.14 12:42 Sylwester Łazar
Najnowsze wątki z tej grupy
- Zrobił TV OLED z TV LCD
- Zasilacz USB na ścianę.
- Gniazdo + wtyk
- Aliexpress zaczął oszukiwać na bezczelnego.
- OpenPnP
- taka skrzynka do kablowki
- e-paper
- 60 mA dużo czy spoko?
- Dziwne zachowanie magistrali adresowej w 8085
- Współczesne mierniki zniekształceń nieliniowych THD audio, produkują jakieś?
- Jaki silikon lub może klej?
- Smar do video
- Litowe baterie AA Li/FeS2 a alkaliczne
- "ogrodowa linia napowietrzna"
- jaki zasilacz laboratoryjny
Najnowsze wątki
- 2025-03-02 Tusk idzie na rekord deportacji po 1989 [Będzie popyt na prawników]
- 2025-03-01 Obywatel telefonuje 112 lub 986
- 2025-03-01 detektyw (?) Rutkowski działał jako prasa
- 2025-03-01 "Policjant został ujęty obywatelsko..."
- 2025-03-01 zatrzymanie zbyszka maja
- 2025-03-01 Warszawa => Expert Recruiter 360 <=
- 2025-03-01 Chrzanów => NodeJS Developer <=
- 2025-03-01 Warszawa => Gen AI Engineer <=
- 2025-03-01 Wrocław => Konsultant wdrożeniowy Comarch XL/Optima (Księgowość i
- 2025-03-01 Kraków => Technical Team Leader (Clojure, Java) <=
- 2025-03-01 Zrobił TV OLED z TV LCD
- 2025-03-01 Gdynia => Sales Executive / KAM <=
- 2025-03-01 Błonie => Sales Specialist <=
- 2025-03-01 Ryga => Konsultant Wdrożeniowy Comarch XL/Optima (Księgowość i Kad
- 2025-03-01 Żerniki => Dyspozytor Międzynarodowy <=