バッテリーの power_now は信用できない - energy_now で本当の消費電力を測る
ノート PC の消費電力を調べようとして /sys/class/power_supply/BAT0/power_now を見ると、妙なことに気づく。
CPU に負荷をかけても、数値がほとんど動かない。
この機体では、アイドルでも全力負荷でも 約 8.6W のあたりをうろうろする。これでは「8スレッド回したら何W増えたか」なんて分からない。最初は「省電力が効いているのか」と思ったが、そうではなかった。power_now が信用できない値だったのだ。
結論を先に書く。
- この機体の
power_nowは、負荷をかけてもほぼ一定の推定値(約 8.6W)で、実際の消費電力を反映しない - 正しいのは
energy_now(残量)の差分を時間で割る方法 - 実測: アイドル 約 5.7W / 8スレッド負荷 約 22.8W
なぜ power_now が嘘になるのか
power_now はドライバやファームウェアが計算して出す値で、ハードによっては電流・電圧の計測ではなく、いい加減な推定を返す。この機体(HP OmniBook、AMD)がまさにそれで、負荷に追従しない。
一方 energy_now(バッテリー残量、単位は µWh)は、実際に減っていく残量そのもの。これを時間で割れば、本当の平均消費電力になる。
正しい測り方
energy_now を一定時間あけて2回読み、差分を時間で割る。
BAT=/sys/class/power_supply/BAT0
e1=$(cat $BAT/energy_now); t1=$(cut -d. -f1 /proc/uptime)
sleep 120
e2=$(cat $BAT/energy_now); t2=$(cut -d. -f1 /proc/uptime)
# P[W] = ΔE[µWh] * 0.0036 / Δt[s]
awk -v e1=$e1 -v e2=$e2 -v t1=$t1 -v t2=$t2 \
'BEGIN { printf "%.2f W\n", (e2-e1)*0.0036/(t2-t1) }'
時間に date(実時刻)ではなく /proc/uptime(起動時間) を使うのがポイント。この機体の実時刻はスリープをまたぐと正しく進まないため、CLOCK_BOOTTIME を使う。
落とし穴: 量子化
energy_now は 10mWh(10000 µWh)刻みでしか動かない。つまり短時間の計測では、差分が1目盛しか進まず精度が出ない。
たとえば 5W で 10秒測ると、動くのは 0.014Wh = 1.4目盛。誤差が 70% にもなる。目安として2分以上測ると安定する。不確かさは「1目盛 ÷ 計測時間」で見積もれる。
実測結果
- アイドル(
platform_profile=quiet適用後): 約 5.7W - 8スレッド負荷: 約 22.8W
power_now が約 8.6W で固定されていたのに対し、実際はアイドル 5.7W から負荷 22.8W まで、4倍の幅で動いていた。これを知らずに「電力を見て最適化」すると、嘘の数値を追いかけることになる。
まとめ
power_nowを信じるな。ハードによっては推定値で、負荷に追従しないenergy_nowの差分を時間で割れば、本当の消費電力が出る- 量子化(10mWh 刻み)を意識して、2分以上測る
- 時間は
dateではなく/proc/uptimeで
「電力を見て省電力化する」なら、まず正しく測ることから。