Ako som si zaoptimalozoval.

Na jednom projekte som sa dostal na obmedzenia veľkosti flash v ATtiny2313. Tak som sa vrhol na optimalizáciu (Kód sa kompiloval z prepínačom -Os). V kóde som našiel len jednu možnosť ako optimalizovať veľkosť. Zbaviť sa násobenia a delenia. Vo výsledku sa mi celkový kód scvrkol o 98 bytov oproti pôvodnej veľkosti.

Na začiatok pôvodný kód ktorý je z dôvodu prehľadnosti silne neoptimalizovaný:

/* read uint32_t 8 chars - 0xFFFFFFFF = error */
uint32_t readul(void) {
        uint8_t x=0;
        unsigned char c;
        uint32_t nasobok = 10000000;
        uint32_t vysledok = 0;
        do {
                c = uart_get();
                vysledok = vysledok + (c - '0') * nasobok;
                nasobok = nasobok / 10;
                x++;
        } while ((x < 8) & (c >= '0') & (c <= '9'));
        if (x == 8)
                return(vysledok);
        else
                return(0xFFFFFFFF);
}

Ako vidno optimalizácia je možná len zmenou algoritmu ktorý nebude využívať náročné operácie. A tými sú násobenie a delenie. Delenia sa dá vcelku ľahko zbaviť:

/* read uint32_t 8 chars - 0xFFFFFFFF = error */
uint32_t readul(void) {
        uint8_t x=0;
        unsigned char c;
        uint32_t vysledok = 0;
        do {
                c = uart_get();
                vysledok = vysledok * 10;
                vysledok = vysledok + (c - '0');
                x++;
        } while ((x < 8) & (c >= '0') & (c <= '9'));
        if (x == 8)
                return(vysledok);
        else
                return(0xFFFFFFFF);
}

 

Kód je trošku zložitejší na pochopenie ale zatiaľ žiadna hrôza. Kód po skompilovaní je menší o 56 bytov. Nevyzerá to moc ale je to dostatočné na moje potreby. Navyše kód vyžaduje menej RAM keďže  nám vypadla jedna premenná. A je podstatne rýchlejší. Predsa len delenie 32bit čísiel nieje pre 8bit CPU triviálna úloha.

Teraz ostal otázne už len jedno násobenie, je možné ho optimalizovať? Skúsme to. Keďže sa jedná o násobenie konštantou je možné ho nahradiť bitovým posuvom a súčinom.

/* read uint32_t 8 chars - 0xFFFFFFFF = error */
uint32_t readul(void) {
        uint8_t x=0;
        unsigned char c;
        uint32_t vysledok = 0;
        do {
                c = uart_get();
                vysledok = (vysledok << 1) + (vysledok << 3);
                vysledok = vysledok + (c - '0'); //23
                x++;
        } while ((x < 8) & (c >= '0') & (c <= '9'));
        if (x == 8)
                return(vysledok);
        else
                return(0xFFFFFFFF);
}

Výsledok je oproti p;vodnému kódu menší o 98 bytov ale jeho pochopenie je o dosť ťažšie.

Ďalším adeptom na optimalizáciu je kód na výpis unsigned long v decimálnom formáte. Ale zatiaľ neviem ako.

/* tlac freq */
void print_freq(uint32_t freq) {
        uint8_t y=0;
        uint32_t tosc;
        char c[8];
        tosc = freq;
        for(y=8;y>0;y--) {
                c[y-1] = (tosc % 10) + '0';
                tosc = tosc / 10;
        }
        for(y=0;y<8;y++)
                uart_putc(c[y]);
        uart_putS('nr');
}

 

Print Friendly, PDF & Email