Plan 9でCPUの温度を計測する
/dev/cputemp を読むと温度が分かる。ただしファイルの内容はCPUによって異なる。Intel CPUの場合は3つのフィールドを持つ。
res t statusres はResolution in Degrees Celsiusのようだが具体的にどのような値なのかは分からない。t は温度(摂氏)の値で、未計測の場合は-1となる。status は alarm または unsupported を返すが、どちらもなければ省略される。
実装を読むと、Intel CPUで温度を計測するで調べたように、CPUID命令でDTSセンサーの有無を調べている。これが存在しなければ /dev/cputemp ファイルも無い。
cpuid(6, regs);if((regs[0] & 1) == 0) return readstr(offset, a, n, Notemp);cpuid 関数では機能テーブル6を取得してregsに入れて返す。ここでDTSセンサー未対応のハードウェアなら、 /dev/cputemp ファイルは固定で以下の文字列を返す。
-1 -1 unsupported\n続いて、TCC activation temperatureの値を調べている。この値は85〜105までの範囲を取りうるらしいが、Plan 9のコードでは100か85の2種類しか考慮していないようだった。
tj = 100; /* tjはthermal junctionの略かな */d = X86MODEL(m->cpuidax);d |= (m->cpuidax>>12) & 0xf0;if((d == 0xf && (m->cpuidax & 0xf)>1) || d == 0xe){ rdmsr(0xee, &emsr); msr = emsr; if(msr & 1<<30) tj = 85;}これであとは現在のDTS値を調べて tj との差を取ればいい。
rdmsr(0x19c, &emsr);msr = emsr;t = -1;if(msr & 1<<31){ t = (msr>>16) & 127; /* 17..23bit */ t = tj - t;}res = (msr>>27) & 15;if((msr & 0x30) == 0x30) s = " alarm";snprint(buf, sizeof buf, "%ld %lud%s\n", t, res, s);ところで、Intel CPUの場合は3つのフィールドだけど、ARMの場合はフィールドを1つしか持たない。
static longcputempread(Chan*, void *a, long n, vlong offset){ char str[16]; snprint(str, sizeof str, "%ud\n", (getcputemp()+500)/1000); return readstr(offset, a, n, str);}