核心探索: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 的計算方式:
- seq_printf(m, "BogoMIPS\t\t: %u.%02u\n",
- cpu_data[n].udelay_val / (500000/HZ),
- (cpu_data[n].udelay_val / (5000/HZ)) % 100);
其中 HZ 是在核心配置的時候就確定好的常量,那在這個公式裡就只剩 udelay_val 的值是未知的了。小提醒:這裡是一個經典的用整型來表達浮點型別的例子,小夥伴們可以學習下。 </br>
然後,在檔案 arch/mips/include/asm/bugs.h
中給出了 udelay_val 的計算方式:
- cpu_data[cpu].udelay_val = loops_per_jiffy;
最後,在檔案init/calibrate.c
中,我們能找到 loops_per_jiffy 的計算方式:
- #define LPS_PREC 8
- static unsigned long 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);
- /* wait for "start of" clock tick */
- /* 這裡很聰明的選擇了一個計算 loops 的起始時間,即,一個 tick 剛開始的時候 */
- ticks = jiffies;
- while (ticks == jiffies)
- ; /* nothing */
- /* Go .. */
- ticks = jiffies;
- /* 這裡用逐漸逼近的方式計算在一個jiffy的時間段內,迴圈呼叫 __delay(NOP 迴圈),
- * 最後累計 delay 了多少。loops_per_jiffy 就是多少了。
- */
- 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;
- /* 接下來,再對上面算出來的 loops_per_jiffy 的值進行微調,確保其準確 */
- recalibrate:
- lpj = lpj_base;
- 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)
- */
- if (lpj + loopadd * 2 == lpj_base + loopadd_base * 2) {
- lpj_base = lpj;
- loopadd_base <<= 2;
- goto recalibrate;
- }
- return lpj;
- }
這下我們搞清楚了 loops_per_jiffy 的實質。詳細計算方式,可以參考上面程式碼中給出的中文註釋。
- BogoMIPS = loops_per_jiffy ÷ (500000 / HZ) ---> BogoMIPS = (loops_per_jiffy * HZ) ÷ 500000
HZ 是什麼,HZ 就是每秒的滴答數,即每秒的 jiffy 數。那麼,loops_per_jiffy * HZ = loops_per_second
- 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 實戰經驗與技巧,訂閱「Linux知識星球」
- 儒碼科技:Linux 技術諮詢、培訓與服務,聯絡「儒碼科技」
- 技術交流:Linux 使用者技術交流微信群,聯絡微訊號:tinylab
支付寶打賞 ¥9.68元 |
微信打賞 ¥9.68元 |
|
請作者喝杯咖啡吧 |