Skip to content

Plan 9でCPUの温度を計測する

/dev/cputemp を読むと温度が分かる。ただしファイルの内容はCPUによって異なる。Intel CPUの場合は3つのフィールドを持つ。

res t status

res はResolution in Degrees Celsiusのようだが具体的にどのような値なのかは分からない。t は温度(摂氏)の値で、未計測の場合は-1となる。statusalarm または 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 long
cputempread(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);
}