A.D.Danilecki, Poznan, Polska
Politechnika Poznanska, Wydzial Informatyki i Zarzadzania
W tej chwili adanilecki _malpa_ cs.put.poznan.pl
Z wykorzystaniem wielu listow z uwagami od wielu autorow
Krótki wstęp do programowania z wykorzystaniem inline assemblera x86



5. Testowanie

Rozdział ten poświęcony jest testowaniu efektywności programów, a nie kontroli ich poprawności. Temu drugiemu zagadnieniu poświęcony jest rodział "Używanie gdb" .

Teraz kilka słów na temat testowania programów. Poniżej pokazałem przykład, jak ja to robię. Wykorzystuję funkcję gettimeofday (man gettimeofday). W przykładzie tym sprawdzam ile setnych części sekundy trwa dana część kodu. Tą część kodu wykonuje 1000 razy by mieć pewniejsze wyniki. Oczywiste jest też, żeby mieć w miarę wiarugodne wyniki, nasz system powinien być w miarę jednakowo obciążony, i pomiary przeprowadzać kilkakrotnie. (Przy okazji, zauważyłem ciekawą rzecz : pierwszy pomiar w 75 % przypadków jest zawsze sporo większy od następnych. Wpływ cache ? ). Istnieje również inna (lepsza?) metoda, której z czystego lenistwa nie używałem (nie chce mi się przestawić). Pozwól że zacytuję Piotra Gackiewicza gacek@ds14.agh.edu.pl :
<CYTAT> man gprof
musisz odpowiednio skomilować program (np. opcje: -pg -profile-arcs -ftest-coverage i zlinkować (-pg).
Po uruchomieniu i zakończeniu takiego programu dostajesz plik gmon.out, który łyka z kolei gprof. </CYTAT>

Aby uzyskać kod assemblerowy, piszę :
gcc -DASMx86 dziewiaty.c -o asm
natomiast by uzyskać kod w C piszę :
gcc dziewiaty.c -o noasm
oto kod programu:

dziewiaty.c
#include <stdio.h>
#include <sys/time.h>

void main()
{
int a[2]={11,12};
struct timeval t1,t2;
int i;
#ifndef ASMx86
int tmp;
#endif
printf("Przed wykonaniem instrukcji a[0]=%d, a[1]=%d\n",a[0],a[1]);
gettimeofday(&t1,NULL);
for (i=0;i<1000;i++)
#ifdef ASMx86
asm volatile(
"lea %0,%%edx\n\t"
"pushl (%%edx)\n\t"
"pushl 4(%%edx)\n\t"
"popl (%%edx)\n\t"
"popl 4(%%edx)\n\t"
: "=g" (a)
::"ax" , "cx" , "dx"
);
#else
tmp=a[0];
a[0]=a[1];
a[1]=tmp;
#endif
}
gettimeofday(&t2,NULL);
printf("czas sec: %d, microsec : %d\n",t2.tv_sec-t1.tv_sec,t2.tv_usec-t1.tv_usec);
printf("Po wykonaniu instrukcji a[0]=%d, a[1]=%d\n",a[0],a[1]);
}


Wyniki : kod skompilowany z użyciem assemblera: 70 microsec. Kod skompilowany w wersji C : 58 microsec. Więcej : kod w którym dodaliśmy opcję -O2 (optymalizuj) wykonał się w 40 microsec.


Gdyby się okazało, że program z inline assemblerem wisi, mimo że powinien działać, może się okazać, że modyfikujesz zawartość jakichś rejestrów i zapomniałeś powiedzieć o tym gcc (W ostatnim polu instrukcji assemblerowej, ang. assembler statement). Do tej pory zdarzyło mi się to dwa razy i od tego czasu zawsze to pole wypełniam. Strzeżonego..