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
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..