/* mips_mflops.c
* Stefano Salvi - 4/10/02
* Benchmark che calcola:
* - MIPS basandosi su di un ciclo in C;
* - MIPS basandosi su di un ciclo in Assembler;
* - MFLOPS basandosi su di un ciclo in C
*/
#include <stdio.h>
#include <time.h>
#include <sched.h>
#define DIM_MIPS 1000000000 /*1 miliardo - Ripetizioni per MIPS*/
#define DIM_MFLOPS 100000000 /*100 milioni - Ripetizioni per MFLOPS*/
/* Calcolo MIPS con ciclo ASSEMBLY
* Esegue un ciclo che fa' la somma di una costante a 2 registri,
* quindi ripete l'operazione con 3 registri.
* Calcola il tempo per ciascuno dei due cicli.
* Calcola la differenza, che dovrebbe essere il tempo impiegato per una somma per ciclo
* divide per il numero di ripetizione ed ottiene il tempo di una ripetizione.
*/
void asm_mips()
{
clock_t inizio; // Tempo iniziale Ciclo
clock_t tempoDueAdd; // Tempo ciclo con due somme
clock_t tempoTreAdd; // Tempo ciclo con tre somme
double tempo; // Tempo in secondi
double MIPS;
sched_yield(); // Cede il passo, cosi' dopo lo scheduler non lo disturba
inizio = clock(); // tempo iniziale primo ciclo
__asm__(
"pushl %ecx\n" // Salva tutti i registri usati
"\tpushl %ebx\n"
"\tpushl %eax\n"
"\tpushl %edx\n"
"\tmovl $1000000000,%ecx\n" // Inizializza contatore
"\tmovl $1,%eax\n" // Inizializza variabili
"\tmovl $2,%ebx\n"
"\tmovl $3,%edx\n"
"lp:\n"
"\taddl $1,%eax\n" // Prima somma
"\taddl $1,%ebx\n" // Seconda somma
"\tdecl %ecx\n" // Decrementa contatore
"\tjnz lp\n" // Ciclo finche' decremento non da' 0
"\tpopl %edx\n" // Ripristina i registri 'sporcati'
"\tpopl %eax\n" // Ripristina i registri 'sporcati'
"\tpopl %ebx\n" // Ripristina i registri 'sporcati'
"\tpopl %ecx\n"
);
tempoDueAdd = clock()- inizio; // Tempo ciclo con due somme
sched_yield(); // Cede il passo, cosi' dopo lo scheduler non lo disturba
inizio = clock(); // tempo iniziale secondo ciclo
__asm__(
"pushl %ecx\n" // Salva i registri usati
"\tpushl %ebx\n"
"\tpushl %eax\n"
"\tpushl %edx\n"
"\tmovl $1000000000,%ecx\n" // Inizializza contatore
"\tmovl $1,%eax\n" // Inizializza variabili
"\tmovl $2,%ebx\n"
"\tmovl $3,%edx\n"
"\tmovl $0,%ebx\n" // Inizializza variabile
"lp1:\n"
"\taddl $1,%eax\n" // Prima somma
"\taddl $1,%ebx\n" // Seconda somma
"\taddl $1,%edx\n" // Terza Somma
"\tdecl %ecx\n" // decrementaConteggio cicli
"\tjne lp1\n" // Ciclo
"\tpopl %edx\n" // Ripristina i registri usati
"\tpopl %eax\n"
"\tpopl %ebx\n"
"\tpopl %ecx\n"
);
tempoTreAdd=clock() - inizio; // Tempo ciclo con tre somme
printf("tempi: 2 somme %f secondi, tre somme %f secondi\n",
((double)tempoDueAdd)/CLOCKS_PER_SEC, ((double)tempoTreAdd)/CLOCKS_PER_SEC);
/* sottraendo al tempo del secondo ciclo il tempo del primo si otterra' il tempo puro
* dell'incremento b++; */
tempo = (tempoTreAdd - tempoDueAdd) / (double)CLOCKS_PER_SEC;
printf("Il tempo di %d somme e' %f secondi\n", DIM_MIPS, tempo);
/*Quante istruzioni fa al secondo = MIPS*/
MIPS=(DIM_MIPS/tempo)/1000000;
printf("\nMIPS: %lf\n",MIPS);
}
/* Calcola i MIPS con un ciclo in C
* Esegue un ciclo che fa' la somma di una costante a 2 variabili,
* quindi ripete l'operazione con 3 registri.
* Calcola il tempo per ciascuno dei due cicli.
* Calcola la differenza, che dovrebbe essere il tempo impiegato per una somma per ciclo
* divide per il numero di ripetizione ed ottiene il tempo di una ripetizione.
*/
void c_mips()
{
static int a,b,c,i;
clock_t inizio; // Tempo iniziale Ciclo
clock_t tempoDueAdd; // Tempo ciclo con due somme
clock_t tempoTreAdd; // Tempo ciclo con tre somme
double tempo; // Tempo in secondi
double MIPS;
a=0; // Inizializza le variabili
b=0;
c=0;
sched_yield(); // Cede il passo, cosi' dopo lo scheduler non lo disturba
inizio = clock(); // tempo iniziale primo ciclo
for(i=0;i < DIM_MIPS;i++) // primo ciclo con due somme
{
a+=3;
b+=4;
}
tempoDueAdd = clock()- inizio; // Tempo ciclo con due somme
sched_yield(); // Cede il passo, cosi' dopo lo scheduler non lo disturba
inizio = clock(); // tempo iniziale secondo ciclo
for(i=0;i<DIM_MIPS;i++) //secondo ciclo con tre somme
{
a+=2;
b+=3;
c+=4;
}
tempoTreAdd=clock() - inizio; // Tempo ciclo con tre somme
printf("tempi: 2 somme %f secondi, tre somme %f secondi\n",
((double)tempoDueAdd)/CLOCKS_PER_SEC, ((double)tempoTreAdd)/CLOCKS_PER_SEC);
/* sottraendo al tempo del secondo ciclo il tempo del primo si otterra' il tempo puro
* dell'incremento b++; */
tempo = (tempoTreAdd - tempoDueAdd) / (double)CLOCKS_PER_SEC;
printf("Il tempo di %d somme e' %f secondi\n", DIM_MIPS, tempo);
/*Quante istruzioni fa al secondo = MIPS*/
MIPS=(DIM_MIPS/tempo)/1000000;
printf("\nMIPS: %lf\n",MIPS);
}
/* Calcolo dei MFLOPS
* Esegue un ciclo che fa' la somma di una costante a 2 variabili double,
* quindi ripete l'operazione con 3 registri.
* Calcola il tempo per ciascuno dei due cicli.
* Calcola la differenza, che dovrebbe essere il tempo impiegato per una somma per ciclo
* divide per il numero di ripetizione ed ottiene il tempo di una ripetizione.
*/
void c_mflops() /*Calcolo MFLOPS*/
{
static int i;
clock_t inizio; // Tempo iniziale Ciclo
clock_t tempoDueAdd; // Tempo ciclo con due somme
clock_t tempoTreAdd; // Tempo ciclo con tre somme
double tempo; // Tempo in secondi
double MFLOPS;
double a,b,c;
a=0.0; // Inizializza le variabili
b=0.0;
c=0.0;
sched_yield(); // Cede il passo, cosi' dopo lo scheduler non lo disturba
inizio = clock(); // tempo iniziale primo ciclo
for(i=0;i<DIM_MFLOPS;i++) /*primo ciclo con una istruzione*/
{
a=a+0.1;
b=b+0.1;
}
tempoDueAdd = clock()- inizio; // Tempo ciclo con due somme
sched_yield(); // Cede il passo, cosi' dopo lo scheduler non lo disturba
inizio = clock(); // tempo iniziale secondo ciclo
for(i=0;i<DIM_MFLOPS;i++) /*secondo ciclo con due istruzioni*/
{
a=a+0.1;
b=b+0.1;
c=c+0.1;
}
tempoTreAdd=clock() - inizio; // Tempo ciclo con tre somme
printf("tempi: 2 somme %f secondi, tre somme %f secondi\n",
((double)tempoDueAdd)/CLOCKS_PER_SEC, ((double)tempoTreAdd)/CLOCKS_PER_SEC);
/* sottraendo al tempo del secondo ciclo il tempo del primo si otterra' il tempo puro
* dell'incremento b++; */
tempo = (tempoTreAdd - tempoDueAdd) / (double)CLOCKS_PER_SEC;
printf("Il tempo di %d somme e' %f secondi\n", DIM_MFLOPS, tempo);
/*Quante istruzioni fa al secondo = MFLOPS*/
MFLOPS=(DIM_MFLOPS/tempo)/1000000;
printf("\nMFLOPS: %lf\n",MFLOPS);
}
int main()
{
int scelta;
// Stampa il menu'
printf("1. MIPS con C\n");
printf("2. MIPS con ASM\n");
printf("3. MFLOPS\n");
printf("Inserisci la scelta: ");
// Legge la scelta
scanf("%d",&scelta);
// Esegue il lavoro
switch(scelta)
{
case 1:
c_mips();
break;
case 2:
asm_mips();
break;
case 3:
c_mflops();
break;
default:
printf("La scelta non e' presente!");
break;
}
return 0;
}
|