在啟動過程中,內核會計算處理器在一個jiffy時間內運行一個內部的延遲循環的次數。jiffy的含義是系統定時器 2個連續的節拍之間的間隔。正如所料,該計算必須被校準到所用CPU的處理速度。校準的結果被存儲在稱為loops_per_jiffy的內核變量中。使用loops_per_jiffy的一種情況是某設備驅動程序希望進行小的微秒級別的延遲的時候。


為了理解延遲—循環校​​準代碼,讓我們看一下定義於init/calibrate.c文件中的calibrate_ delay()函數。該函數靈活地使用整型運算得到了浮點的精度。如下的代碼片段(有一些註釋)顯示了該函數的開始部分,這部分用於得到一個loops_per_jiffy的粗略值


1 #define LPS_PREC 8    
  //定義計算BogoMIPS的精度,這個值越大,則計算出的BogoMIPS越精確。
2 void __init calibrate_delay(void)
3 {
4 unsigned long ticks,loopbit;
5 int lps_precision=LPS_PREC
6
7 loops_per_sec=(1<<12);
  //loops_per_sec為每秒鐘執行一個極短的循環的次數。
8
9 printk(「Calibrating delay loop…」); 
10 while(loops_per_sec<<=1) {
  //第10至21行,是第一次計算loops_per_sec的值,這次計算只是一個粗略的計算,為下面的計算打好基礎。
11 /* wait for 「start of」 clock tick */
   /*第11 至16行,是用於等待一個新的定時器滴答(它大概是百萬分之一秒)的開始。
   可以想像我們要計算loops_per_sec的值,可以在一個滴答的開始時,立即重複執行一個極短的循環,
   當一個滴答結束時,這個循環執行了多少次就是我們要求的初步的值,再用它乘以一秒鐘內的滴答數就是loops_per_sec的值。
   */
12 ticks=jiffies;
12 系統用jiffies全局變量記錄了從系統開始工作到現在為止,所經過的滴答數。它會被內核自動更
   新。這行語句用於記錄當前滴答數到tick變量中。
13 while(ticks==jiffies)
13 注意這是一個沒有循環體得空循環,第14行僅有一個「;」號。這條循環語句是通過判斷tick的
   值與jiffies的值是否不同,來判斷jiffies是否變化,即是否一個新的滴答開始了
14 /* nothing */;
15 /* Go… */
16 ticks=jiffies;
16 記錄下新的滴答數以備後用。
17 __delay(loops_per_sec);
17 根據loops_per_sec值進行延時(及執行loop_per_sec次極短循環)。
18 ticks=jiffies-ticks;
18 以下三行用於判斷執行的延時是否超過一個滴答。一般loops_per_sec的初始值並不大,
   所以循環會逐步加大loops_per_sec的值,直到延時超過一個滴答。我們可以看出,前
   一次loops_per_sec的值還因太小不合適時,經過一次增大,它提高了兩倍,滿足了循環
   條件,跳出循環,而這個值實在是誤差太大,所以我們還要經過第二次計算。這裡還要注
   意的是通過上面的分析,我們可以知道更加精確的loops_per_sec的值應該在現在的值與它的
   一半之間。
19 if(ticks)
20 break;
21 }
22
23 /* Do a binary approximation to get loops_per_second set
24 * to equal one clock (up to lps_precision bits) */
23 這裡開始就是第二次計算了。它用折半查找法在我們上面所說的範圍內計算出了更精確的loops_per_sec的值。
25 loops_per_sec >>=1;
25 義查找範圍的最小值,我把它稱為起點。
26 loopbit=loop_per_sec;
26 定義查找範圍,這樣我們就可以看到loop_per_sec的值在「起點」與「起點加範圍(終點)」之間。
27 while(lps_precision-- && (loopbit >>=1) ) {
27 進入循環,將查找範圍減半。
28 loops_per_sec |= loopbit;
28 重新定義起點,起點在「原起點加27行減半範圍」處,即新起點在原先起點與終點的中間。這時我們可以
   看出loops_per_sec在「新起點」與「新起點加減半範圍(新終點)」之間。
29 ticks=jiffies;
29 第29至32行與第12至17行一致,都是等待新的滴答,執行延時。
30 while(ticks==jiffies);
31 ticks=jiffies;
32 __delay(loops_per_sec);
33 if(jiffies!=ticks) /* longer than 1 tick */
33 如果延時過短,說明loops_per_sec的值小了,將會跳過這部分,再次進入循環。它將是通過不斷的折
   半方式來增大。如果延時過長,說明loops_per_sec的值大了,將起點重新返回原起點,當再次進入循環,
   由於範圍減半,故可以達到減小的效果。
34 loops_per_sec &=~loopbit;
35 }
36 /* finally,adjust loops per second in terms of seconds
37 * instead of clocks */
38 loops_per_sec *= HZ;
38 計算出每秒執行極短循環的次數。從這裡我們可以看出它好像是個死循環,所以加入了lps_precision變量
   ,來控制循環,即LPS_PREC越大,循環次數越多,越精確。可能這些不太好懂,總的說來,它首先將loop_per_sec
   的值定為原估算值的1/2,作為起點值(我這樣稱呼它),以估算值為終點值.然後找出起點值到終點值的中間值.用上面
   相同的方法執行一段時間的延時循環.如果延時超過了一個tick,說明loop_per_sec值偏大,則仍以原起點值為起點值,
   以原中間值為終點值,以起點值和終點值的中間為中間值繼續進行查找,如果沒有超過一個tick,說明loop_per_sec偏
   小,則以原中間值為起點值,以原終點值為終點值繼續查找。


39 /* Round the value and print it */
40 printk(「%lu.%02lu BogoMIPSn」,
41 (loops_per_sec+2500)/500000,
42 ((loops_per_sec+2500)/5000) % 100);
40 出BogoMIPS,並打印。
43 }


 


 


http://www.lslnet.com/linux/f/docs1/i34/big5259869.htm

    全站熱搜

    立你斯 發表在 痞客邦 留言(0) 人氣()