1. 程式人生 > >linux calibrate_delay

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
版權宣告:本文為博主原創文章,轉載請附上博文連結!