Nu sunt foarte sigur unde s-ar încadra chestia asta, probabil la o categorie de genul “Ce efect au razele Lunii asupra papucilor de gumă”
Din curiozitate plictisită, m-a pălit ideea să văd cu cât mai rapid poate fi executat o secvenţă simplă scrisă în assembler, faţă de o secvenţa care execută ceva echivalent, dar scrisă în C. Am făcut o buclă care execută 1,000,000,000 (un miliard) iteraţii şi incrementează o variabilă. A ieşit un cod de genul ăsta:
#include <stdio.h>
#include <time.h>
static clock_t time_start;
static int result;
void start()
{
time_start = clock();
}
void elapsed(const char *msg)
{
clock_t time_end = clock();
fprintf(stdout, "%s: %d ms\n", msg, (time_end - time_start) / (CLOCKS_PER_SEC / 1000));
fprintf(stdout, " RESULT: %d\n", result);
}
int main(int argc, char *argv[])
{
result = 0;
start();
for(int i = 1000000000; i != 0; i--)
{
result++;
}
elapsed("Test C");
start();
__asm__ volatile
(
"xor %%eax, %%eax;"
"mov $1000000000, %%ecx;"
"LOOP:"
"inc %%eax;"
"dec %%ecx;"
"jnz LOOP;"
"mov %%eax, %0;"
: "=r" (result)
:
: "%ecx"
);
elapsed("Test ASM");
return 0;
}
Maşina de test este un SBC de la PC Engines, un bătrân ALIX:
processor : 0
vendor_id : AuthenticAMD
cpu family : 5
model : 10
model name : Geode(TM) Integrated Processor by AMD PCS
stepping : 2
cpu MHz : 498.050
cache size : 128 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 1
wp : yes
flags : fpu de pse tsc msr cx8 pge cmov clflush mmx mmxext 3dnowext 3dnow up
bogomips : 996.10
Rezultatul… well, aici e mai complicat. Dacă setam compilatorul să nu optimizeze codul (flag -O0), codul ASM este executat de cel puţin două-trei ori mai rapid decât cel scris în C (asta este rulat pe o maşină ALIX, cu CPU
Test C: 18400 ms
RESULT: 1000000000
Test ASM: 6140 ms
RESULT: 1000000000
Diferenţa mare este cauzată de faptul că secvenţa în assembler foloseşte doar regiştrii interni ai procesorului, în schimb codul generat de C accesează şi RAM-ul.
În schimb, dacă optimizăm cu -O2, rezultatele se schimbă drastic:
Test C: 0 ms
RESULT: 1000000000
Test ASM: 6110 ms
RESULT: 1000000000
Explicaţia e simplă, optimizerul compilatorului vede că este o corelaţie între numărul de interaţii şi incrementarea variabilei “result”. Şi atunci pur şi simplu pune în “result” numărul de iteraţii, nici măcar nu se mai oboseşte să execute bucla. Am incercat să-l păcalesc, sa introduc numărul de interaţii şi step-ul pentru increment prin stdin, să nu le ştie de la compile-time. Degeaba, tot gaseşte o corelaţie şi execută direct asignarea (probabil îşi dă seama că rezultatul final este “numărul de iteraţii * step”).
Totuşi, este impresionant că un CPU la doar 500 MHz este capabil să execute 1 miliard (!) de iteraţii în doar 6 secunde. Pe un CPU I7 rezultalte sunt astea:
Test C: 1696 ms
RESULT: 1000000000
Test ASM: 239 ms
RESULT: 1000000000