Bench matematických funkcí knihovny AvrLibc

Michael Novák, UREL, FEEC, VUT Brno
xnovak58stud.feec.vutbr.cz

Obsah:

  1. Úvod
  2. Realizace
  3. Závěr
  4. Literatura

Úvod

Protože jádro mikrokontroléru dokáže jednoduše a rychle pracovat pouze se základními matematickými a logickými operacemi, jsou složitější matematické funkce v AVR implementovány jako matematická knihohvna <math.h>. Tato knihovna umožňuje v AVR využívat např. goniometrické nebo statistické funkce s třesností typu double jazyka C, ale

na úkor výpočetního výkonu. Tyto funkce mají dobu zpracování několik set až tísíc strojových cyklů.

Realizace

Abychom dosáhli úspěšného a správného výsledku měření, je potřeba vypnou veškerou optimalizaci kompilátoru zdrojového kódu. Tato optimalizace mění strukturu a pořadí samotného kódu, a dobu zpracování by tak nebylo možné v simulátoru změřit.

Veškeré naměřené hodnoty jsou tedy platné pro neoptimalizovaný kód, kde vstupy i výstupy matematických funkcí i základních matematických operací jsou paměťové proměnné. Měření bylo provedeno několikrát v jednom cyklu, vždy se stejným výsledkem.

 

Základní matematické operace:

Základní matematické operace představují jednoduché sčítání, odčítání, násobení, dělení a dělení modulo. Tyto operace lze provádět s jakýmkoliv číselným typem, a to se znaménkem i bez znaménka. V následující tabulce je vidět, že práce s celočíselnými typy je ve srovnání s typem s plovoucí desetinnou čárkou mnohem rychlejší. Mikrokontroléry Atmel AVR nejsou na výpočty s plovoucí desetinnu čárkou přizpůsobené.

 

Tab. 1: Doba zpracování jednoduchých matematických operací ve strojových cyklech

Operace char  int long double
unsigned signed unsigned signed unsigned signed
A++ 5 5 10 10 20 20 983
B-- 5 5 10 10 20 20 961
C = A + B 7 8 14 14 28 28 890
C = A - B 9 10 16 16 32 32 859
C = A * B 10 10 23 23 76 76 2047
C = A / B 87 258 212 256 601 656 1395
C = A mod B 88 257 211 255 601 656 -

 

Pokročilé matematické funkce:

Mezi pokročilé matematické funkce patří např. goniometrické funkce a statistické funkce. Většina těchto funkcí pracuje s parametry s plovoucí desetinnou čárkou (typ double), a proto jsou výpočetně náročné. Ke srovnání výkonu jsou zde uvedeny hodnoty testu z manuálu avr-libc [1] pro CPU jádra AVR2 a AVR4.

 

Tab. 2: Doba zpracování pokročilých matematických funkcí ve strojových cyklech

Funkce Definice Strojových cyklů Poznámka
Aktuální AVR2 AVR4
  O = cos (M) double  cos (double __x) 1742 3387 1671
  O = abs (M) double  fabs (double __x) 17 - -
  O = M mod N double  fmod (double __x, double __y) 244 131 131
 

O = M mod 1, N = M div 1 = M - O

double  modf (double __x, double *__iptr) 1553 433 429 Rozdělí číslo na celou a desetinnou část 
  O = sin (M) double  sin (double __x) 1819 3353 1653
  O = sqrt (M) double  sqrt (double __x) 496 494 492
  O = tan (M) double  tan (double __x) 2430 4381 2426
  O = floor (M) double  floor (double __x) 119 180 180
  O = ceil (M) double  ceil (double __x) 122 177 177
  O * 2^N = M double  frexp (double __x, int *__pexp) 65 42 41
  O = M * 2^N double  ldexp (double __x, int __exp) 68 42 42
  O = exp (M) double  exp (double __x) 54 4708 2765
  O = cosh (M) double  cosh (double __x) 647 4922 2979
  O = sinh (M) double  sinh (double __x) 670 4946 3003
  O = tanh (M) double  tanh (double __x) 1751 5126 3173
  O = acos (M) double  acos (double __x) 2691 4411 2455
  O = asin (M) double  asin (double __x) 2761 4517 2556
  O = atan (M) double  atan (double __x) 3233 4710 2271
  O = atan (M / N) double  atan2 (double __y, double __x) 3729 5270 2857
  O = log (M) double  log (double __x) 3039 4142 2134 přirozený logaritmus
  O = log10 (M) double  log10 (double __x) 3165 4498 2260 dekadický logaritmus
  O = power (M, N) = M ^ N double  pow (double __x, double __y) 6825 9293 5047
  O = isNaN (M) int  isnan (double __x) 355 - - vrací nenulovou hodnotu pokud parametr M není číslo
  O = isInf (M) int  isinf (double __x) 826 - - vrací nenulovou hodnotu pokud parametr je nekonečno
  O = sqr (M) double  square (double __x) 151 - - square root
  O = (abs (M) * sign (N)) static double  copysign (double __x, double __y) 112 - - vrací M se znaménkem N
  O = max (M - N, 0) double  fdim (double __x, double __y) 851 111 111
  O = (M * N) + P double  fma (double __x, double __y, double __z) 270 - -
  O = max (M, N) double  fmax (double __x, double __y) 58 39 37
  O = min (M, N) double  fmin (double __x, double __y) 61 35 35
  O = sign (M) int  signbit (double __x) 17 - -
  O = trunc (M) double  trunc (double __x) 117 178 178
  O = isFinite (M) static int  isfinite (double __x) 86 - -
  O = sqrt (M^2 + N^2) double  hypot (double __x, double __y) 852 1341 866
  O = round (M) double  round (double __x) 96 150 150
  O = round (M) long  lround (double __x) 76 - -
  O = round (M) long  lrint (double __x) 89 - -

Závěr

Na první pohled je patrné, že srovnání mého měření a měření z oficiálních stránek [1] jsou velice odlišné. Ve skutečnosti to ale závisí na typu použitého kompilátoru, metodě použité optimalizace kódu. Průběh výpočtu některých funkcí je také závislý na hodnotě parametru, která může ovlivnit dobu jeho zpracování.

Literatura

[1] AVR-Libc User Manual - Benchmarks [online]. Dostupný z WWW: <http://www.nongnu.org/avr-libc/user-manual/benchmarks.html>