Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Program do oszacowania zużycia zasobów dla kompilatora sdcc dla PIC18XXXX

trol.six 15 Feb 2020 12:22 13704 1
  • Program do oszacowania zużycia zasobów dla kompilatora sdcc dla PIC18XXXX

    Napisałem, a w zasadzie jeszcze coś nie coś chce napisać, programik który analizuje dane z plików *asm wygenerowanych przez kompilator sdcc dla mikrokontrolerów serii PIC18XXXX.

    Program ma być pomocny w określaniu zasobów które może zużyć program który piszemy na mikrokontroler. Po prostu przy większym programie można łatwiej to ogarnąć.

    Działa z wersją sdcc 3.6.0. Jak z innymi, nie wiem. Generalnie program pisałem pod linuksa którego używam, ale że nie używa jakiś nadzwyczajnych funkcji, być może da się bez problemu skompilować na inne systemy.

    Możliwości, opcje:

    1. -a wszystkie pliki asm
    analizuje pliki *asm i tworzy plik _listnamefun.txt, oraz wyświetla informacje indywidualne funkcji np:

    Code:

                                    codename sstck  regx  regf  ramf  rams resstack
                              S_pff__pf_read   52    40    40   107   111     0
                              S_pff__pf_open   27    40    18   107   111     0
                             S_pff__pf_mount   44    40    33   107   111     0

                                    codename sstck  regx  regf  ramf  rams resstack
                      S_t07t_ivec_0x2_tc_int    0     4     0    54   165     0
                     S_t07t_ivec_0x1_tch_int    0     4     0    54   165     0
                                S_t07t__main    8     4     2    54   165     0
                             S_t07t__tch_int    9     4     0    54   165     0
                              S_t07t__tc_int    9     4     0    54   165     0


    codename - nazwa asemblerowa
    sstck - zużycie stosu programowego przez funkcje
    regx - maxymalne zużycie rejestrów na plik *(1)
    regf - maxymalne zużycie rejestrów na funkcje
    ramf - zarezerwowana ilość ram
    rams - sumaryczna zarezerwowana ilość ram
    resstack - zarezerwowana wielkość stosu programowego

    ad.(1) Rejestry rezerwowane są głównie na początku ram i określone w pliku linkera

    2. -s
    analizuje plik _listnamefun.txt i wyświetla sumaryczne dane dla funkcji które nie są wywoływane, np:
    Code:

                              name sstck  regf hstck  +l+h   ?lh sumhs
                   ivec_0x2_tc_int     9     0     0           2
                  ivec_0x1_tch_int     9     0     0           2
                             _main   174    40     9   192   183    11


    name - nazwa prawie jak w C
    sstck - sumaryczne zużycie stosu programowego przez funkcje
    regf - sumaryczne (maxymalne) zużycie rejestrów przez funkcje
    hstck - sumaryczne zużycie stosu sprzetowego przez funkcje
    +l+h - zużycie stosu programowego przez funkcje wraz z sumą przerwań
    ?lh - zużycie stosu programowego przez funkcje wraz z największą wartością z przerwań
    sumhs - sumaryczne zużycie stosu sprzętowego przez funkcje (ilość wywołań, razem ze znalezionymi przerwaniami )

    By program uwzględnił stosy z przerwań należy je nazwać:
    tch_int - dla wysokiego priorytetu
    tc_int - dla niskiego

    Code: c
    Log in, to see the code


    3. -cs plik_linkera
    znajduje największy ostatni blok pamięci, przyda się do określenia gdzie ma być stos

    Program na wyjście błędów wysyła czasem informacje, np o nieznalezionych skokach:

    Spoiler:
    call global not found __mullong ...skip



    Program nie zawsze wszystko idealnie policzy:

    1. Gdyby były przemieszane różne kody ze skokami lokalnymi w których stos rośnie, a gdzie indziej gdzie stos maleje, a jeśli skoki będą warunkowe to jeszcze pogarsza sytuacje. W tej chwili program nie uwzględnia skoków lokalnych.

    2. Nie policzy sum w funkcjach wywoływanych przez wskaźniki do funkcji.

    3. Nie policzy funkcji bibliotecznych linkowanych do projektu.

    4. Program pokazuje wszystko co znajdzie w plikach, jednak nie wszystko jest umieszczane w końcowym programie przez linker. Np nieużywane funkcje nie są umieszczane w końcowym pliku.

    W planach:

    1. Chce dodać analize plików po deasemblacji. W takich plikach jest troche mniej niektórych informacji, ale jest cały projekt. Uzupełniłoby to troche wiedzy w zakresie stosu funkcji bibliotecznych.

    2. W jakiś sposób uwzględnić funkcje wywoływane wskaźnikiem na funkcje.
    Są takie przypadki że można je policzyć z pliku asm, ale w wielu nie jest to oczywiste. Myśle o pliku, gdzie można określić ręcznie jakie funkcje są wywoływane przez jakie. Jednak nawet w takim wypadku można uwzględnić jedynie maksymalne wartości, jeśli wywołań jest więcej niż dwa do różnych funkcji.

    Link do ściągnięcia kodu

    Macie jakieś uwagi, dygresje itp., w miare możliwości uwzględnie itp.

    Cool! Ranking DIY
    Can you write similar article? Send message to me and you will get SD card 64GB.
    About Author
    trol.six
    Level 31  
    Offline 
  • #2
    trol.six
    Level 31  
    Wersja kolejna 0.1.6, wzbogacona o możliwość czytania z pliku po deasemblacji.

    Nowe opcje:
    -d plik - plik po deasemblacji, zapis do pliku _lisdfun.txt
    -D analiza pliku _lisdfun.txt kalkulacja stosu
    -m plik plik map

    Na chwile obecną program czyta pliki z deasemblacji (za pomocą np gpdasm z pakietu gputils), z pliku formatu zawierający etykiety oraz adresy, np deasemblacja:

    Code:
    gpdasm -n -p 18f26k22 t07t.hex > deasembl.S
    


    Przykładowy plik:

    Code:
    vector_reset:                                               ; address: 0x000000
    

    000000:  ef29  goto    label_189                            ; dest: 0x003852
    000002:  f01c

    label_001:                                                  ; address: 0x000004

    000004:  efb8  goto    label_216                            ; dest: 0x003d70
    000006:  f01e


    Potem uruchamiamy poleceniem:
    Code:
    pictc -d deasembl.S
    


    Analizowany jest plik deasembl.S i tworzony _lisdfun.txt

    Następnie uruchamiamy poleceniem, można na typ etapie dodać plik map:
    Code:
    pictc -D -m t07t.map
    

    Plik map otrzymujemy podczas linkowania, dla programu gplink dodajemy opcje -m

    Fragment pliku map:
    Code:
             S_crt0iz___entry       code   0x000000    program   0x000004
    
     S___eeprom_gptrget1_stub       code   0x000004    program   0x000004
      S_t07t_ivec_0x1_tch_int       code   0x000008    program   0x000004
       S_t07t_ivec_0x2_tc_int       code   0x000018    program   0x000004


    Analizowany jest plik _lisdfun.txt oraz liczone są stosy:

    Jesli nie podamy pliku map to otrzymujmy wyniki np:
    Code:
                                         name      adr  stckf stcka stckh
    
                                 vector_reset 0x000000     0   174    12
                              vector_int_high 0x000008     9     9     0
                                 function_000 0x00000c     1     6     1
                               vector_int_low 0x000018     9     9     0


    Jeśli podamy plik map, to podmieniane są nazwy z pliku np:
    Code:
                                         name      adr  stckf stcka stckh
    
                             S_crt0iz___entry 0x000000     0   174    12
                      S_t07t_ivec_0x1_tch_int 0x000008     9     9     0
                        S_diskio__SPI_receive 0x00000c     1     6     1
                       S_t07t_ivec_0x2_tc_int 0x000018     9     9     0


    Na chwile obecna program kalkuluje zużycie stosu.
    - adr - adres funkcji
    - stckf - zużycie stosu przez funkcje
    - stcka - sumaryczne zużycie stosu programowego przez funkcje
    - stckh - sumaryczne zużycie stosu sprzetowego przez funkcje

    Uwaga, w funkcjach przerwaniowych jest tylko zużycie stosu przez funkcje, normalnie podczas przerwania dojdzie jedno zajęcie stosu sprzętowego na adres powrotu. Sumaryczne dane w planie. ;)

    Niuanse:
    Generalnie policzenie stosów byłoby banalne gdyby nie pewien niuans, gdyż w C stos nie może sobie skakać byle jak, i zawsze początek i koniec funkcji musi pozostawić tą samą wartość. Ale już podczas analizy można natknąć się na funkcje która w zależności od jej przebiegu, może zmienić stos inaczej. Tak dzieje się z np. niektórymi funkcjami bibliotecznymi napisanymi w asemblerze. W zasadzie te funkcje też powinny zostawiać stos w przewidywalny sposób, ale niby nie robią tego. W przypadku niektórych funkcji bibliotecznych po prostu pewne rzeczy są niezaimplementowane w kodzie, i to powoduje że z punktu widzenia analizy, taki kod czasem daje inną wartość stosu. W normalnym programie i tak tego nie robi, ale to trzeba się domyślać.


    Program do oszacowania zużycia zasobów dla kompilatora sdcc dla PIC18XXXX

    W przykładowym grafie -1 oraz +1 to zmiana stosu. Najpierw następuje zmiana stosu(-1) a potem wywołanie funkcji f_027 z której są trzy drogi. Jak widać z powrotu (R) dwie z nich zmieniają stos (+1) a jedna nie.

    Przyjąłem więc na razie taki algorytm, który w razie innej wartości stosu funkcji uwzględnia maksymalną z wartości bezwględnej. Nie gwarantuje to poprawności na każdą funkcje. Niestety nie znam tutaj niezawodnego i prostego sposobu.

    Program informuje o tym np takimi komunikatami:

    Spoiler:
    function_030 differ stack -1 0
    function_029 differ stack -1 0


    Inne:

    1. Jak widać nie ma liczonego zużycia rejestrów. Generalnie jest problem odróżnić w kodzie wynikowym czy mamy do czynienia z pamięcią przeznaczoną na rejestr czy pamięcią dla zmiennej.

    Generalnie pierwsze 128 bajtów jest rezerwowanych na rejestry, ale wcale tak być nie musi, po zmianie pliku linkera ta wartość może być mniejsza.

    Natomiast można to zrobić przy pomocy pliku map. Gdyż tam zawarta jest informacja o tym jakie zmienne zużywają pamięć. I może to uwzględnie w przyszłości.

    2. Program nie wskaże także informacji o funkcjach które są wywoływane za pomocą wskaźnika do funkcji. Nie można ich po prostu odróżnić (w prosty sposób) z kodu wynikowego, czy są to dane, czy może inna część kodu. I jak w poprzednim przypadku można to zrobić z pomocą pliku map. Gdzie są adresy funkcji.

    Link do ściągnięcia kodu

    .