linux calibrate_delay
https://blog.csdn.net/chenliang0224/article/details/78704823
1.核心啟動資訊
console [ttyS0] enabled
Calibrating delay loop… 148.88 BogoMIPS (lpj=744448)
pid_max: default: 32768 minimum: 301
2.BogoMIPS
BogoMIPS (Bogo–Bogus–偽的,MIPS–millions of instruction per second) 按照字面的解釋是“不太真實的MIPS”。之所以不太真實,那是因為其計算方法並不十分精確。BogoMIPS的值在系統系統時,在一閃而過的啟動資訊裡可以看到;也可以dmesg看到;還可以通過檢視/proc/cpuifo看到。BogoMIPS 的值是 linux 核心通過在一個時鐘節拍裡不斷的執行迴圈指令而估算出來,它實際上反應了 CPU 的速度。
3.calibrate_delay()
路徑:linux-3.10.x\init\main.c–>start_kernel–>calibrate_delay
void __cpuinit calibrate_delay(void)
{
unsigned long lpj;
static bool printed;
int this_cpu = smp_processor_id();
if (per_cpu(cpu_loops_per_jiffy, this_cpu)) { lpj = per_cpu(cpu_loops_per_jiffy, this_cpu); if (!printed) pr_info("Calibrating delay loop (skipped) " "already calibrated this CPU"); } else 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_is_known())) { ; } else if ((lpj = calibrate_delay_direct()) != 0) { if (!printed) pr_info("Calibrating delay using timer " "specific routine.. "); } else { if (!printed) pr_info("Calibrating delay loop... "); lpj = calibrate_delay_converge(); } per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj; if (!printed) pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n", lpj/(500000/HZ), (lpj/(5000/HZ)) % 100, lpj); loops_per_jiffy = lpj; printed = true;
}
BogoMIPS計算的核心函式:
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); //1<<12=4096 /* wait for "start of" clock tick */ ticks = jiffies; while (ticks == jiffies) //等待下一個時鐘節拍 ; /* nothing */ /* Go .. */ ticks = jiffies; do { if (++trial_in_band == (1<<band)) { //首次進入do{...}while(x)時if條件成立,初始化band=1和trial_in_band=0 ++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; //去除上面do{...}while(x)裡迴圈的最後一次,因為最後一次時鐘節拍已經變更,所以不能統計到裡面 loopadd_base = lpj * band; //上面do{...}while(x)最後一次迴圈所需的時間,也是下一個時鐘節拍的起始值 lpj_base = lpj * trials; //一個時鐘節拍需要的時間
recalibrate:
lpj = lpj_base; //一個時鐘節拍需要的時間
loopadd = loopadd_base; //上面do{…}while(x)最後一次迴圈所需的時間,也是下一個時鐘節拍的起始值
/*
* Do a binary approximation to get lpj set to
* equal one clock (up to LPS_PREC bits)
*/
chop_limit = lpj >> LPS_PREC; //用於控制迴圈計算的次數,一個時鐘節拍分頻/2^8, 2^8=256
while (loopadd > chop_limit) { //採用二分法的方式,無限靠近真值, 下一個時鐘節拍的首次值 > 一個時鐘節拍內256分頻後的值,通過分析該while迴圈意思應該是要迴圈256次
lpj += loopadd;
ticks = jiffies;
while (ticks == jiffies)
; /* nothing */
ticks = jiffies;
__delay(lpj);
if (jiffies != ticks) /* longer than 1 tick */
lpj -= loopadd; //時鐘滴答切換,徐去除最後一次值,這裡的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;
}
根據報文中lpj=744448,Calibrating delay loop… 148.88 BogoMIPS (lpj=744448)
作者:chenliang0224
來源:CSDN
原文:https://blog.csdn.net/chenliang0224/article/details/78704823
版權宣告:本文為博主原創文章,轉載請附上博文連結!