BogoMIPS与calibrate_delay

     在分析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说了这么多,终于将该函数分析完了。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
可以使用以下命令查看Linux CPU的厂商信息: 1. 使用lscpu命令查看: lscpu命令可以显示CPU的详细信息,包括厂商信息、架构、核心数等等。 命令:lscpu 示例输出: ``` Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 1 On-line CPU(s) list: 0 Thread(s) per core: 1 Core(s) per socket: 1 Socket(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 158 Model name: Intel(R) Core(TM) i5-7500T CPU @ 2.70GHz Stepping: 9 CPU MHz: 2700.000 BogoMIPS: 5400.00 Virtualization: VT-x L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 6144K ``` 可以看到,Vendor ID显示的是CPU厂商信息,这里是GenuineIntel,表示是英特尔的CPU。 2. 使用cat /proc/cpuinfo命令查看: cat /proc/cpuinfo命令可以显示CPU的详细信息,包括厂商信息、型号、频率等等。 命令:cat /proc/cpuinfo 示例输出: ``` processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i5-7500T CPU @ 2.70GHz stepping : 9 cpu MHz : 2700.000 cache size : 6144 KB physical id : 0 siblings : 1 core id : 0 cpu cores : 1 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves ibrs_enhanced tpr_adjust md_clear flush_l1d bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs bogomips : 5400.00 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: ``` 可以看到,vendor_id显示的是CPU厂商信息,这里也是GenuineIntel,表示是英特尔的CPU。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YoungerChina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值