logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

AVR [C] Optymalizacja kodu przy konwersji LittleEndian na BigEndian

jp_elek 01 Mar 2018 14:51 1992 8
  • #1 17072510
    jp_elek
    Poziom 9  
    Witam,
    po długim czasie znów wypadło mi "skrobnąć" małą rzecz , jednak z dużą ilością danych z AVR ( często po około 100 uint16_t ) na (uint16_t dla ModBus'a).
    Kombinuję już którąś godzinę , a to deklarując zmienne jako strukturę, a to jako tablicę uint8_t , a to jawnie rzutując poszczególne bajty ...

    Problem w tym iż (Atmel Studio 7.0.1645 z akt. toolchainem) produkuje kod
    delikatnie mówiąc co najmniej 50 % wolniejszy niż potrzeba .

    wersja [C] usiłująca na piechotę poinformować kompilator jak to ma zrobić :
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    produkuje taki ( z wszystkich wyprodukowanych ten jest najkrótszy ):
    Kod: AVR assembler
    Zaloguj się, aby zobaczyć kod


    a oczywistą oczywistością wydaje się że powinien to być banał w rodzaju (kopiowanie uint16_t - LE na BE):

    LDI XL ,Low( AdrPobrania)
    LDI XH , High(AdrPobrania) ;r26:r27 to rej. wsk X
    LDI ZL ,Low( AdrPrzeznaczenia)
    LDI ZH , High(AdrPrzeznaczenia) ;r30:r31 to rej. wsk Z
    ; i lecimy ile by tego nie było
    ld r24,X+ ; odwróc pierwszą parę
    ld r25,X+
    st Z+, r25
    st Z+, r24
    ld r24,X+ ; odwróc kolejną parę
    ld r25,X+
    st Z+, r25
    st Z+, r24
    itd.

    Jest ktoś w stanie podpowiedzieć skuteczniejszą konstrukcję ?
    Z góry dziękuję za pomoc J.P.
  • #2 17072536
    grko
    Poziom 33  
    jp_elek napisał:

    Jest ktoś w stanie podpowiedzieć skuteczniejszą konstrukcję ?


    Tak. Znam dla gcc:
    Cytat:

    Built-in Function: uint16_t __builtin_bswap16 (uint16_t x)

    Returns x with the order of the bytes reversed; for example, 0xaabb becomes 0xbbaa. Byte here always means exactly 8 bits.

    Built-in Function: uint32_t __builtin_bswap32 (uint32_t x)

    Similar to __builtin_bswap16, except the argument and return types are 32 bit.

    Built-in Function: uint64_t __builtin_bswap64 (uint64_t x)

    Similar to __builtin_bswap32, except the argument and return types are 64 bit.
  • Pomocny post
    #3 17072602
    michalko12
    Specjalista - Mikrokontrolery
    Spróbuję zgadnąć: -O0?
    A poza tym nie wiadomo o co chodzi w tych załączonych szczątkach kodu.


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #4 17072674
    jp_elek
    Poziom 9  
    @micha_łko12
    Nie , próbowałem wszystkie dostępne opcje optymalizacji.

    Przykład w "C" to wersja "na siłę"
    - zmienne są już najprostszymi tablicami uint8_t

    - problemem jest to iż kompilator nie używa instrukcji z postinkrementacją
    a zamiast tego wstawia cudaczne (dla każdych dwu bajtów )

    adiw r26, offset

    r24, X // ładuj niski bajt

    sbiw r26, 0x02 ; offset
    adiw r26, 0x03 ; offset +1

    ld r25,X // ładuj wysoki bajt

    ps. pomijam już używanie std Z+a, zamiast prostego st Z+ - ale zapewne wynika
    to z krótkiego zakresu w tym przykładzie

    ps. jako "cienias" z C chce załapać mechanizm zapisu, aby uzyskać efekt

    Dodano po 37 [minuty]:

    @michalko12

    Jest poprawa , ale nie to co powinno, Twój przykład produkuje taki algorytm cykliczny dla każdej zamiany :

    540: 2d 91 ld r18, X+
    542: 3d 91 ld r19, X+
    544: 32 27 eor r19, r18
    546: 23 27 eor r18, r19
    548: 32 27 eor r19, r18
    54a: 21 93 st Z+, r18
    54c: 31 93 st Z+, r19

    ps. teraz nadmiarowość (w cyklach - użyte do niezbędnych ) 11/8 a było 14/8
    ps2. zabawa jest o tyle ważna iż składam dane do wysyłki z wielu procesów i muszę to zamknąć w sekcji krytycznej ( jest ich 112 sztuk uint16_t) a to już długi czas
  • #5 17073279
    JacekCz
    Poziom 42  
    1. Głosuję na @grko , tej platformy w tym względzie nie disasemblowałem, inne tak, wbudowane funkcje swap to często to jest wykonanie idealnie pasującego jednego rozkazu maszynowego. Mimo, że wygląda jak funkcja, nie ma narzutu stosu itd...
    2. Widzę ochotę na pisanie w mixie wstawek asemblerowcych C i klasycznego C. Gdybym był twórcą kompilatora, w takiej miksowanej funkcji ograniczył bym optymalizację albo w ogóle ją zawiesił. Np kompilator ma prawo zamienić kolejność odczytu dwóch komórek, ale nie dwóch portów. Wydaje mi się jak przez mgłę, ze coś takiego jest w dokumentacji avr-gcc, ale nie przywołam.

    ps. sekcje krytyczne nie muszą zamykać takiego kodu, gdzie konkurencja nie może zajść, jak przygotowanie oddzielnych danych (buforów) itd ... o ile takie są. Może wystarczyć zabezpieczenie na chwile krytyczne, zarządzanie całym gotowym buforem/start wysyłki
  • #6 17073481
    jp_elek
    Poziom 9  
    @JacekCz

    Użycie funkcji
    uint16_t __builtin_bswap16 (uint16_t wartosc)
    produkuje kod na jedną zamianę kolejności bajtów:

    ld r24, X+
    ld r25, X
    sbiw r26, 0x03 ; offset
    std Z+(a), r24 ;
    std Z+(a+1), r25 ;
    adiw r26, 0x04 ; offset+1

    to kolejny cykl mniej, teraz już 10/8 na każdą przekopiowaną uint16_t
  • Pomocny post
    #7 17073514
    grko
    Poziom 33  
    @jp_elek Jeżeli musisz optymalizowac tego typu rzeczy w swoim programie to albo coś poszło nie tak na etapie projektowania i wybierania odpowiedniego MCU. Albo coś poszło nie tak podczas implementacji.
  • #8 17073586
    jp_elek
    Poziom 9  
    Dzięki wszystkim,

    @grko -bez stresu :D
    W "C" bywam tylko hobbystą i to z konieczności, "wyrosłem" na asm.
    i to raczej się nie zmieni, jak już coś robię to chcę "naj. jak się da"
    Po prostu widząc iż na tym forum głównie odpowiadają zawodowcy,
    chciałem po prostu upewnić się iż mój "wynik" nie jest konsekwencją
    nonszalancji w rodzaju " byle jak ,byle było"
    J.P.
  • #9 17073802
    Konto nie istnieje
    Konto nie istnieje  
REKLAMA