-
21. Data: 2009-06-12 03:37:13
Temat: Re: Problem lekko OT, ale w WinAVR ;-)
Od: "T.M.F." <t...@n...mp.pl>
W dniu 11.06.2009 15:02, Zbych pisze:
> T.M.F. pisze:
>>>>> ale czasem tak dla sportu zaglądam do pliku .lss i patrzę co tam
>>>>> kompilator wysmarował.
>>>> Moja rada - nie zaglądać. Ja co zajrzę to rzucam mięsem (a bo to brak
>>>> optymalizacji przy adresowaniu tablic struktur, albo przy pobieraniu
>>>> wielu stałych z flasha, albo przy alokacji ramki na stosie przy
>>>> przekazywaniu parametrów itd.)
>>>
>>> A ja ostatnio sporo dziubię na ARMa w gcc i przeglądając listing
>>> asemblerowy co chwila dziwię się, jak to optymalizator ładnie
>>> wykoncypował, że sam bym lepiej w asemblerze nie napisał. Tak że jedyna
>>> rada - zmienić platformę.
>>
>> Cos Zbych przesadza.
>
> Nie przesadza, wystarczy sprawdzić.
>
No zagladam dosyc czesto przy okazji debuggowania tego co napisalem.
Jakis koszmarnych brakow optymalizacji nie zauwazylem. Mozesz podac
konkretny przyklad w C, ktory jest zle optymalizowany? To zawsze mozna
zglosic jako bug.
--
Inteligentny dom - http://idom.wizzard.one.pl
http://idom.sourceforge.net/
Teraz takze forum dyskusyjne
Zobacz, wyslij uwagi, dolacz do projektu.
-
22. Data: 2009-06-12 07:54:41
Temat: Re: Problem lekko OT, ale w WinAVR ;-)
Od: Zbych <a...@o...pl>
T.M.F. pisze:
> No zagladam dosyc czesto przy okazji debuggowania tego co napisalem.
> Jakis koszmarnych brakow optymalizacji nie zauwazylem. Mozesz podac
> konkretny przyklad w C, ktory jest zle optymalizowany? To zawsze mozna
> zglosic jako bug.
To zależy co kto uważa za koszmarne. Poniżej parę przykładów, ale
wątpię, żeby komuś chciało się to czytać.
Wszystkie przykłady były optymalizowane na rozmiar.
----------------------------------------------------
-----
Testowanie warunków logicznych:
#define PIN1_IS_LOW (!(PINB & (1<<PINB7)))
#define PIN2_IS_LOW (!(PINB & (1<<PINB6)))
volatile uint8_t a;
asm volatile(";start");
a = (PIN1_IS_LOW || PIN2_IS_LOW);
asm volatile(";stop");
Kod wynikowy:
32 ;start
33 ; 0 "" 2
34 .LSM2:
35 /* #NOAPP */
36 000a 1F99 sbic 35-32,7
37 000c 00C0 rjmp .L2
38 000e 81E0 ldi r24,lo8(1)
39 0010 90E0 ldi r25,hi8(1)
40 0012 00C0 rjmp .L3
41 .L2:
42 0014 83B1 in r24,35-32
43 0016 90E0 ldi r25,lo8(0)
44 0018 26E0 ldi r18,6
45 001a 9695 1: lsr r25
46 001c 8795 ror r24
47 001e 2A95 dec r18
48 0020 01F4 brne 1b
49 0022 8095 com r24
50 0024 9095 com r25
51 0026 8170 andi r24,lo8(1)
52 0028 9070 andi r25,hi8(1)
53 .L3:
54 002a 8983 std Y+1,r24
55 .LVL0:
56 .LSM3:
57 /* #APP */
58 ; 96 "main.c" 1
59 ;stop
Pomijając już tą nieszczęsną promocję do inta, to najbardziej w tym
kodzie rozwaliło mnie wyłuskiwanie 6 bitu.
Delikatna modyfikacja kodu:
if (PIN1_IS_LOW || PIN2_IS_LOW) a = true;
else a = false;
daje już coś takiego:
62 /* #NOAPP */
63 002c 1F9B sbis 35-32,7
64 002e 00C0 rjmp .L4
65 0030 1E99 sbic 35-32,6
66 0032 00C0 rjmp .L5
67 .L4:
68 0034 81E0 ldi r24,lo8(1)
69 0036 8983 std Y+1,r24
70 .LVL1:
71 0038 00C0 rjmp .L6
72 .L5:
73 .LSM5:
74 003a 1982 std Y+1,__zero_reg__
75 .LVL2:
76 .L6:
----------------------------------------------------
------
Przygotowanie ramki na stosie dla 5 parametrów 16-bitowych:
1637 0068 ADB7 in r26,__SP_L__
1638 006a BEB7 in r27,__SP_H__
1639 006c 1A97 sbiw r26,10
1640 006e 0FB6 in __tmp_reg__,__SREG__
1641 0070 F894 cli
1642 0072 BEBF out __SP_H__,r27
1643 0074 0FBE out __SREG__,__tmp_reg__
1644 0076 ADBF out __SP_L__,r26
Przy dwóch parametrach:
1751 010e 00D0 rcall .
1752 0110 00D0 rcall .
Łatwo policzyć, że poniżej 8 parametrów bardziej opłaca się wersja z
rcall (program optymalizowany na rozmiar).
----------------------------------------------------
-------
Adresowanie struktur i pobieranie adresów z flasha:
typedef struct{
const prog_char * a;
const prog_char * b;
const prog_char * c;
const prog_char * d;
}Aqq;
prog_char s[] = "Aqq";
Aqq PROGMEM tab[]={
{s,s,s,s},
{s,s,s,s},
{s,s,s,s},
{s,s,s,s},
};
asm volatile (";start");
for (uint8_t i = 0; i < tab_size(tab); i++){
blabla( pgm_read_word( &tab[i].a ), pgm_read_word( &tab[i].b ),
pgm_read_word( &tab[i].c ), pgm_read_word( &tab[i].d ) );
}
asm volatile (";stop");
Pierwszy problem to wyliczanie adresu w flashu:
69 .LBB24:
70 0024 F901 movw r30,r18
71 .LVL4:
72 0026 E050 subi r30,lo8(-(tab+4))
73 0028 F040 sbci r31,hi8(-(tab+4))
74 /* #APP */
75 ; 106 "main.c" 1
76 002a 4591 lpm r20, Z+
77 002c 5491 lpm r21, Z
78
79 ; 0 "" 2
Pomimo, że jest (czy raczej mogłoby być) użyte adresowanie z
postinkrementacją, to adresy kolejnych elementów są i tak przed każdym
pobraniem na nowo wyliczane. W przykładzie, który podałem daje to 12
niepotrzebnych instrukcji w każdym obiegu tej krótkiej pętli i dodatkowo
zajętą parę rejestrów R19:R18.
Drugi problem, to wyliczanie od początku adresu komórki w tablicy przy
każdym obiegu pętli:
27 ;start
28 ; 0 "" 2
29 /* #NOAPP */
30 0000 C0E0 ldi r28,lo8(0)
31 0002 D0E0 ldi r29,hi8(0)
32 .L2:
33 .LBB21:
34 .LBB22:
35 .LSM2:
36 0004 9E01 movw r18,r28
37 0006 83E0 ldi r24,3
38 0008 220F 1: lsl r18
39 000a 331F rol r19
40 000c 8A95 dec r24
41 000e 01F4 brne 1b
42 0010 F901 movw r30,r18
43 .LVL0:
[...]
96 .LBE25:
97 0038 0E94 0000 call blabla
98 .LVL8:
99 003c 2196 adiw r28,1
100 .LSM3:
101 003e C430 cpi r28,4
102 0040 D105 cpc r29,__zero_reg__
103 0042 01F4 brne .L2
104 .LBE21:
105 .LSM4:
106 /* #APP */
107 ; 108 "main.c" 1
108 ;stop
Wystarczy prosty myk ze wskaźnikiem i pętla się skraca:
asm volatile (";start");
for (uint8_t i = 0; i < tab_size(tab); i++){
const Aqq * p = &tab[i];
blabla( pgm_read_word( &p->a ), pgm_read_word( &p->b ), pgm_read_word(
&p->c ), pgm_read_word( &p->d ) );
}
asm volatile (";stop");
27 ;start
28 ; 0 "" 2
29 /* #NOAPP */
30 0000 C0E0 ldi r28,lo8(tab)
31 0002 D0E0 ldi r29,hi8(tab)
[...]
87 0022 0E94 0000 call blabla
88 .LVL8:
89 0026 2896 adiw r28,8
90 .LBE23:
91 .LSM3:
92 0028 80E0 ldi r24,hi8(tab+32)
93 002a C030 cpi r28,lo8(tab+32)
94 002c D807 cpc r29,r24
95 002e 01F4 brne .L2
96 .LBE22:
97 .LSM4:
98 /* #APP */
99 ; 109 "main.c" 1
100 ;stop
1
A podobno gcc ma super optymalizator do pętli (widocznie moja wersja
gdzieś go zgubiła).
-
23. Data: 2009-06-12 08:14:05
Temat: Re: Problem lekko OT, ale w WinAVR ;-)
Od: Zbych <a...@o...pl>
Adam Dybkowski pisze:
> Zbych pisze:
>
>>> A ja ostatnio sporo dziubię na ARMa w gcc i przeglądając listing
>>> asemblerowy co chwila dziwię się, jak to optymalizator ładnie
>>> wykoncypował, że sam bym lepiej w asemblerze nie napisał. Tak że jedyna
>>> rada - zmienić platformę.
>> To pokaż mi jeszcze ARMa, który po zatrzymaniu zegara pobiera < 1uA.
>
> A cóż to za wymaganie? 1uA to pobiera dobry RTC a nie mikrokontroler.
To chyba nie jest wygórowane wymaganie dla _wyłączonego_ uC (ale
potrafiącego się wybudzić po zmianie stanu portów)? STM32 prawie by się
łapał, gdy nie to, że prąd w nim rośnie ze wzrostem temperatury.
> AVRy mają prąd upływu do 1uA na każdy pin I/O (patrzę w PDFa pierwszej z
> brzegu ATmegi 128) plus dodatkowo typowo 5uA (max. 10uA) w najgłębszym
> power-down i to przy wyłączonym watchdogu. Oprócz tego każdy obciążony
> pull-up zjada nieco prądu (typowa rezystancja to 20-50 kOhm). Daleko
> stąd raczej do magicznego 1uA.
> Jak chcesz oszczędzać prąd to bierz się raczej za rodzinę MSP430 a nie AVRy.
Spokojnie, nie tylko TI robi takie wynalazki. Atmel ma uC "pico-power",
Microchip "nono-watt".
Poza tym za 10zł dostaniesz najmniejszego MSP430 (4kB flash, 256B Ram).
Za podobne pieniądze mam ATmega324p, która spełnia moje wymagania co do
poboru prądu (i ma potrzebne peryferia). Zresztą jaką mam gwarancję, że
gcc będzie generowało lepszy kod na msp430 niż na avr?
(pamiętasz? polecałeś ARMa ze względu na lepsze wsparcie w gcc). Ruch na
liście mailingowej msp430-gcc jest raczej znikomy. Kolejna rzecz, to
zakres napięć zasilających. AVR mogę zasilić prosto z li-ion. Do MSP430
musiałbym dodać stabilizator (który też żre prąd na swoje potrzeby).
-
24. Data: 2009-06-12 09:05:51
Temat: Re: Problem lekko OT, ale w WinAVR ;-)
Od: Grzegorz Kurczyk <g...@c...slupsk.pl>
Użytkownik Zbych napisał:
> T.M.F. pisze:
>
>> No zagladam dosyc czesto przy okazji debuggowania tego co napisalem.
>> Jakis koszmarnych brakow optymalizacji nie zauwazylem. Mozesz podac
>> konkretny przyklad w C, ktory jest zle optymalizowany? To zawsze mozna
>> zglosic jako bug.
>
> To zależy co kto uważa za koszmarne. Poniżej parę przykładów, ale
> wątpię, żeby komuś chciało się to czytać.
>
> Wszystkie przykłady były optymalizowane na rozmiar.
>
>
> ----------------------------------------------------
-----
> Testowanie warunków logicznych:
>
> #define PIN1_IS_LOW (!(PINB & (1<<PINB7)))
> #define PIN2_IS_LOW (!(PINB & (1<<PINB6)))
>
> volatile uint8_t a;
> asm volatile(";start");
> a = (PIN1_IS_LOW || PIN2_IS_LOW);
> asm volatile(";stop");
>
Ooooo to, to :-) W programach unikam operacji logicznych na bitach
portów, bo wychodzą koszmarki. Czasem zamiast:
if((PINB & (1<<7)) && (PINC & (1<<3))) {...}
lepiej napisać
if(PINB & (1<<7))
if(PINC & (1<<3))
{...}
Z jakiś troszkę wcześniejszych wersji pamiętam, że samo wstawienie
operatora ! na bicie portu automatycznie generowało koszmarek z rozkazem
in i wyliczaniem stanu bitu na piechotę.
if(PINB & (1<<7)) {...} wyglądało poprawnie z użyciem sbic/sbis,
ale już:
if(!(PINB & (1<<7))) {...} generowało wspomniany przez Kolegę koszmarek
i w zastępstwie używałem:
if(PINB & (1<<7)) else {...} i juz było cacy na sbic/sbis
Co do adresowania tablic w pamięci FLASH w pętli to już od dawna stosuję
wyłącznie inkrementację wskaźnika, bo te każdorazowe wyliczanie adresu
też mnie biło w oczy :-)
P.S. Używam trochę starawej wersji 20070525, bo sprawia mi najmniej
problemów. Późniejsze wersje 2008xxxx sprawiły mi zbyt dużo psikusów i
trochę się zraziłem. Choć może warto wypróbować jakąś świeżynkę :-)
Pozdrawiam
Grzegorz
-
25. Data: 2009-06-12 10:29:46
Temat: Re: Problem lekko OT, ale w WinAVR ;-)
Od: Zbych <a...@o...pl>
T.M.F. pisze:
>> Pomijając już tą nieszczęsną promocję do inta, to najbardziej w tym
>> kodzie rozwaliło mnie wyłuskiwanie 6 bitu.
>
> Promocja do int wynika ze standardu C wiec trudno tu robić zarzut
> kompilatorowi. Żeby to ominąć wystarczy explicite typecastowac.
Wyraźnie napisałem, że nie promocja jest tu największym problemem.
Zresztą rzutowanie i tak tego nie poprawia.
>> Łatwo policzyć, że poniżej 8 parametrów bardziej opłaca się wersja z
>> rcall (program optymalizowany na rozmiar).
>
> Tu sprawa nie jest tak oczywista. Co prawda rcall są krótsze w sensie
> długości kodu, ale zajmuja 3 takty zegara.
Specjalnie napisałem, że optymalizacja była ustawiona na rozmiar, więc
rcall powinno mieć pierwszeństwo.
>
> To zalezy zapewne od zdefiniowanej przez ciebie funkcji tab_size(tab).
> Kompilator za każdym obiegiem petli musi ja wywołać, żeby wilczyć wynik
> dla danego argumentu - dlaczego? Bo ja źle zdefiniowałeś.
Zapomniałem wstawić. Oto kod:
#define tab_size(__a) (sizeof(__a)/sizeof(__a[0]))
Jeśli według ciebie jest źle zdefiniowana, to czekam na poprawki.
> Sprawdziłem to u siebie i nic takiego się nie dzieje. Musiałem
> zdefiniować dodatkowo dziwna funkcje Babla bo mi kompilator to
> optymalizował i ją wywalał.
Ja na potrzeby przykładu w ogóle jej nie zdefiniowałem (nie jest to
potrzebne, disasemblację zrobiłem po kompilacji, bez linkowania).
>> A podobno gcc ma super optymalizator do pętli (widocznie moja wersja
>> gdzieś go zgubiła).
>
> Jak ci nie pasuje gcc to zaproponuj cos lepszego...
Chciałeś przykłady, to ci je pokazałem. Nie jest w tym przypadku istotne
czy inne kompilatory zrobiłyby to lepiej (a myślę, że IAR byłby lepszy).
> Jak ci nie pasuje gcc to zaproponuj cos lepszego... nie mowiac juz o
> tym, ze masz kod źródłowy wiec możesz się wykazać dla potomności :)
Dzięki, już kiedyś próbowałem (na innym porcie gcc). To nie jest robota
na 1 dzień, a ja mam swoją pracę.
-
26. Data: 2009-06-12 11:27:41
Temat: Re: Problem lekko OT, ale w WinAVR ;-)
Od: Zbych <a...@o...pl>
T.M.F. pisze:
>>> Sprawdziłem to u siebie i nic takiego się nie dzieje. Musiałem
>>> zdefiniować dodatkowo dziwna funkcje Babla bo mi kompilator to
>>> optymalizował i ją wywalał.
>>
>> Ja na potrzeby przykładu w ogóle jej nie zdefiniowałem (nie jest to
>> potrzebne, disasemblację zrobiłem po kompilacji, bez linkowania).
>
> To wtedy petla sie totalnie zoptymalizowala i wywalilo mi te wywolania w
> ogole.
Eeee, coś musiałeś skopać. Jak kompilator może zoptymalizować coś czego
nie widzi?
cały przykład powinien wyglądać tak:
#define tab_size(__a) (sizeof(__a)/sizeof(__a[0]))
void blabla( uint16_t, uint16_t, uint16_t, uint16_t);
typedef struct{
const prog_char * a;
const prog_char * b;
const prog_char * c;
const prog_char * d;
}Aqq;
prog_char s[] = "Aqq";
Aqq PROGMEM tab[]={
{s,s,s,s},
{s,s,s,s},
{s,s,s,s},
{s,s,s,s},
};
asm volatile (";start");
for (uint8_t i = 0; i < tab_size(tab); i++){
blabla( pgm_read_word( &tab[i].a ), pgm_read_word( &tab[i].b ),
pgm_read_word( &tab[i].c ), pgm_read_word( &tab[i].d ) );
}
asm volatile (";stop");
-
27. Data: 2009-06-12 15:42:26
Temat: Re: Problem lekko OT, ale w WinAVR ;-)
Od: "T.M.F." <t...@n...mp.pl>
W dniu 12.06.2009 03:54, Zbych pisze:
> T.M.F. pisze:
>
>> No zagladam dosyc czesto przy okazji debuggowania tego co napisalem.
>> Jakis koszmarnych brakow optymalizacji nie zauwazylem. Mozesz podac
>> konkretny przyklad w C, ktory jest zle optymalizowany? To zawsze mozna
>> zglosic jako bug.
>
> To zależy co kto uważa za koszmarne. Poniżej parę przykładów, ale
> wątpię, żeby komuś chciało się to czytać.
>
> Wszystkie przykłady były optymalizowane na rozmiar.
>
>
> ----------------------------------------------------
-----
> Testowanie warunków logicznych:
>
> #define PIN1_IS_LOW (!(PINB & (1<<PINB7)))
> #define PIN2_IS_LOW (!(PINB & (1<<PINB6)))
>
> volatile uint8_t a;
> asm volatile(";start");
> a = (PIN1_IS_LOW || PIN2_IS_LOW);
> asm volatile(";stop");
>
> Pomijając już tą nieszczęsną promocję do inta, to najbardziej w tym
> kodzie rozwaliło mnie wyłuskiwanie 6 bitu.
Promocja do int wynika ze standardu C wiec trudno tu robić zarzut
kompilatorowi. Żeby to ominąć wystarczy explicite typecastowac.
> Delikatna modyfikacja kodu:
>
> if (PIN1_IS_LOW || PIN2_IS_LOW) a = true;
> else a = false;
Tu faktycznie jest jakiś problem z optymalizacja. Warto to zgłosić jako Bug.
> ----------------------------------------------------
------
> Przygotowanie ramki na stosie dla 5 parametrów 16-bitowych:
>
> 1637 0068 ADB7 in r26,__SP_L__
> 1638 006a BEB7 in r27,__SP_H__
> 1639 006c 1A97 sbiw r26,10
> 1640 006e 0FB6 in __tmp_reg__,__SREG__
> 1641 0070 F894 cli
> 1642 0072 BEBF out __SP_H__,r27
> 1643 0074 0FBE out __SREG__,__tmp_reg__
> 1644 0076 ADBF out __SP_L__,r26
>
> Przy dwóch parametrach:
>
> 1751 010e 00D0 rcall .
> 1752 0110 00D0 rcall .
>
> Łatwo policzyć, że poniżej 8 parametrów bardziej opłaca się wersja z
> rcall (program optymalizowany na rozmiar).
Tu sprawa nie jest tak oczywista. Co prawda rcall są krótsze w sensie
długości kodu, ale zajmuja 3 takty zegara. To co generuje gcc zajmuje
niezależnie od długości ramki 9 taktow, czyli 3 rcall. Sytuacja wyglada
jeszcze gorzej kiedy PC jest 22 bitowy - wtedy 4 takty. Wiec jak sadze
wybrano pewien kompromis pomiedzy długością kodu a czasem egzekucji.
>
>
>
> ----------------------------------------------------
-------
> Adresowanie struktur i pobieranie adresów z flasha:
>
> typedef struct{
> const prog_char * a;
> const prog_char * b;
> const prog_char * c;
> const prog_char * d;
> }Aqq;
>
> prog_char s[] = "Aqq";
>
> Aqq PROGMEM tab[]={
> {s,s,s,s},
> {s,s,s,s},
> {s,s,s,s},
> {s,s,s,s},
> };
>
> asm volatile (";start");
> for (uint8_t i = 0; i < tab_size(tab); i++){
> blabla( pgm_read_word( &tab[i].a ), pgm_read_word( &tab[i].b ),
> pgm_read_word( &tab[i].c ), pgm_read_word( &tab[i].d ) );
> }
> asm volatile (";stop");
>
>
> Pierwszy problem to wyliczanie adresu w flashu:
To zalezy zapewne od zdefiniowanej przez ciebie funkcji tab_size(tab).
Kompilator za każdym obiegiem petli musi ja wywołać, żeby wilczyć wynik
dla danego argumentu - dlaczego? Bo ja źle zdefiniowałeś.
> Pomimo, że jest (czy raczej mogłoby być) użyte adresowanie z
> postinkrementacją, to adresy kolejnych elementów są i tak przed każdym
> pobraniem na nowo wyliczane. W przykładzie, który podałem daje to 12
> niepotrzebnych instrukcji w każdym obiegu tej krótkiej pętli i dodatkowo
> zajętą parę rejestrów R19:R18.
>
> Drugi problem, to wyliczanie od początku adresu komórki w tablicy przy
> każdym obiegu pętli:
>
Sprawdziłem to u siebie i nic takiego się nie dzieje. Musiałem
zdefiniować dodatkowo dziwna funkcje Babla bo mi kompilator to
optymalizował i ją wywalał.
> Wystarczy prosty myk ze wskaźnikiem i pętla się skraca:
>
> asm volatile (";start");
> for (uint8_t i = 0; i < tab_size(tab); i++){
> const Aqq * p = &tab[i];
> blabla( pgm_read_word( &p->a ), pgm_read_word( &p->b ), pgm_read_word(
> &p->c ), pgm_read_word( &p->d ) );
> }
Tu problem jest bardziej dyskretny. C przy adresowaniu elementów
struktury używa adresowania z przemieszczeniem. W pierwszym przykładzie
pobierasz adresy konkretnego elementu, stad za każdym razem są pobierane
pełne adresy. Za drugim razem używasz adresu struktury i offsetów do jej
elementów (operator -> generuje offsety). Zauważ, że gdyby pola tej
struktury były duże - powyżej 127 bajtów, to i tak zaszłaby konieczność
pobrania pełnego adresu, bo offset byłby większy niż maksymalne
przemieszczenie. Oczywiście kompilator może sobie z tym poradzić,
niestety tu wychodzi jedna z wad gcc - jest to kompilator pod duże
procki, a AVR jest tylko specyficzną wspieraną platformą. Żeby ta
optymalizacja dobrze zadziałała trzebaby nieźle zamieszać w kodzie gcc.
A w sumie jeśli często się ogląda sesje typu połączony C+assembler to
człowiek szybko się uczy jaka składnia języka jest optymalna. Akurat
przy pętlach ze względu na specyfikę listy rozkazów AVR można się nieźle
wykazać.
> A podobno gcc ma super optymalizator do pętli (widocznie moja wersja
> gdzieś go zgubiła).
Jak ci nie pasuje gcc to zaproponuj cos lepszego... nie mowiac juz o
tym, ze masz kod źródłowy wiec możesz się wykazać dla potomności :)
--
Inteligentny dom - http://idom.wizzard.one.pl
http://idom.sourceforge.net/
Teraz takze forum dyskusyjne
Zobacz, wyslij uwagi, dolacz do projektu.
-
28. Data: 2009-06-12 15:47:28
Temat: Re: Problem lekko OT, ale w WinAVR ;-)
Od: "T.M.F." <t...@n...mp.pl>
> Ooooo to, to :-) W programach unikam operacji logicznych na bitach
> portów, bo wychodzą koszmarki. Czasem zamiast:
>
> if((PINB & (1<<7)) && (PINC & (1<<3))) {...}
>
> lepiej napisać
>
> if(PINB & (1<<7))
> if(PINC & (1<<3))
> {...}
To się mocno zmieniło w nowszych wersjach gcc. W wielu przypadkach to
się kompiluje do cbi/sbi. Z kolei ja ostatnio używam wyłącznie C++, więc
niewykluczone, że są tu pewne różnice w optymalizacji.
Inna sprawa, że jesli pisze program skladający się z kilku tysięcy linii
to wielu przypadkach efektywność generowanego kodu mnie nie interesuje.
A jesli mam miejsca czasowo krytyczne to zawsze mam inline assembler.
--
Inteligentny dom - http://idom.wizzard.one.pl
http://idom.sourceforge.net/
Teraz takze forum dyskusyjne
Zobacz, wyslij uwagi, dolacz do projektu.
-
29. Data: 2009-06-12 16:46:40
Temat: Re: Problem lekko OT, ale w WinAVR ;-)
Od: J.F. <j...@p...onet.pl>
On Thu, 11 Jun 2009 20:53:28 -0400, T.M.F. wrote:
>>>>> Inaczej kompilator musi utworzyc kopie obiektu tRect i ta kopie dopiero
>>>>> przekazac do funkcji.
>>>> W C++ moze to byc faktycznie kosztowne.
>>> W C tez powinno byc kosztowne. Bo skad kompilator ma wiedziec, ze Rysuj
>>> nie modyfikuje struktury tRect?
>> Nie musi wiedziec. Ma wrzucic cala na stos, co powinno pojsc dosc
>> szybko.
>
>Tak sie nie da. Jesli tRect jest gdzies dalej wykorzystywany to
>kompilator musi utworzyc jego kopie, zeby zagwarantowac, ze Rysuj jej
>nie zmodyfikuje - to wynika ze standardu.
"wrzucenie na stos" to wlasnie utworzenie kopii.
Tylko ze w zwyklym C bez obiektowej nadbudowy jest to operacja dosc
prosta i szybka, jesli struktura krotka. A jak jeszcze procek ma 16
czy 32 bitowe operacje push ...
>Oczywiscie optymalizator moze
>zauwazyc, ze nasze tRect jest dalej niewykorzystywane i z tego etapu
>zrezygnowac - no ale to juz zaklada, ze optymalizator jest dosc
>sensowny.
Musialby byc IMO az za bardzo sensowny.
>Ale mowimy konkretnie o AVR i AVR-gcc.
Ja tam patrze troche szerzej.
Jak juz sie pisze w C to dobrze by bylo nie pisac pod jeden procesor,
ktory w dodatku nie ma alternatywnego dostawcy :-)
J.
-
30. Data: 2009-06-12 17:14:53
Temat: Re: Problem lekko OT, ale w WinAVR ;-)
Od: "T.M.F." <t...@n...mp.pl>
>>> Pomijając już tą nieszczęsną promocję do inta, to najbardziej w tym
>>> kodzie rozwaliło mnie wyłuskiwanie 6 bitu.
>>
>> Promocja do int wynika ze standardu C wiec trudno tu robić zarzut
>> kompilatorowi. Żeby to ominąć wystarczy explicite typecastowac.
>
> Wyraźnie napisałem, że nie promocja jest tu największym problemem.
> Zresztą rzutowanie i tak tego nie poprawia.
U mnie poprawia - najnowszy WinAVR.
>>> Łatwo policzyć, że poniżej 8 parametrów bardziej opłaca się wersja z
>>> rcall (program optymalizowany na rozmiar).
>>
>> Tu sprawa nie jest tak oczywista. Co prawda rcall są krótsze w sensie
>> długości kodu, ale zajmuja 3 takty zegara.
>
> Specjalnie napisałem, że optymalizacja była ustawiona na rozmiar, więc
> rcall powinno mieć pierwszeństwo.
Tak, tylko developerzy sa skupieni na Os - tak to bywa, kiedy zasoby sa
ograniczone.
>> To zalezy zapewne od zdefiniowanej przez ciebie funkcji tab_size(tab).
>> Kompilator za każdym obiegiem petli musi ja wywołać, żeby wilczyć
>> wynik dla danego argumentu - dlaczego? Bo ja źle zdefiniowałeś.
>
> Zapomniałem wstawić. Oto kod:
>
> #define tab_size(__a) (sizeof(__a)/sizeof(__a[0]))
>
> Jeśli według ciebie jest źle zdefiniowana, to czekam na poprawki.
To powinno w efekcie dac stala. Kiedy zastapilem wywolanie tab_size
stala problem zniknal. Wiec byc moze uzywasz starej wersji?
>> Sprawdziłem to u siebie i nic takiego się nie dzieje. Musiałem
>> zdefiniować dodatkowo dziwna funkcje Babla bo mi kompilator to
>> optymalizował i ją wywalał.
>
> Ja na potrzeby przykładu w ogóle jej nie zdefiniowałem (nie jest to
> potrzebne, disasemblację zrobiłem po kompilacji, bez linkowania).
To wtedy petla sie totalnie zoptymalizowala i wywalilo mi te wywolania w
ogole.
>>> A podobno gcc ma super optymalizator do pętli (widocznie moja wersja
>>> gdzieś go zgubiła).
>>
>> Jak ci nie pasuje gcc to zaproponuj cos lepszego...
>
> Chciałeś przykłady, to ci je pokazałem. Nie jest w tym przypadku istotne
> czy inne kompilatory zrobiłyby to lepiej (a myślę, że IAR byłby lepszy).
IAR zwykle jest lepszy bo jest dostosowany do tej platformy, niestety
uniwersalnosc gcc jest tu jego wada. Z drugiej strony wada ta jest
kompensowana problemami na ktore sie natkniesz probujac przeniesc kod z
IAR na inna platforme.
>> Jak ci nie pasuje gcc to zaproponuj cos lepszego... nie mowiac juz o
>> tym, ze masz kod źródłowy wiec możesz się wykazać dla potomności :)
>
> Dzięki, już kiedyś próbowałem (na innym porcie gcc). To nie jest robota
> na 1 dzień, a ja mam swoją pracę.
Owszem. Ale wystarczy nieco wiedzy jak kompilator generuje kod i
wszystkie pokazane problemy znikaja. Sa co prawda inne, ktorych tak
prosto wyeliminowac sie nie da, ale skoro ich nie pokazales, to pewnie
nie sa dla ciebie tak klopotliwe :)
--
Inteligentny dom - http://idom.wizzard.one.pl
http://idom.sourceforge.net/
Teraz takze forum dyskusyjne
Zobacz, wyslij uwagi, dolacz do projektu.