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'); }