在分析Arm+linux啓動信息的時候。發現有一個信息居然耗費了2s的時間,這簡直是不能忍受的。這個耗時大鱷是什麼東西哪,請看分析信息:linux
[ 0.000000] console [ttyMT0] enabled緩存
[ 2.057770] Calibrating delay loop... 1694.10 BogoMIPS (lpj=4235264)app
[ 2.102188] pid_max: default: 32768 minimum: 301函數
針對上述信息,有不少疑惑,一點一點來分析。oop
BogoMIPS (Bogo--Bogus--僞的,MIPS--millions of instruction per second) 按照字面的解釋是「不太真實的MIPS」。之因此不太真實,那是由於其計算方法並不十分精確。BogoMIPS的值在系統系統時,在一閃而過的啓動信息裏能夠看到;也能夠dmesg看到;還能夠經過查看/proc/cpuifo看到。BogoMIPS 的值是 linux 內核經過在一個時鐘節拍裏不斷的執行循環指令而估算出來,它實際上反應了 CPU 的速度。ui
「Calibrating delay loop... 1694.10 BogoMIPS」來自文件init/ calibrate.c中的函數calibrate_delay(),該函數主要做用根據不一樣的配置計算BogoMIPS的值。spa
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_lpj和lpj_fine。定義在文件init/calibrate.c中:rest
unsigned long lpj_fine;code
unsigned long preset_lpj;htm
在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; }
對於特定的CPU,BogoMips可用來查看它是不是個合適的值.它的時鐘頻率和它潛在的CPU緩存。可是它不可在不一樣的CPU間進行比較演示。
請參考百度百科和wiki百科
http://baike.baidu.com/view/1086713.htm
http://zh.wikipedia.org/zh-cn/BogoMips
Ok說了這麼多,終於將該函數分析完了。