eGospodarka.pl
eGospodarka.pl poleca

eGospodarka.plGrupypl.misc.elektronika › Problem lekko OT, ale w WinAVR ;-)
Ilość wypowiedzi w tym wątku: 61

  • 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.

strony : 1 . 2 . [ 3 ] . 4 ... 7


Szukaj w grupach

Szukaj w grupach

Eksperci egospodarka.pl

1 1 1

Wpisz nazwę miasta, dla którego chcesz znaleźć jednostkę ZUS.

Wzory dokumentów

Bezpłatne wzory dokumentów i formularzy.
Wyszukaj i pobierz za darmo: