曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 8575|回复: 0
打印 上一主题 下一主题

calibrate_delay

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2011-1-14 01:08:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
calibrate_delay() 函数用来计算 BogoMIPS 的值。函数代码定义在 init/calibrate.c 中,如下所示:
/*
* This is the number of bits of precision for the loops_per_jiffy.  Each
* bit takes on average 1.5/HZ seconds.  This (like the original) is a little
* better than 1%
*/
#define LPS_PREC 8

void __devinit calibrate_delay(void)
{
     unsigned long ticks, loopbit;
     int lps_precision = LPS_PREC;

     if (preset_lpj) {
         loops_per_jiffy = preset_lpj;
         printk("Calibrating delay loop (skipped)... "
             "%lu.%02lu BogoMIPS preset\n",
             loops_per_jiffy/(500000/HZ),
             (loops_per_jiffy/(5000/HZ)) % 100);
     } else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) {
         printk("Calibrating delay using timer specific routine.. ");
         printk("%lu.%02lu BogoMIPS (lpj=%lu)\n",
             loops_per_jiffy/(500000/HZ),
             (loops_per_jiffy/(5000/HZ)) % 100,
             loops_per_jiffy);
     } else {
         loops_per_jiffy = (1<<12);

         printk(KERN_DEBUG "Calibrating delay loop... ");
         while ((loops_per_jiffy <<= 1) != 0) {
             /* wait for "start of" clock tick */
             ticks = jiffies;
             while (ticks == jiffies)
                 /* nothing */;
             /* Go .. */
             ticks = jiffies;
             __delay(loops_per_jiffy);
             ticks = jiffies - ticks;
             if (ticks)
                 break;
         }

         /*
         * Do a binary approximation to get loops_per_jiffy set to
         * equal one clock (up to lps_precision bits)
         */
         loops_per_jiffy >>= 1;
         loopbit = loops_per_jiffy;
         while (lps_precision-- && (loopbit >>= 1)) {
             loops_per_jiffy |= loopbit;
             ticks = jiffies;
             while (ticks == jiffies)
                 /* nothing */;
             ticks = jiffies;
             __delay(loops_per_jiffy);
             if (jiffies != ticks)    /* longer than 1 tick */
                 loops_per_jiffy &= ~loopbit;
         }

         /* Round the value and print it */
         printk("%lu.%02lu BogoMIPS (lpj=%lu)\n",
             loops_per_jiffy/(500000/HZ),
             (loops_per_jiffy/(5000/HZ)) % 100,
             loops_per_jiffy);
     }

}
printk(KERN_DEBUG "Calibrating delay loop... "); 语句上面部分代码不需要关注,真正计算部分为下边的代码。现在来看看该函数时如何算出 BogoMIPS 值的。

loops_per_jiffy 变量顾名思义是每个 jiffy 中多少个 loops 循环 (关于 jiffy 概念可参考:http://www.groad.net/bbs/read.php?tid-3056.html)。

[Plain Text] 纯文本查看 复制代码
loops_per_jiffy = (1<<12);

右移 12 位后, loops_per_jiffy 的值为 4096 。

[Plain Text] 纯文本查看 复制代码
while ((loops_per_jiffy <<= 1) != 0) 

在 while 循环里 loops_per_jiffy 的值 x 2

[Plain Text] 纯文本查看 复制代码
[mw_shl_code=text,true]ticks = jiffies;
             while (ticks == jiffies)
                 /* nothing */;

ticks 变量用来保存当前的 jiffies 值。在底下的 while() 里,只要 ticks == jiffies ,那么就一直执行空语句(;)。换句话就是说,时钟节拍还没更新就一直执行空语句等待。

[Plain Text] 纯文本查看 复制代码
ticks = jiffies;
             __delay(loops_per_jiffy);

OK,时钟节拍更新了(等时钟节拍更新是因为希望我们的计算有一个新的开始),那么我们开始执行 __delay() 函数(__delay() 函数不断对传进的 loops_per_jiffy 做减 1 运算,它是一小段汇编程序,具体分析参考:http://www.groad.net/bbs/read.php?tid-3052.html)。

[Plain Text] 纯文本查看 复制代码
ticks = jiffies - ticks;
             if (ticks)
                 break;

当一个 __delay() 完毕后再检查一下 jiffies 值是否更新,如果相减的结果不为零,则表示更新了,这时就会跳出这个循环。如果没有更新,loops_per_jiffy 再乘以 2 从而加大 __delay() 的延迟时间。也就是说,通过不断的加大 __delay() 的时间而达到一个时钟节拍时间的粗略估算。

现在假设上面的循环已经推出,开始执行下面的语句。

[Plain Text] 纯文本查看 复制代码
loops_per_jiffy >>= 1;

这里 loops_per_jiffy 右移一位除以 2 的目的是修正上面的估算。例如,我们假设一个时钟节拍所经过的时间为 t ,一个基本的 __delay() (对 4096 进行减 1 延迟所需要的时间)为 T1。再假设 t 的范围落在 2T1 < t < 4T1 。这里,我们会选择 2T1 ,目的是以 2T1 这个时间作为新的起点,然后根据下面的算法逐步的逼近 t 。
[Plain Text] 纯文本查看 复制代码
loopbit = loops_per_jiffy;

将 得到的 "新起点" loops_per_jiffy 保存到 loopbit 中。
[Plain Text] 纯文本查看 复制代码
while (lps_precision-- && (loopbit >>= 1)) {
             loops_per_jiffy |= loopbit;

从上面知道,lps_precision 的初始值为 8 ,这个值是一个精度。我们就是利用这个精度,从而不断的逼近 t 。为了更清晰,逼近值见下表(新起点就设为 2T1,也就是 4096*2=8192,即二进制 10000000000000) :
10000000000000
11000000000000
10100000000000
10010000000000
10001000000000
10000100000000
10000010000000
10000001000000
上面就是一个逼近的规律了。每一次的逼近,就是  loopbit >>=1; ,然后 loops_per_jiff |= loopbit; 。

[Plain Text] 纯文本查看 复制代码
  ticks = jiffies;
             while (ticks == jiffies)
                 /* nothing */;
             ticks = jiffies;
             __delay(loops_per_jiffy);

这一段代码和上面分析的一样。

[Plain Text] 纯文本查看 复制代码
   if (jiffies != ticks)    /* longer than 1 tick */
                 loops_per_jiffy &= ~loopbit;

如果发现 jiffies 不等于 ticks 了,那就说明 jiffies 已经加 1,也就是说我们之前的 loops_per_jiffy 的值(上表中的一个)设大了。这不要紧,我们继续将其减小,然后再重复去测试。如果说,精度 8 已经减完了( lps_precision--) 还是达不到要求,那么我们也只好认为最低的精度(比如是 10000001000000 )就是所需要的值了。
从上面的分析我们可以发现,这样的计算方法并不是很精确的,但是至少可以让我们大概明了我们的 CPU 快到了什么样的程度。

[Plain Text] 纯文本查看 复制代码
       printk("%lu.%02lu BogoMIPS (lpj=%lu)\n",
             loops_per_jiffy/(500000/HZ),
             (loops_per_jiffy/(5000/HZ)) % 100,
             loops_per_jiffy);

计算 MogoMIPS 的方法:
BogoMIPS = loops_per_jiffy * HZ * 循环延迟所消耗指令

循环延迟是指 __delay() 这个循环,它的基本延迟就是 decl 和 jns 这两条指令。所以根据上面的公式有:
loops_per_jiffy * HZ * 2 / 1000000
底下除数 1000000 就是 MIPS ,表示 100W 条指令,所以又得到: loops_per_jiffy/(500000/HZ)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-6 09:59 , Processed in 0.083629 second(s), 24 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表