bogomips

Milan Pikula - WWW www na fornax.elf.stuba.sk
Pátek Leden 30 12:26:22 CET 1998


On 29 Jan 1998, Matus Uhlar wrote:

W>Zdravim,
W>hladam zdrojak bogomips, poradi mi niekto ? podla moznosti pisany tak aby
W>bol portovatelny aj na iny system.

caf, je to init/main.c: calibrate_delay()
portovatelne tpo nebude nikdy, lebo to vyzaduje vsetok cas CPU a nieco na
interrupte, co zvysuje casovac. Ak take nieco mas (dos, casovac), tak ta
rutina je krasne priamo pouzitelna.. Sorry ak to je proti pravidlam
(dajte mi vediet ak sa to nema), ale hodim sem trosku okomentovany kus
zdrojaku..

najprv rutinka __delay pre x86, z include/asm/delay.h
extern __inline__ void __delay(int loops)
{
        __asm__ __volatile__(
                ".align 2,0x90\n1:\tdecl %0\n\tjns 1b"
                :/* no outputs */
                :"a" (loops)
                :"ax");
}
povedane po nasom, word align nopmi, potom dec parametra az kym nie je
carry. cize netestuje nijake ine instrukcie..

no a teraz ku kodu bogomipsov:

unsigned long loops_per_sec = (1<<12);

/* This is the number of bits of precision for the loops_per_second.  Each
   bit takes on average 1.5/HZ seconds.  This (like the original) is a
little better than 1% */

#define LPS_PREC 8 /* presnost v pocte bitov, s ktorymi robime zaverecnu */
		/* aproximaciu. cim viac, tym dlhsie trva test, ale */
		/* vysledok je lepsi. sak viz. orig. poznamka. */

void calibrate_delay(void)
{
        int ticks;	/* pomocna premenna na hodnotu hodiniek */
        int loopbit;	/* pouzivane pri neskorsej aproximacii */
        int lps_precision = LPS_PREC;

        loops_per_sec = (1<<12);

        printk("Calibrating delay loop.. ");

/* teraz sa hlada take velke cislo, ktoreho prehnanie cez rutinu __delay
 * bude trvat viac ako jeden takt casovaca. Takze sa zasynchronizujeme na
 * zaciatok intervalu 
 */

        while (loops_per_sec <<= 1) { /* bude vysvetlene neskor */

                ticks = jiffies;	/* toto je interna kernelovska */
					/* premenna, inkrementovana casom */
                while (ticks == jiffies) ;
                         	 /* cakame kym sa zmeni */

/* teraz sme na zaciatku hodiniek, zapiseme si cas a zavolame __delay,
 * ak to trva viac ako perioda hodin, koniec, inak sa premenna vo while
 * podmienke vynasobi dvomi a test sa opakuje. v pripade ze mame nekonecne
 * rychlu masinu, cyklus nezostane visiet, ale skonci tym, ze bit pretecie
 * a premenna loops_per_sec bude nulova. Preto je to v podmienke while().
 */

                ticks = jiffies;
                __delay(loops_per_sec); /* chrr */
                ticks = jiffies - ticks; /* pocet incnuti casovaca, */
					 /* kym sme spali 	*/
                if (ticks) 		 /* ak je nenulovy, nasli sme */ 
                        break;		 /* nase cislo */
                }

/* a mame cislo, ktoreho dekrementovanie trva viac ako jeden takt. teraz 
 * chceme take, ktore sa DA stihat. Kedze binarny tvar cisla je 100..0 a
 * hladame MENSIE vyhovujuce, mozeme ako prvy bit dat 0 a skusat nastavit
 * ostatne bity. kvoli pohodlnosti autora sa nami zistene cislo vydeli
 * dvomi..
 */

/* Do a binary approximation to get loops_per_second set to equal one
clock (up to lps_precision bits) */

        loops_per_sec >>= 1;
        loopbit = loops_per_sec; /* toto je bit, ktory skusame pridavat */
        while ( lps_precision-- && (loopbit >>= 1) ) { /* vysv. neskor */
                loops_per_sec |= loopbit; /* pokusne pridame bit */

                ticks = jiffies;
                 while (ticks == jiffies);	/* synchro na casovac */
                ticks = jiffies;
                __delay(loops_per_sec);		/* cakame */

/*
 * a ak to s tym bitom trva dlhsie, tak tam ten bit nedame. zrusit bit
 * sa da tym, ze ANDujeme cislo s negaciou pozadovaneho bitu..
 */

                if (jiffies != ticks)   	/* longer than 1 tick */
                        loops_per_sec &= ~loopbit; /* ten bit uz vadi */

/* toto vsetko robime v cykle, kym testovaci bit neujde uplne doprava,
 * alebo kym cislo lps_precision, cize pocet bitov pre aproximaciu, nie
 * je nulove.
 */
        }

/* no a teraz to uz len pekne vypiseme, konstanta HZ je pocet interruptov
za sekundu (definovane v /usr/include/asm/param.h ako 100) */

        loops_per_sec *= HZ;

/* teraz to delime 500000 a zobrazime.. btw sa tu pri deleni pouziva
 * zaokruhlenie, takze pridame k cislu polovicu najmensieho kroku, ktory
 * este vypisujeme.
 */

        printk("ok - %lu.%02lu BogoMIPS\n",
                (loops_per_sec+2500)/500000,
                ((loops_per_sec+2500)/5000) % 100);
}


Inac to vlastne chce povedat, ze BogoMIPS * 500000 je pocet vykonani dec a
relativny skok za sekundu, alias BogoMIPS * 250000 je priemerna dlzka
instrukcie.

hm a este k nepresnostiam algoritmu:

ak som to dobre pochopil, celkove je mysleny ako dobry vtip autorov
kernelu. zistuje iba rychlost dec-u a podmieneneho skoku. zaroven
align toho cyklu je na word, co znamena, ze okrem cyklu samotneho
sa vykonaju aj 0 az dva nopy (co je zanedbatelne vzhladom k sialene
velkemu cislu na dekrementaciu), ale ak doteraz word align stacil, dlho uz
asi nebude a spomalovat bude to, ze kod nie je optimalizovany pre
64bitovu organizaciu pamate. Tak ci tak, je trosku neelegantne to, ze po
rekompilacii kernelu mozu vyjst bogomipsy ine prave qoli tomu alignu.

caf,
						wWw

          -----------------------------------------------------
             WWW/4CP, Milan Pikula,  www na fornax.elf.stuba.sk
              .. dajte mi pewnu linku a pohnem zemegulow ..





Další informace o konferenci Linux