zoukankan      html  css  js  c++  java
  • 内核探索:Linux BogoMips 探秘【转】

    转自:http://tinylab.org/explore-linux-bogomips/

    Tao HongLiang 创作于 2015/05/12

    By Tao Hongliang of TinyLab.org 2015/04/12

    1 背景

    今天和往常一样,在实验室和一群攻城师同事们没日没夜的码着代码。突然,一个同学问了一句: /proc/cpuinfo (龙芯平台) 里的 BogoMIPS 和 CPU 的频率是什么关系? 一石激起千层浪,一时间各种奇葩的答案层出不穷,最终也没个定论。本攻城师决定直捣黄龙一探究竟,给迷茫的小伙伴们一个交代。

    2 BogoMIPS 的由来

    BogoMIPS 是 Linus 本人的独创,Bogo 意思是“假的,伪造的”,MIPS 意思是“Millions of Instructions Per Second”,如果系统启动时,计算出 BogoMIPS 为 100,可记为 100万条伪指令每秒。

    之所以叫伪指令,是因为在计算 BogoMIPS 的值时,CPU 一直在单一的执行 NOP (空操作),而不是随机执行指令集中的任意指令,所以不能以此作为 CPU 的性能指标。

    3 BogoMIPS 的计算

    现在就让我们走进代码,看看他是怎么计算的。笔者是在 v3.13.0 版本的 Linux kernel 源码中做的实验。这一部分变动很少,其他相似版本应该无差别。 </br>

    首先,在文件 arch/mips/kernel/proc.c 中给出了 BogoMIPS 的计算方式:

    1. seq_printf(m, "BogoMIPS : %u.%02u ",
    2. cpu_data[n].udelay_val / (500000/HZ),
    3. (cpu_data[n].udelay_val / (5000/HZ)) % 100);

    其中 HZ 是在内核配置的时候就确定好的常量,那在这个公式里就只剩 udelay_val 的值是未知的了。小提醒:这里是一个经典的用整型来表达浮点类型的例子,小伙伴们可以学习下。 </br>

    然后,在文件 arch/mips/include/asm/bugs.h中给出了 udelay_val 的计算方式:

    1. cpu_data[cpu].udelay_val = loops_per_jiffy;

    最后,在文件init/calibrate.c中,我们能找到 loops_per_jiffy 的计算方式:

    1. #define LPS_PREC 8
    2.  
    3. static unsigned long calibrate_delay_converge(void)
    4. {
    5. /* First stage - slowly accelerate to find initial bounds */
    6. unsigned long lpj, lpj_base, ticks, loopadd, loopadd_base, chop_limit;
    7. int trials = 0, band = 0, trial_in_band = 0;
    8.  
    9. lpj = (1<<12);
    10.  
    11. /* wait for "start of" clock tick */
    12. /* 这里很聪明的选择了一个计算 loops 的起始时间,即,一个 tick 刚开始的时候 */
    13. ticks = jiffies;
    14. while (ticks == jiffies)
    15. ; /* nothing */
    16. /* Go .. */
    17. ticks = jiffies;
    18.  
    19. /* 这里用逐渐逼近的方式计算在一个jiffy的时间段内,循环调用 __delay(NOP 循环),
    20. * 最后累计 delay 了多少。loops_per_jiffy 就是多少了。
    21. */
    22. do {
    23. if (++trial_in_band == (1<<band)) {
    24. ++band;
    25. trial_in_band = 0;
    26. }
    27. __delay(lpj * band);
    28. trials += band;
    29. } while (ticks == jiffies);
    30. /*
    31. * We overshot, so retreat to a clear underestimate. Then estimate
    32. * the largest likely undershoot. This defines our chop bounds.
    33. */
    34. trials -= band;
    35. loopadd_base = lpj * band;
    36. lpj_base = lpj * trials;
    37.  
    38. /* 接下来,再对上面算出来的 loops_per_jiffy 的值进行微调,确保其准确 */
    39. recalibrate:
    40. lpj = lpj_base;
    41. loopadd = loopadd_base;
    42.  
    43. /*
    44. * Do a binary approximation to get lpj set to
    45. * equal one clock (up to LPS_PREC bits)
    46. */
    47. chop_limit = lpj >> LPS_PREC;
    48. while (loopadd > chop_limit) {
    49. lpj += loopadd;
    50. ticks = jiffies;
    51. while (ticks == jiffies)
    52. ; /* nothing */
    53. ticks = jiffies;
    54. __delay(lpj);
    55. if (jiffies != ticks) /* longer than 1 tick */
    56. lpj -= loopadd;
    57. loopadd >>= 1;
    58. }
    59. /*
    60. * If we incremented every single time possible, presume we've
    61. * massively underestimated initially, and retry with a higher
    62. * start, and larger range. (Only seen on x86_64, due to SMIs)
    63. */
    64. if (lpj + loopadd * 2 == lpj_base + loopadd_base * 2) {
    65. lpj_base = lpj;
    66. loopadd_base <<= 2;
    67. goto recalibrate;
    68. }
    69.  
    70. return lpj;
    71. }

    这下我们搞清楚了 loops_per_jiffy 的实质。详细计算方式,可以参考上面代码中给出的中文注释。

    1. BogoMIPS = loops_per_jiffy ÷ (500000 / HZ) ---> BogoMIPS = (loops_per_jiffy * HZ) ÷ 500000

    HZ 是什么,HZ 就是每秒的滴答数,即每秒的 jiffy 数。那么,loops_per_jiffy * HZ = loops_per_second

    1. BogoMIPS = loops_per_second ÷ 500000 ---> BogoMIPS = (loops_per_second * 2) ÷ 1000000

    自此,BogoMIPS 的计算探秘结束。

    4 BogoMIPS 和 CPU 频率的关系

    看了上面 BogoMIPS 的计算方式,我们发现并没有一个直接的公式可以让 BogoMIPS 和 CPU 频率之间相互转换。但至少可以推断出对于同一款处理器

    • CPU 频率越快,loops_per_second 的值必然越大,那么 BogoMIPS 的值将会越大;
    • CPU 频率越低,则 BogoMIPS 的值将越小;
    • CPU 变频的时候,BogoMIPS 会随着 CPU 频率升高而升高,降低而降低。

    引用 维基百科上已有的数据,可以进一步的对于 BogoMIPS 和 CPU 频率之间的关系,有更深的感性认识:

    Linux BogoMips


    猜你喜欢:

    Read Related:

    Read Latest:

  • 相关阅读:
    [FAQ] jsoneditor 如何切换 mode 或者选择 modes
    IDA动态调试快捷键
    [FAQ] PHP Warning: json_encode(): double INF does not conform to the JSON spec
    Git 工具下载慢问题 & 图像化界面工具
    Windows 查看端口是被什么程序占用
    什么是 objdump 命令
    什么是 IDA 工具
    什么是 ELF 文件(文件格式)
    ARM 反汇编速成
    [Mobi] Android Studio NDK 安装
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/14005406.html
Copyright © 2011-2022 走看看