2011年08月23日
/proc/cpuinfoの疑問点をソースコードで確認する
いくつかのAndroid端末の/proc/cpuinfoを見比べてみると疑問なところがあります。
- ブート時のBogoMIPSと値と/proc/cpuinfoでの値が異なるものがある。
- デュアルコアの端末でブート時のログでは2つCPUを起動しているのに、/proc/cpuinfoではひとつしか表示されない。
これらをソースコードで調べてみました。
ブート時のBogoMIPSと値と/proc/cpuinfoでの値が異なるものがある。
KZM-A9-Dualボードなどの評価ボードでは起動時のBogoMIPSと/proc/cpuinfoでの値は一致しています。しかし、市販の携帯電話では両者は異なっていて、/proc/cpuinfoでの方が非常に小さな値になります。
Nexus Oneの例では、ブート時のBogoMIPS
<6>[ 0.000000] NR_IRQS:316
<6>[ 0.000000] Calibrating delay loop... 509.54 BogoMIPS (lpj=2547712)
<6>[ 0.229461] pid_max: default: 32768 minimum: 301
<4>[ 0.229705] Mount-cache hash table entries: 512
右側のタイムスタンプからBogoMIPSの計測に約200msecかけて実測したと思われます。
一方、/proc/cpuinfoでの値はその約1/3です。
Processor : ARMv7 Processor rev 2 (v7l)
BogoMIPS : 162.54
Features : swp half thumb fastmult vfp edsp thumbee neon
デュアルコアの端末でブート時のログでは2つCPUを起動しているのに、/proc/cpuinfoではひとつしか表示されない。
KZM-A9-Dualボードはデュアルコアです。SMP対応のカーネルを使えば2つのCPUを起動します。/proc/cpuinfoではCPUの情報が2つ表示されます。
GALAXY S IIもデュアルコアです。ブートログでは以下のように2つCPUを起動しています。
<6>[ 0.000176] Calibrating delay loop (skipped) preset value.. 1592.52 BogoMIPS (lpj=3981312) <6>[ 0.000203] pid_max: default: 32768 minimum: 301 <4>[ 0.000331] Mount-cache hash table entries: 512 ... <4>[ 0.025099] CPU1: Booted secondary processor <6>[ 0.025175] Brought up 2 CPUs <6>[ 0.025188] SMP: Total of 2 processors activated (3185.04 BogoMIPS).
しかし、/proc/cpuinfoではひとつのCPUしか表示されません。
Processor : ARMv7 Processor rev 1 (v7l) processor : 0 BogoMIPS : 1592.52 Features : swp half thumb fastmult vfp edsp neon vfpv3 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x2 CPU part : 0xc09 CPU revision : 1 Hardware : SMDKC210 Revision : 000c Serial : xxxxxxxxxxxxxxxx
/proc/cpuinfoを表示する部分のkernelのソースコードを調べる
fs/proc/cpuinfo.c からたどっていくと
arch/arm/kernel/setup.c
static int c_show(struct seq_file *m, void *v) { int i; seq_printf(m, "Processor\t: %s rev %d (%s)\n", cpu_name, read_cpuid_id() & 15, elf_platform); #if defined(CONFIG_SMP) for_each_online_cpu(i) { /* * glibc reads /proc/cpuinfo to determine the number of * online processors, looking for lines beginning with * "processor". Give glibc what it expects. */ seq_printf(m, "processor\t: %d\n", i); seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n", per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ), (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100); } #else /* CONFIG_SMP */ seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", loops_per_jiffy / (500000/HZ), (loops_per_jiffy / (5000/HZ)) % 100); #endif /* dump out the processor features */ seq_puts(m, "Features\t: "); for (i = 0; hwcap_str[i]; i++) ... return 0; }
BogoMIPSはloops_per_jiffyという変数から算出されていることがわかりました。この値は短い時間をタイトループで待つときのカウンタで、省電力モードでCPUのクロックを下げるときには連動してこの値を変えていました。
つまり、Nexus Oneで通常状態でのBogoMIPSの値が小さかったのは、省電力のためにCPUのクロックを落としていたからでした。
また、SMPのときは、for_each_online_cpu(i)というマクロでループを回しています。このマクロは include/linux/cpumask.h で定義されています。
for_each_online_cpu(i)ではそのときに稼働しているCPUだけになります。ブート時に認識した全てのCPUで回すのは for_each_possible_cpu(i)です。
つまり、GALAXY S IIは通常時は2つのCPUのうちのひとつしか動かしていないということがわかりました。おそらく省電力のために止めているのでしょう。