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

[avr-gcc] Problem z objętością kodu wynikowego

anomelif 27 Gru 2008 01:32 2198 4
  • #1 5906892
    anomelif
    Poziom 12  
    Witam.

    Przytrafił mi się ciekawy problem, którego nijak nie potrafię rozwiązać.
    Piszę procedurkę do odczytu kart mmc/sd pod attiny2313 -ponieważ nie ma w tym procku SPI, użyłem USI. Aby uzyskać maksymalną prędkość transmisji zastosowałem się do wskazówek zawartych w dokumentacji procka i napisałem funkcję wysyłania/odbierania bajtu z softwareowym taktowaniem USI:

    
    uint8_t spi_byte(uint8_t byte)
    {
    	USIDR=byte;
    
    	register uint8_t tik=(1<<USIWM0)|(0<<USICS0)|(1<<USITC);
    	register uint8_t tak=(1<<USIWM0)|(0<<USICS0)|(1<<USITC)|(1<<USICLK);
    
    //8 taktów zeara, żeby wysłać /odebrać cały bajt
    	USICR=tik;
    	USICR=tak;
    	USICR=tik;
    	USICR=tak;
    	USICR=tik;
    	USICR=tak;
    	USICR=tik;
    	USICR=tak;
    	USICR=tik;
    	USICR=tak;
    	USICR=tik;
    	USICR=tak;
    	USICR=tik;
    	USICR=tak;
    	USICR=tik;
    	USICR=tak;
    
    	return USIDR;
    }


    No i tu pojawia się problem...

    Przy każdym wywołaniu tej funkcji kompilator traktuje ją jako inline co w efekcie daje niesamowicie spuchnięty kod wynikowy. Np funkcja:

    
    void mmc_send_command(uint8_t command, uint16_t px, uint16_t py)
    {
    	register union u16convert r;
    
    	MMC_CS_PORT &= ~(1 << MMC_CS); 	//  CS
    	spi_byte(0xff);			
    	spi_byte(command | 0x40);
    
    	r.value = px;
    	spi_byte(r.bytes.high);	
    	spi_byte(r.bytes.low);	
    
    	r.value = py;
    	spi_byte(r.bytes.high);	
    	spi_byte(r.bytes.low);	
    
    	spi_byte(0x95);	// poprawne CRC dla pierwszej komendy SPI
    	spi_byte(0xff);		
    }
    


    generuje taki oto piękny kod:

    
       +000001DD: 98C4      CBI     0x18,4
       +000001DE: EF3F      LDI     R19,0xFF          ; 0xFF = 0b11111111 = 255
       +000001DF: B93F      OUT     0xF,R19
       +000001E0: E121      LDI     R18,0x11          ; 0x11 = 0b00010001 = 17
       +000001E1: B92D      OUT     0xD,R18
       +000001E2: E193      LDI     R25,0x13          ; 0x13 = 0b00010011 = 19
       +000001E3: B99D      OUT     0xD,R25
       +000001E4: B92D      OUT     0xD,R18
       +000001E5: B99D      OUT     0xD,R25
       +000001E6: B92D      OUT     0xD,R18
       +000001E7: B99D      OUT     0xD,R25
       +000001E8: B92D      OUT     0xD,R18
       +000001E9: B99D      OUT     0xD,R25
       +000001EA: B92D      OUT     0xD,R18
       +000001EB: B99D      OUT     0xD,R25
       +000001EC: B92D      OUT     0xD,R18
       +000001ED: B99D      OUT     0xD,R25
       +000001EE: B92D      OUT     0xD,R18
       +000001EF: B99D      OUT     0xD,R25
       +000001F0: B92D      OUT     0xD,R18
       +000001F1: B99D      OUT     0xD,R25
       +000001F2: B1EF      IN      R30,0xF
       +000001F3: 6480      ORI     R24,0x40          ; 0x40 = 0b01000000 = 64
       +000001F4: B98F      OUT     0xF,R24
       +000001F5: B92D      OUT     0xD,R18
       +000001F6: B99D      OUT     0xD,R25
       +000001F7: B92D      OUT     0xD,R18
       +000001F8: B99D      OUT     0xD,R25
       +000001F9: B92D      OUT     0xD,R18
       +000001FA: B99D      OUT     0xD,R25
       +000001FB: B92D      OUT     0xD,R18
       +000001FC: B99D      OUT     0xD,R25
       +000001FD: B92D      OUT     0xD,R18
       +000001FE: B99D      OUT     0xD,R25
       +000001FF: B92D      OUT     0xD,R18
       +00000200: B99D      OUT     0xD,R25
       +00000201: B92D      OUT     0xD,R18
       +00000202: B99D      OUT     0xD,R25
       +00000203: B92D      OUT     0xD,R18
       +00000204: B99D      OUT     0xD,R25
       +00000205: B18F      IN      R24,0xF
       +00000206: B97F      OUT     0xF,R23
       +00000207: B92D      OUT     0xD,R18
       +00000208: B99D      OUT     0xD,R25
       +00000209: B92D      OUT     0xD,R18
       +0000020A: B99D      OUT     0xD,R25
       +0000020B: B92D      OUT     0xD,R18
       +0000020C: B99D      OUT     0xD,R25
       +0000020D: B92D      OUT     0xD,R18
       +0000020E: B99D      OUT     0xD,R25
       +0000020F: B92D      OUT     0xD,R18
       +00000210: B99D      OUT     0xD,R25
       +00000211: B92D      OUT     0xD,R18
       +00000212: B99D      OUT     0xD,R25
       +00000213: B92D      OUT     0xD,R18
       +00000214: B99D      OUT     0xD,R25
       +00000215: B92D      OUT     0xD,R18
       +00000216: B99D      OUT     0xD,R25
       +00000217: B18F      IN      R24,0xF
       +00000218: B96F      OUT     0xF,R22
       +00000219: B92D      OUT     0xD,R18
       +0000021A: B99D      OUT     0xD,R25
       +0000021B: B92D      OUT     0xD,R18
       +0000021C: B99D      OUT     0xD,R25
       +0000021D: B92D      OUT     0xD,R18
       +0000021E: B99D      OUT     0xD,R25
       +0000021F: B92D      OUT     0xD,R18
       +00000220: B99D      OUT     0xD,R25
       +00000221: B92D      OUT     0xD,R18
       +00000222: B99D      OUT     0xD,R25
       +00000223: B92D      OUT     0xD,R18
       +00000224: B99D      OUT     0xD,R25
       +00000225: B92D      OUT     0xD,R18
       +00000226: B99D      OUT     0xD,R25
       +00000227: B92D      OUT     0xD,R18
       +00000228: B99D      OUT     0xD,R25
       +00000229: B18F      IN      R24,0xF
       +0000022A: B95F      OUT     0xF,R21
       +0000022B: B92D      OUT     0xD,R18
       +0000022C: B99D      OUT     0xD,R25
       +0000022D: B92D      OUT     0xD,R18
       +0000022E: B99D      OUT     0xD,R25
       +0000022F: B92D      OUT     0xD,R18
       +00000230: B99D      OUT     0xD,R25
       +00000231: B92D      OUT     0xD,R18
       +00000232: B99D      OUT     0xD,R25
       +00000233: B92D      OUT     0xD,R18
       +00000234: B99D      OUT     0xD,R25
       +00000235: B92D      OUT     0xD,R18
       +00000236: B99D      OUT     0xD,R25
       +00000237: B92D      OUT     0xD,R18
       +00000238: B99D      OUT     0xD,R25
       +00000239: B92D      OUT     0xD,R18
       +0000023A: B99D      OUT     0xD,R25
       +0000023B: B18F      IN      R24,0xF
       +0000023C: B94F      OUT     0xF,R20
       +0000023D: B92D      OUT     0xD,R18
       +0000023E: B99D      OUT     0xD,R25
       +0000023F: B92D      OUT     0xD,R18
       +00000240: B99D      OUT     0xD,R25
       +00000241: B92D      OUT     0xD,R18
       +00000242: B99D      OUT     0xD,R25
       +00000243: B92D      OUT     0xD,R18
       +00000244: B99D      OUT     0xD,R25
       +00000245: B92D      OUT     0xD,R18
       +00000246: B99D      OUT     0xD,R25
       +00000247: B92D      OUT     0xD,R18
       +00000248: B99D      OUT     0xD,R25
       +00000249: B92D      OUT     0xD,R18
       +0000024A: B99D      OUT     0xD,R25
       +0000024B: B92D      OUT     0xD,R18
       +0000024C: B99D      OUT     0xD,R25
       +0000024D: B18F      IN      R24,0xF
       +0000024E: E985      LDI     R24,0x95          ; 0x95 = 0b10010101 = 149
       +0000024F: B98F      OUT     0xF,R24
       +00000250: B92D      OUT     0xD,R18
       +00000251: B99D      OUT     0xD,R25
       +00000252: B92D      OUT     0xD,R18
       +00000253: B99D      OUT     0xD,R25
       +00000254: B92D      OUT     0xD,R18
       +00000255: B99D      OUT     0xD,R25
       +00000256: B92D      OUT     0xD,R18
       +00000257: B99D      OUT     0xD,R25
       +00000258: B92D      OUT     0xD,R18
       +00000259: B99D      OUT     0xD,R25
       +0000025A: B92D      OUT     0xD,R18
       +0000025B: B99D      OUT     0xD,R25
       +0000025C: B92D      OUT     0xD,R18
       +0000025D: B99D      OUT     0xD,R25
       +0000025E: B92D      OUT     0xD,R18
       +0000025F: B99D      OUT     0xD,R25
       +00000260: B18F      IN      R24,0xF
       +00000261: B93F      OUT     0xF,R19
       +00000262: B92D      OUT     0xD,R18
       +00000263: B99D      OUT     0xD,R25
       +00000264: B92D      OUT     0xD,R18
       +00000265: B99D      OUT     0xD,R25
       +00000266: B92D      OUT     0xD,R18
       +00000267: B99D      OUT     0xD,R25
       +00000268: B92D      OUT     0xD,R18
       +00000269: B99D      OUT     0xD,R25
       +0000026A: B92D      OUT     0xD,R18
       +0000026B: B99D      OUT     0xD,R25
       +0000026C: B92D      OUT     0xD,R18
       +0000026D: B99D      OUT     0xD,R25
       +0000026E: B92D      OUT     0xD,R18
       +0000026F: B99D      OUT     0xD,R25
       +00000270: B92D      OUT     0xD,R18
       +00000271: B99D      OUT     0xD,R25
       +00000272: B18F      IN      R24,0xF
       +00000273: 9508      RET
    


    Zabawa z flagami optymalizacji, modyfikatorami register czy zawartością samej funkcji nic w tej materii nie zmienia.

    Czy ktoś ma pomysł jak ten problem rozwiązać? Cy można wymusić na kompilatorze, aby funkcja NIE BYŁA inline?
  • Pomocny post
    #3 5907468
    BoskiDialer
    Poziom 34  
    1/ zebrać dane do tablicy i pętlą, lub
    2/ wyciągnąć funkcję do osobnego pliku c.

    Przypadek pierwszy powinien być dobry, ale jeśli kompilator postanowi rozwinąć pętlę, to do niczego to nie doprowadzi. Kontrola iteracji w pętli + pobieranie danych + właściwa część (dec, brne, ld, 17[lub 18]*out: 22 lub 23 cykle), przygotowanie wartości USICR można wyciągnąć poza pętlę.

    Drugie rozwiązanie gwarantuje, że funkcja nie zostanie dołączona inline, gdyż nie jest dostępna w czasie kompilowania aktualnego pliku. Jednak w takim przypadku traci się na szybkości: 18 cykli z transmisji, 2 cykle z przygotowania wartości rejestrów, 7 cykli z wywołania funkcji (już 27) a jeszcze trzeba uwzględnić, że funkcja wywołująca musi odłożyć niektóre niższe rejestry na stos (i przenieść do nich zmienne), aby móc wywołać zewnętrzną funkcję.

    Najlepszym rozwiązaniem, kompromisem pomiędzy obiema metodami jest zewnętrzna funkcja do transferu bloku o dowolnym rozmiarze - funkcja taka na pewno przyda się w dalszych fragmentach programu, minimum objętości przy stosunkowo dużej szybkości.
  • Pomocny post
    #4 5907556
    Dr.Vee
    VIP Zasłużony dla elektroda
    Co do odpowiedzi na pytanie:
    uint8_t spi_byte(uint8_t byte) __attribute__ ((noinline));
    uint8_t spi_byte(uint8_t byte)
    {
        /* ciało funkcji */
    }


    Rozwiązanie z funkcją wysyłającą w pętli bajty z tablicy byłoby pewnie najlepsze (jak radził BoskiDialer). Ew. można zrobić 2 osobne funkcje - wyślij bajt i wyślij tablicę bajtów, z czego ta druga nie korzysta z pierwszej (żeby wyeliminować narzut wywołania funkcji).

    Pozdrawiam,
    Dr.Vee
  • #5 5907763
    anomelif
    Poziom 12  
    Dzięki Boski, jesteś boski ;)

    Potraktowanie problemu pętlą nie zadziałało - kompilator co prawda jej nie rozwinął, ale każde wywołanie spi_byte w innych miejscach programu było kompilowane inline, więc zamierzony efekt osiągnięty został hmmm... połowicznie.

    Wydzielenie spi_byte do odrębnego pliku i dolinkowywanie zadziałało natomiast rewelacyjnie - po optymalizacji całość, wraz z wywołaniem wykonuje się 30 cykli i nawet nie bawi się stosem.

    Pytanie tylko się nasuwa: jeśli kompilator wykaże się fantazją i wszystkie funkcje zacznie robić inline, to co wtedy? Rozdziabać program na n plików po jednej funkcji w każdym? Wiem, wiem, to czarny scenariusz i raczej nierealny.
    Chodzi mi jedynie o to, czy jesteśmy w stanie wpływać w jakiś sposób w tej kwestii na kompilator, czy jedynie pozostają nam w/w sztuczki i nadzieja że będzie ok?
    avr-gcc ma w trąbę przełączników do optymalizacji kodu - właśnie się wczytuję w doc.
     Optimization Options
               -falign-functions=n  -falign-jumps=n -falign-labels=n  -falign-loops=n -fbounds-check -fmudflap -fmudflapth -fmudflapir
               -fbranch-probabilities -fprofile-values -fvpt -fbranch-target-load-optimize -fbranch-target-load-optimize2 -fbtr-bb-exclusive
               -fcaller-saves  -fcprop-registers  -fcse-follow-jumps -fcse-skip-blocks  -fcx-limited-range  -fdata-sections -fdelayed-branch
               -fdelete-null-pointer-checks -fearly-inlining -fexpensive-optimizations  -ffast-math  -ffloat-store -fforce-addr  -ffunc‐
               tion-sections -fgcse  -fgcse-lm  -fgcse-sm  -fgcse-las  -fgcse-after-reload -fcrossjumping  -fif-conversion  -fif-conversion2
               -finline-functions  -finline-functions-called-once -finline-limit=n  -fkeep-inline-functions -fkeep-static-consts  -fmerge-con‐
               stants  -fmerge-all-constants -fmodulo-sched -fno-branch-count-reg -fno-default-inline  -fno-defer-pop -fmove-loop-invariants
               -fno-function-cse  -fno-guess-branch-probability -fno-inline  -fno-math-errno  -fno-peephole  -fno-peephole2 -funsafe-math-opti‐
               mizations  -funsafe-loop-optimizations  -ffinite-math-only -fno-toplevel-reorder -fno-trapping-math  -fno-zero-initial‐
               ized-in-bss -fomit-frame-pointer  -foptimize-register-move -foptimize-sibling-calls  -fprefetch-loop-arrays -fprofile-generate
               -fprofile-use -fregmove  -frename-registers -freorder-blocks  -freorder-blocks-and-partition -freorder-functions -fre‐
               run-cse-after-loop -frounding-math -frtl-abstract-sequences -fschedule-insns  -fschedule-insns2 -fno-sched-interblock
               -fno-sched-spec  -fsched-spec-load -fsched-spec-load-dangerous -fsched-stalled-insns=n -fsched-stalled-insns-dep=n
               -fsched2-use-superblocks -fsched2-use-traces -fsee -freschedule-modulo-scheduled-loops -fsection-anchors  -fsignaling-nans
               -fsingle-precision-constant -fstack-protector  -fstack-protector-all -fstrict-aliasing  -fstrict-overflow  -ftracer
               -fthread-jumps -funroll-all-loops  -funroll-loops  -fpeel-loops -fsplit-ivs-in-unroller -funswitch-loops -fvariable-expan‐
               sion-in-unroller -ftree-pre  -ftree-ccp  -ftree-dce -ftree-loop-optimize -ftree-loop-linear -ftree-loop-im -ftree-loop-ivcanon
               -fivopts -ftree-dominator-opts -ftree-dse -ftree-copyrename -ftree-sink -ftree-ch -ftree-sra -ftree-ter -ftree-lrs -ftree-fre
               -ftree-vectorize -ftree-vect-loop-version -ftree-salias -fipa-pta -fweb -ftree-copy-prop -ftree-store-ccp -ftree-store-copy-prop
               -fwhole-program --param name=value -O  -O0  -O1  -O2  -O3  -Os


    Czy ktoś się w to już wgłębiał? Ze swojej strony pobawię się tym trochę i jeśli tylko dojdę do jakichkolwiek konstruktywnych wniosków, przedstawię je na forum.

    ps.
    Dr.Vee
    można zrobić 2 osobne funkcje - wyślij bajt i wyślij tablicę bajtów

    Tak właśnie uczyniłem - kompromis pomiędzy rozmiarem a wydajnością - dziękuję za pomysł.
REKLAMA