GCC, optymalizacja kodu, uruchamianie i GDB Insight

Mar 13, 2006 15 Replies

Witam,



Mam takie pytanko male - do symulacji na GDB Insight zalecaja zeby stosowac optymalizacje kompilatora na 0. Rzeczywiscie przy optymalizacji typu s kod skacze raz do gory, raz w dol zamiast ladnie instrukcja po instrukcji. Przy zerowej optymalizacji - jest ok. Zauzwazylem jednak, ze program w ten sposob skompilowany (0) po wgraniu do procka sprawia, ze kod ktory dotychczas chodzil normalnie przestaje dzialac w rzeczywistym systemie. Przestaje dzialac np. obsluga klawiatury, I2C, LCD na przerwaniach...null... Po wgraniu najglupszego programu typu 'Led blink' widze, ze owszem kod dziala, ale strasznie wolno.... Zastanawiam sie czy to normalka i nie warto sie tym przejmowac i dla symulacji stosowac 'O', a dla rzeczywistej pracy 's'? Wyglada to tak, jakby wolniejsze dzialanie procka mialo wplyw na dzialanie programu - cos sie nie wyrabia czasowo? Chociaz wiekszosc krytycznych rzeczy mam na przerwaniach...ale moze na jakas flage czeka? Jakies podobne doswiadczenia w tej sprawie?



Procesor LPC2114.


A jakiego JTAG'a uzywasz? Bo ja kupilem na LPT - dziala kiepsko i bardzo wolno.

Zrobilem sobie klona Wigglera, calosc pod linuksem.

Widze, ze na comp.sys.arm rozwija sie bardzo podobny watek - zobaczymy czy bedzie jakas odpowiedz.

Nikt z Was nigdy nie kompilowal programu dla LPC za pomoca GCC z opcja -o0?

Jack Houseman napisał(a):

A jak go odpaliłeś z gdb? Próbowałem OCDRemote, ale Wigglera obsługują tylko wersje Windozowe, pod Linuxem nie obsługiwany. :-(

Sprobuj z OpenOCD - dziala pod linuksem, nawet z ECP (przynajmniej u mnie tak dziala :-))

W zasadzie tak sie zastanawiam a poropos debuggingu - jaki jest sens debugowac z opcja -o0, skoro i tak program docelowo bedzie kompilowany z opcja -os czy -o3? A roznice w kodzie zawsze jakies beda - choc niby funkcjonalnie jest to samo. Ostatnio ogladalem stronke gdzie byl przyklad jak kompilator zamienia funkcje w C na asm przy roznych optymalizacjach - dla opcji zero dodawal np. procedury odkladania na stosie niektorych rejestrow, a przy opcji -o3 nie (co nie bylo potrzebne, nie bylo odkladane).

Tak wiec program docelowy bedzie sie roznil od programu debugowanego, a przy tym jesli np. urzadzenie czyta dane z pamieci EEPROM i po ustawieniu opcji

0 ten odczyt z jakis powodow przestaje dzialac, to co mi z debugingu, jak dane z EEPROMU nie splynely do procesora? Moge sobie obejrzec, jak sie wykonuja instrukcje tylko - a to mozna rownie dobrze zrobic na symulatorze.

To juz chyba lepiej przecierpiec to skakanie w gore i w dol przy opcji -os, ale za to miec rzeczywisty program, dzialajacy w rzeczywistm systemie do dyspozycji. Na szczescie "step one asm instruction" dziala bez skokow - tyle tylko, ze trzeba wnikac w kod asemblerowy zeby rozgryzc o co chodzi :-)

No coz udalo mi sie znalezc zrodlo bledu, co nie znaczy, ze wiem dlaczego on powstaje...

Przyczyną jest pusta petla delay (wiedzialem dlaczego ich nie lubie ;-)

Ta nie dziala przy optymalizcji 0 - jak zauwazylem po osiagnieciu zera, nie zatrzymuje sie tylko przewija przez zero, a ze liczba 32bitowa, to....

{ for(; e; --e) { for(; d; --d) { asm volatile ("nop"); } } }

totez dodalem jawne sprecyzowanie warunku (powyzsza petla byla wzieta z przykladow "na pale") i teraz wyglada tak:

{ for(; e==0; --e) { for(; d==0; --d) { asm volatile ("nop"); } } } I ta dziala.

Co ciekawe powyzsza "zla" procedura dziala w glupim przykladzie z diodami LED (tylko znacznie wolniej), a w programie z przerwaniami - juz nie. Czyzby przerwania cos macily?

A jednoczesnie wykrylem, ze tylko jedna petla (bez zagniezdzania) dziala - bez podawania jawnego warunku zero.

Tak wiec cos tu kompilator chyba knoci - no chyba, ze ja o czyms nie wiem :-) Niestety w ARM ASM jestem jeszcze za cienki, zeby moc to przeanalizowac...

W kazdym razie widac jasno, ze zbytnie niedbanie o prawidlowe deklaracje, jawne porownania itd...moze prowadzic do takich kwiatkow...

Jack Houseman przemówił ludzkim głosem:

[...]
  1. Te pętle mają przeciwne warunki zakończenia
  2. Nie zapomniałeś przypadkiem o wpisaniu ile razy ma się ta pętla wykonać ?

Masz racje - przesymulowalem sobie wlasnie te petle i okazuje sie ze ta z warunkiem == wogole nie jest petla :-)) Po prostu od razu po wejsciu wychodzi. Natomiast petla z samym e dziala poprawnie - dekrementuje do zera i dopiero wychodzi.

No, czyli wracamy do punktu wyjscia - czemu te poprawne petle nie dzialaja w zerowym trybie optymalizacji?

Ale zdaje sie, ze nikt mi na to pytanie nie odpowie... Moze po jakims czasie to wyjdzie.

Jack Houseman przemówił ludzkim głosem:

W twoim kodzie nie widać, kiedy nadajesz licznikom pętli jakąkolwiek wartość. Jeśli tego nie robisz we wcześniejszym fragmencie kodu to wartość opóźnienia twojej pętli (zewnętrznej) jest przypadkowa (co nie oznacza, że nie jest powtarzalna). Do tego w zależności od stopnia optymalizacji zmienne e i d mogą wylądować na stosie, w rejestrach, albo obie pętle mogą być całkowicie wywalone przez optymalizację. Jeśli koniecznie chcesz w taki sposób realizować opóźnienia, to chociaż przeczytaj sobie o "volatile" i sprawdź jak kompilator "obsługuje" zmienne z volatile i bez.

W poprzednicm poscie pokazalem oczywiscie tylko fragment funkcji - oczywiscie jest inicjalizacja. Funkcja jest zdeklarowana, a wywolywana z parametrem np. delay(10000,10000)

Funkcja Delay to tylko tymczasowo jako pewnego rodzaju substytut funkcjonalny kodu. Po prostu wycialem i wkleilem z innego kodu, bo bylo mi to akurat w pewnym momencie potrzebne. Napisalem przeciez kilka postow wyzej, ze nie cierpie martwych petli :-)

No dobrze - zadeklaruje te zmienne jako volatile i zobaczymy czy to poprawi sytuacje.

A nie dzialaja ? Jesli liczby sa 32 bit to odliczanie chwile trwa. Warto tez zobaczyc jak to skompilowano - moze mu ten nop zaszkodzil ?

J.

Niestety - zdeklarowanie zmiennych jako volatile nic nie dalo. Co gorsza odkrylem wlasnie ze jeszcze inny fragment kodu nie dziala po kompilacji 0 jak powinien. Zamiast odczytywac 16 bajtow z EEPROMU, to sieje po wyswietlaczu LCD (z tym, ze ladnie sieje, tzn. komunikatem, ktory normalnie pojawia sie podczas starupu (powitalnym) Czyli to nie tylko problem z petla, a cos ogolnie z programem. Moze przerwania? Mam tu ustawione przerwania od 2 timerow, I2C i portu szeregowego przy czym timerowe generuja sie z czestotliwoscia 1kHz i 400Hz. Wykorzystalem tu gotowe przylady w ktorych przerwania sa zdefiniowane jako 'naked', a zapamietywanie i zdejmowanie ze stosu rejestrow jest realizowane jako wstawki assemblerowe. Jest to podebrane z biblioteki armlib by Procyon jesli ktos kojarzy. Niestety - nie analizowalem tego kodu, bo skoro biblioteka gotowa, to chyba po to zeby z niej skorzystac (chociaz znalazlem w niej jeden blad - literowke)

No ladnie - czlowiek sobie programuje, wszystko mu pieknie dziala, a potem ustawia inna opcje optymalizacji i program zaczyna sie niedopuszczalnie krzaczyc. Zaczynam doceniac pisanie w asssemblerze (jak dotad) :-)

Wczesniej bylo bez nopu i na petlach typu while - tez to samo. Po prostu szedl w maliny.

No - wyjasnilem :-) Jednak przerwania od I2C. Zamiast naked+asm dalem tradycyjna deklaracje IRQ i poszlo. Procedurka juz nie glupieje, petle tez zachowuja sie normalnie. Ufff....wraca mi wiara w C ;-) Na ekranie sie jednak lepiej mysli jak slusznie zauwazyl T.M.F.

A swoja droga debbuger nic nie pokazywal - tylko w trybie continue uklad zachowywal sie blednie - przy pracy krokowej wszystko ok.

Jak już to: for(; e>0; --e) { for(; d>0; --d) { asm volatile ("nop"); } }

A i tak dla mnie bardziej czytelne będzie: while(e>0) { while (d>0) { asm volatile ("nop"); d--; } e--; }

Albo jeszcze krocej: while(e-- > 0) { while (d-- > 0) { asm volatile ("nop"); } }

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required