许可优化
许可优化
产品
产品
解决方案
解决方案
服务支持
服务支持
关于
关于
软件库
当前位置:服务支持 >  软件文章 >  BogoMIPS与calibrate_delay函数解析

BogoMIPS与calibrate_delay函数解析

阅读数 66
点赞 0
article_banner

    在分析Arm+linux启动 信息 的时候。发现有一个信息竟然耗费了2s的时间,这简直是不能忍受的。这个耗时大鳄是什么东西哪,请看分析信息:


[    0.000000] console [ttyMT0] enabled

[    2.057770] Calibrating delay loop... 1694.10 BogoMIPS (lpj=4235264)

[    2.102188] pid_max: default: 32768 minimum: 301

针对上述信息,有很多疑惑,一点一点来分析。

1.何为BogoMIPS

BogoMIPS (Bogo--Bogus--伪的,MIPS--millions of instruction per second) 按照字面的解释是“不太真实的MIPS”。之所以不太真实,那是因为其计算方法并不十分精确。BogoMIPS的值在系统系统时,在一闪而过的启动信息里可以看到;也可以dmesg看到;还可以通过查看/proc/cpuifo看到。BogoMIPS 的值是 linux 内核通过在一个时钟节拍里不断的执行循环指令而估算出来,它实际上反应了 CPU 的速度。

2.怎么计算BogoMIPS

“Calibrating delay loop  ... 1694.10 BogoMIPS”来自文件init/ calibrate.c中的函数calibrate_delay(),该函数主要作用根据不同的配置计算BogoMIPS的值。



void __cpuinit calibrate_delay(void){    unsigned long lpj;    static bool printed;     if (preset_lpj) {       lpj = preset_lpj;       if (!printed)           pr_info("Calibrating delay loop (skipped) "              "preset value.. ");    } else if ((!printed) && lpj_fine) {       lpj = lpj_fine;       pr_info("Calibrating delay loop (skipped), "           "value calculated using timer frequency.. ");    } else if ((lpj = calibrate_delay_direct()) != 0) {       if (!printed)           pr_info("Calibrating delay using timer "              "specific routine.. ");    } else {       if (!printed)          <strong> pr_info("Calibrating delay loop... ");         </strong>lpj = calibrate_delay_converge();    }    if (!printed)<strong>       pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",           lpj/(500000/HZ),           (lpj/(5000/HZ)) % 100, lpj);</strong>     loops_per_jiffy = lpj;    printed = true;}


这其中有两个全局变量需要分析,他们是preset_lpjlpj_fine。定义在文件init/calibrate.c中:


unsigned long lpj_fine;

unsigned long preset_lpj;

在linux gcc言,unsigned long变量默认 赋值 为0。

   另外,printed表示信息仅仅打印一次。

1. 若preset_lpj不为0

preset_lpj初值为0。

preset_lpj的赋值是有函数lpj_setup设置而来,该参数是有 kernel   bootloader设置而来。


unsigned long preset_lpj;

static int __init lpj_setup(char *str)

{

   preset_lpj = simple_strtoul(str,NULL,0);

   return 1;

}

__setup("lpj=", lpj_setup);

若preset_lpj不为0,表示lpj的值已经由用户预置,无需内核再行计算,直接赋值给lpj既可。

2. 否则,若printed为0 且 lpj_fine不为0

printed默认为0,只需观察lpj_fine的值既可以。

lpj_fine很简单,如果其不为0,表示该变量是有timer来计算的,无需再行计算,赋值给lpj既可。

3. 否则,若 calibrate_delay_direct()不等于0

  查找配置文件,可以发现很多时候ARCH_HAS_READ_CURRENT_TIMER配置项都是没有设置的,因为calibrate_delay_direct()会直接返回0。

4. 其他

   需要分析calibrate_delay_converge(),该函数是主力函数。



/* * This is the number of bits of precision for the loops_per_jiffy. Each * time we refine our estimate after the first takes 1.5/HZ seconds, so try * to start with a good estimate. * For the boot cpu we can skip the delay calibration and assign it a value * calculated based on the timer frequency. * For the rest of the CPUs we cannot assume that the timer frequency is same as * the cpu frequency, hence do the calibration for those. */#define LPS_PREC 8 static unsigned long __cpuinit calibrate_delay_converge(void){    /* First stage - slowly accelerate to find initial bounds */    unsigned long lpj, lpj_base, ticks, loopadd, loopadd_base, chop_limit;    int trials = 0, band = 0, trial_in_band = 0;     lpj = (1<<12);/* 初始化为4096 */    /* wait for "start of" clock tick */   /* ticks保存当前jiffies的值。在while()中,只要ticks == jiffies,那么就一直执行空语句,也就是,只要时钟节拍还没更新则一直等待;注:系统用jiffies全局变量记录了从系统开始工作到现在为止,所经过的时钟节拍数 */    ticks = jiffies;    while (ticks == jiffies)       ; /* nothing */    /* Go .. */   /* 估算一个时钟节拍内可执行的循环次数 */    ticks = jiffies;    do {       if (++trial_in_band == (1<<band)) {           ++band;           trial_in_band = 0;       }       __delay(lpj * band);       trials += band;    } while (ticks == jiffies);    /* * We overshot, so retreat to a clear underestimate. Then estimate * the largest likely undershoot. This defines our chop bounds. */    trials -= band;    loopadd_base = lpj * band;    lpj_base = lpj * trials; recalibrate:    lpj = lpj_base;/* lpj取估算值为初值,精确度大约为tick/2(若band=2) */    loopadd = loopadd_base;     /* * Do a binary approximation to get lpj set to * equal one clock (up to LPS_PREC bits) *//* 采用二分法的方式,无限靠近真值 */    chop_limit = lpj >> LPS_PREC; /* 用于控制循环计算的次数 */    while (loopadd > chop_limit) {       lpj += loopadd;       ticks = jiffies;       while (ticks == jiffies)           ; /* nothing */       ticks = jiffies;       __delay(lpj);       if (jiffies != ticks)   /* longer than 1 tick */           lpj -= loopadd;       loopadd >>= 1;    }    /* * If we incremented every single time possible, presume we've * massively underestimated initially, and retry with a higher * start, and larger range. (Only seen on x86_64, due to SMIs) */    /* 若每一次都是递增的(可能低估了lpj),则需要使用较大的初值和步幅 */    if (lpj + loopadd * 2 == lpj_base + loopadd_base * 2) {       lpj_base = lpj;       loopadd_base <<= 2;       goto recalibrate;    }     return lpj;}


3.BogoMIPS的用途

对于特定的CPU,BogoMips可用来查看它是否是个合适的值.它的时钟频率和它潜在的CPU缓存。但是它不可在不同的CPU间进行比较演示。

请参考百度百科和wiki百科

http://baike.baidu.com/view/1086713.htm

http://zh.wikipedia.org/zh-cn/BogoMips

Ok说了这么多,终于将该函数分析完了。

免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删


相关文章
技术文档
QR Code
微信扫一扫,欢迎咨询~
customer

online

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 board-phone 155-2731-8020
close1
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

姓名不为空

姓名不为空
手机不正确

手机不正确

手机不正确
公司不为空

公司不为空

公司不为空