常駐AIのRaspberry Pi 5、電気代は月50〜74円と見積もった。最初の式は21Wと出て使えなかった

21.4W。Raspberry Pi 5に負荷をかけて、最初に計算で出てきた消費電力です。
他の人が測った、同じPi 5(4GB・8GB版)の高負荷時の値は9.8Wでした。倍以上ずれています。計算式のどこかが間違っていると、この時点で分かりました。
月のAI費用が$314だった話は先週書きました。その金額に、AIエージェントを住まわせているこのRaspberry Pi 5の電気代は入っていません。入っていないだけで、ゼロではありません。いくらなのかを一度出しておくことにしました。
手元の機械と、測り方の前提
測ったのは、稼働43日のRaspberry Pi 5(16GB)です。ストレージはNVMeが466GBとmicroSDが115GB。USB機器は何もつないでいません。
この機械では、AIエージェントのゲートウェイ、コーディングエージェント数本、ブラウザが動いたままです。測定中は、AIが記事を書く自動ジョブも同じ機械で走っていました。測定開始時のロードアベレージは1.77。つまり「何もしていない状態」ではなく、「いつもの常駐状態」を測っています。
今回はワット計を使っていません。代わりに、Pi 5が自分で持っている電圧と電流のセンサーを使います。電源管理用のチップ(PMIC)が各所の電圧と電流を測っていて、vcgencmd pmic_read_adc で読めます。Raspberry Piの公式ドキュメントにも、このコマンドの記載があります。
vcgencmd pmic_read_adc の出力(そのまま)
vcgencmd pmic_read_adc
3V7_WL_SW_A current(0)=0.00097593A
3V3_SYS_A current(1)=0.14638950A
1V8_SYS_A current(2)=0.19616190A
DDR_VDD2_A current(3)=0.01659081A
DDR_VDDQ_A current(4)=0.00000000A
1V1_SYS_A current(5)=0.17566740A
0V8_SW_A current(6)=0.28594750A
VDD_CORE_A current(7)=0.63403000A
3V3_DAC_A current(17)=0.00024420A
3V3_ADC_A current(18)=0.00030525A
0V8_AON_A current(16)=0.00311355A
HDMI_A current(22)=0.01953600A
3V7_WL_SW_V volt(8)=3.71184000V
3V3_SYS_V volt(9)=3.30724900V
1V8_SYS_V volt(10)=1.81684800V
DDR_VDD2_V volt(11)=1.10402800V
DDR_VDDQ_V volt(12)=0.60586020V
1V1_SYS_V volt(13)=1.10549400V
0V8_SW_V volt(14)=0.80109810V
VDD_CORE_V volt(15)=0.89638500V
3V3_DAC_V volt(20)=3.31226800V
3V3_ADC_V volt(21)=3.30494200V
0V8_AON_V volt(19)=0.79999920V
HDMI_V volt(23)=5.10272000V
EXT5V_V volt(24)=5.09066000V
BATT_V volt(25)=0.00341880V
出力は12本の電流(A)と14本の電圧(V)です。頭の名前が同じものを、電流と電圧で1組にできます。たとえば VDD_CORE_A はCPUコアへ流れる電流で、VDD_CORE_V がその電圧です。このように電圧ごとに分かれた電源の線を「レール」と呼びます。
電流が12本あるのに、EXT5V_V(USB-Cから入ってくる5Vの電圧)には対応する電流がありません。ここが、後で効いてきます。
式を2つ並べて走らせた
電力は電圧×電流です。ただ、入口の電流が読めないので、式の作り方が2通り考えられました。
- 式A:読めた電流を全部足して、
EXT5V_V(約5.05V)を掛ける。入口の電圧で全部まとめて計算します。 - 式B:レールごとに電圧×電流を出し、最後に足す。
どちらが正しいのか、書く前には決められませんでした。同じスクリプトへ両方入れて、1秒間隔で60回測ります。
import subprocess, re, time
def read():
out = subprocess.run(["vcgencmd", "pmic_read_adc"],
capture_output=True, text=True).stdout
cur, vol = {}, {}
for line in out.splitlines():
m = re.match(r"\s*(\S+)_([AV]) (current|volt)\(\d+\)=([\d.]+)[AV]", line)
if m:
(cur if m.group(2) == "A" else vol)[m.group(1)] = float(m.group(4))
return cur, vol
cur, vol = read()
per_rail = sum(cur[k] * vol[k] for k in cur if k in vol) # 式B
all_5v = sum(cur.values()) * vol["EXT5V"] # 式A
実際のスクリプトは、これを60回まわして平均・最小・最大をJSONで出します。名前は sample.py です。まず、いつもの常駐状態で測りました。
python3 sample.py resident_asis 60
{"label": "resident_asis", "n": 60, "per_rail_W": 2.2885684223646763, "all5v_W": 9.225510736475456, "ext5v_V": 5.05025895, "sum_A": 1.8275344365, "min_per_rail": 1.68517792393521, "max_per_rail": 3.88705305681179}
式B(per_rail_W)は2.29W、式A(all5v_W)は9.23Wです。4倍も違います。常駐状態で9Wは、他の人の計測した負荷時の値9.8Wにほぼ並んでしまうので、すでに怪しい数字でした。
4コアを回すと、式Aが壊れた
次に負荷をかけます。4本の while True: pass を nice -n 19 で起動し、5秒待ってから55回測りました。
python3 burn.py
{"label": "burn4_60s", "n": 55, "per_rail_W": 4.452456292659316, "all5v_W": 21.394008458978664, "ext5v_V": 5.043930527272727, "sum_A": 4.241771681272727, "min_per_rail": 4.21677765346768, "max_per_rail": 5.4823155932877}
frequency(0)=2400037120
temp=55.4'C
throttled=0x0
式Aは21.39Wです。冒頭の数字はここから来ました。21Wは、公式が推奨する5V/5A電源(25W)の上限に迫る値です。ところが、CPUは2.4GHzのまま、温度は55.4℃、throttled=0x0(電圧低下などによる制限なし)。そこまで引いている様子は、クロックと温度のどちらにも出ていません。
原因は式Aの前提です。電流の多くは、1V前後の低い電圧のレールを流れています。たとえば VDD_CORE は約0.9Vです。それに5Vを掛けると、電力が5倍以上に膨らみます。入口の5Vから見れば、降圧された先の電流は、もっと小さい電流として流れ込んでいるはずです。電流を足すこと自体が、そもそも間違っていました。
式Bは4.45Wでした。常駐状態との差は約2.2Wで、4コアが全部回ったときの上乗せとして、桁は自然です。
負荷をやめて15秒おいてから、もう一度、常駐状態を60回測りました。
python3 sample.py resident_asis_after 60
{"label": "resident_asis_after", "n": 60, "per_rail_W": 2.223309613742779, "all5v_W": 8.927168650723049, "ext5v_V": 5.0513756333333335, "sum_A": 1.7678551693333333, "min_per_rail": 1.6938427978633899, "max_per_rail": 3.3426863193647796}
2.22Wです。1回目の2.29Wと、0.07W違いました。常駐中の揺れは、1.69Wから3.89Wまで見えています。平均すると約2.26Wです。
月額にすると
電気料金の単価には、家電公取協が示す目安の31円/kWh(税込)を使います。実際の契約単価ではありません。
比べる値は3つ置きました。式Bの2.26W、他の人が測った4GB・8GB版のアイドル値3.2〜3.3W、そして使えなかった式Aの約9.08Wです。
for label, w in [("PMIC合算(常駐2回平均)", (2.2886+2.2233)/2),
("5V換算の誤り", (9.2255+8.9272)/2),
("外部測定アイドル3.3W", 3.3),
("外部測定アイドル3.2W", 3.2)]:
kwh = w*24*30/1000
print(label, round(w,2), "W", round(kwh,2), "kWh/30d",
round(kwh*31,1), "円/30d", round(kwh*31*12), "円/年")
PMIC合算(常駐2回平均) 2.26 W 1.62 kWh/30d 50.4 円/30d 604 円/年
5V換算の誤り 9.08 W 6.53 kWh/30d 202.6 円/30d 2431 円/年
外部測定アイドル3.3W 3.3 W 2.38 kWh/30d 73.7 円/30d 884 円/年
外部測定アイドル3.2W 3.2 W 2.3 kWh/30d 71.4 円/30d 857 円/年
月にすると、式Bで50円、外部の値で71〜74円です。式Aを信じていたら、月203円と書くところでした。
まだ納得していない点
式Bの2.26Wは、おそらく低すぎます。理由は2つあります。
1つ目。PMICが測れるのは降圧した後のレールです。変換のロスや、PMICの外側で使われる電力は入っていません。Raspberry Pi公式フォーラムにも、pmic_read_adc の合計は実際の総消費電力と合わない、という指摘があります。
2つ目。NVMeやmicroSDがどのレールから電力を取っているのか、私は確認できていません。NVMeを積んだ機械は、積まない機械より電力を使うはずです。この2.26Wにそれが含まれているのかどうか、わかりません。
だから、月50〜74円は「見積もり」と書きます。下限が50円、上限が外部の値の74円。真ん中のどこかに本当の数字がある、という言い方が今の精一杯です。上限も、他人の別の個体の値を借りているだけです。
もう1点、負荷試験の相手は、私が書いた4本の空ループです。外部の9.8Wは stress-ng という負荷専用ツールの結果で、メモリや他の部品にも負荷をかけます。私の4.45Wと並べて「半分しか出ない」とは言えません。
次にやるなら、ACアダプタとコンセントの間にワット計を挟みます。それで下限か上限かが決まります。
電気代は、判断を変えない金額でした
見積もりのどこを取っても、年にして600〜900円です。
この数字で、Pi 5を常駐させる判断は変わりません。変わるとしたら、マシンを何台も並べたときです。10台にしても月500〜740円。ここまで来ても、ドル建てで月$314のAI費用と、桁が違います。
先週の記事の金額に電気代は入っていませんでしたが、入れても結論が変わらない大きさでした。ただし、測って初めて言えたことです。「常時稼働」と聞くと、もっと大きな金額に見えがちです。
出典
- Raspberry Pi Documentation「Raspberry Pi computer hardware」(
vcgencmd pmic_read_adcと電源の項): https://www.raspberrypi.com/documentation/computers/raspberry-pi.html - 家電公取協(公益社団法人)「よくある質問 Q&A」(目安単価31円/kWh、令和4年7月22日改定): https://www.eftc.or.jp/qa/
- Jeff Geerlingの2GB版Pi 5の記事(本人の計測表。4GB・8GB版のアイドル3.3W・3.2W、stress-ng時9.8W): https://www.jeffgeerling.com/blog/2024/new-2gb-pi-5-has-33-smaller-die-30-idle-power-savings/
- Raspberry Pi Forums「RPi 5 read supply currents?」(
pmic_read_adcの合計値は総消費電力と合わないとの指摘): https://forums.raspberrypi.com/viewtopic.php?t=359249
