-
Path: news-archive.icm.edu.pl!agh.edu.pl!news.agh.edu.pl!news.cyf-kr.edu.pl!news.nask
.pl!news.nask.org.pl!news.internetia.pl!not-for-mail
From: Sylwester Łazar <i...@a...pl>
Newsgroups: pl.misc.elektronika
Subject: C vs. ASM na przykładzie PIC18F
Date: Sat, 5 Apr 2014 05:20:27 +0200
Organization: Netia S.A.
Lines: 221
Message-ID: <lhntl8$u3a$1@mx1.internetia.pl>
NNTP-Posting-Host: 77-253-141-36.adsl.inetia.pl
Mime-Version: 1.0
Content-Type: text/plain; charset="iso-8859-2"
Content-Transfer-Encoding: 8bit
X-Trace: mx1.internetia.pl 1396668904 30826 77.253.141.36 (5 Apr 2014 03:35:04 GMT)
X-Complaints-To: a...@i...pl
NNTP-Posting-Date: Sat, 5 Apr 2014 03:35:04 +0000 (UTC)
X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2615.200
X-Tech-Contact: u...@i...pl
X-Newsreader: Microsoft Outlook Express 5.00.2615.200
X-Priority: 3
X-Server-Info: http://www.internetia.pl/
X-MSMail-Priority: Normal
Xref: news-archive.icm.edu.pl pl.misc.elektronika:662303
[ ukryj 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
- Akumulatorki Ni-MH AA i AAA Green Cell
- Dławik CM
- JDG i utylizacja sprzetu
- Identyfikacja układ SO8 w sterowniku migających światełek choinkowych
- DS1813-10 się psuje
- Taki tam szkolny problem...
- LIR2032 a ML2032
- SmartWatch Multimetr bezprzewodowy
- olej psuje?
- Internet w lesie - Starlink
- Opis produktu z Aliexpress
- No proszę, a śmialiście się z hindusów.
- Zewnętrzne napięcie referencyjne LM385 1,2V -> 100mV dla ICL7106, Metex M-3800
- karta parkingowa
- Wl/Wyl (On/Off) bialy/niebieski
Najnowsze wątki
- 2024-12-02 Gdańsk => Full Stack web developer (obszar .Net Core, Angular6+) <=
- 2024-12-02 Kraków => Full Stack .Net Engineer <=
- 2024-12-02 Warszawa => Key Account Manager <=
- 2024-12-02 Kraków => Software .Net Developer <=
- 2024-12-02 Wrocław => Inżynier bezpieczeństwa aplikacji <=
- 2024-12-02 Gdańsk => Kierownik Działu Spedycji Międzynarodowej <=
- 2024-12-02 Gdańsk => Head of International Freight Forwarding Department <=
- 2024-12-02 Akumulatorki Ni-MH AA i AAA Green Cell
- 2024-12-02 Usiłowanie zabójstwa
- 2024-12-01 Rambo 2024. Co z radio-stopem
- 2024-12-01 Pijani kierowcy
- 2024-12-01 "Chciałem zamówić kurs tym"
- 2024-11-30 Windykatorzy ścigają spadkobierców z mandat nieboszczyka za przekroczenie prędkości???
- 2024-11-30 Łódź => Technical Artist <=
- 2024-11-30 Lublin => Inżynier Serwisu Sprzętu Medycznego <=