バッテリーを外したIntel Mac(2017)の1.5GHz縛りをVoltageShiftで解除したメモ
このメモ書きは、膨張したバッテリーをBMSごと取り外したIntel Macで、AI歌声合成ソフトのフリーズ処理が極端に遅くなった件の記録だ。原因の特定から、遠回りを経て実用レベルのクロック解除にたどり着くまでをまとめている。
環境
| 項目 | 内容 |
|---|---|
| 機種 | 2017年 13インチ Intel MacBook Pro(Touch Barなし) |
| CPU | Kaby Lake世代 Core i5 2コア4スレッド 定格2.3GHz 最大3.6GHz |
| メモリ | 16GB |
| 電源 | 純正61W USB-Cアダプタのみ(バッテリー未接続) |
| DAW | Mac標準の無料DAW |
| 用途 | AI歌声合成ソフト(AUプラグイン版)+標準ボイスライブラリ |
| 使用ツール | VoltageShift 1.25(MSR読み書き用のオープンソースkext) |
経緯
以前はリアルタイム再生できていた歌声合成トラックが、ある時期からトラックのフリーズをかけないとまともに再生できなくなっている。同時期にバッテリーが膨張し、BMS(Battery Management System)ごと抜き取った状態でAC駆動のみで運用していた。
フリーズ:DAWの機能で、重いプラグインの出力を一時的にオーディオとして書き出し、再生時の計算を省く仕組みだ。編集時は解除が必要になる。
BMS:Battery Management System。バッテリーの電圧や残量を管理し、Mac側のSMCと通信する基板だ。音ゲーのアレではない。
原因は バッテリー未接続を検知したmacOSとSMCが、CPUを1.5GHzに自主規制していたこと だった。
バッテリーはピーク時の電力をアダプタに上乗せする緩衝材の役割も持っている。これがないと重い瞬間に電力不足で電源が落ちる恐れがあるため、Macは「アダプタだけで確実に足りる速度」まで絞る設計になっている。コンセント直結なら安定するという直感とは逆の挙動だ。
ブレーキの正体
計測で判明したブレーキは2段構えだった。
| MSR | 名称 | 読み取り値 | 意味 |
|---|---|---|---|
| 0x1FC | POWER_CTL | 0x24005F | bit0=1でBD PROCHOT有効 |
| 0x64F | PERF_LIMIT_REASONS | 全bit 0 | 熱や電力によるハード側の制限はなし |
| 0x771 | HWP_CAPABILITIES | 最高36 定格23 効率13 最低1 | 単位は100MHz |
| 0x774 | HWP_REQUEST | 0x800F0F04 | 最大15(1.5GHz)が設定されている |
0x774の8bitずつの並びは下表になる。
| 位置(右から) | 意味 | 元の値 | 変更後 |
|---|---|---|---|
| 1番目 | 最低速度 | 4(0.4GHz) | 4 |
| 2番目 | 最高速度 | 15(1.5GHz) | 23(2.3GHz)または28(2.8GHz) |
| 3番目 | 希望速度 | 15 | 0(CPUにおまかせ) |
| 4番目 | 省電力バランス(EPP) | 128 | 128 |
MSR:Model Specific Register。CPU内部の設定スイッチ群だ。書き込みは揮発性で、電源を切れば必ず初期値に戻る。ファームウェアやディスクは一切書き換わらない。
HWP:Hardware P-states。OSが上限と下限を指示し、その範囲でCPU自身が周波数を選ぶ仕組みだ。
電力上限(PL1 100W PL2 125W)や温度(50度前後)には余裕があり、ハードの健康状態とは無関係なOS側の縛り だと確定している。
解決までの道のり
遠回りした内容
| 試したこと | 結果 | 原因 |
|---|---|---|
| DAWのI/Oバッファサイズ変更 | 不可 | 上位版DAWの機能で、無料版には存在しない |
| BD PROCHOTのみ解除 | 1.5GHzのまま | XCPMによるHWP上限が別に残っていた |
| 電力上限を疑う | 無関係 | PL1/PL2は100W/125Wで十分高い |
| 0x774を1回だけ書き換え | 秒で元に戻る | macOSが定期的に上書きしている |
| 4秒間隔のループ | サクサクと重いを繰り返す | 書き戻しの方が速い |
| 0.3秒間隔のループ | 改善が頭打ち | voltageshiftが毎回kextを読み込み外すため1回1.26秒かかる |
| ループ2本を並列実行 | やや改善後にkextが詰まる | 同時ロードで衝突し、全readが0、IO Serviceに接続不可になり再起動が必要になった |
| 歌声合成のフリーズ中に計測 | 1.5GHz固定 | 2コアが埋まり、書き込みが暇なコアにしか当たらない |
| Windows用CPU制限ツール | 対象外 | Windows専用で、上限を下げる方向のツールだ |
| OSからバッテリーありと偽装 | 不可 | 判定はSMCとBMSの専用線通信で行われ、OSから介入できない |
最大の遠回りは、ツールのREADMEを読まずにループを組んだこと だ。loadkext の存在を最初から把握していれば、1.3秒の壁とkext詰まりによる再起動は発生していない。
XCPM:macOSカーネルに組み込まれたIntel CPU用電源管理だ。機種ごとの周波数テーブルを持ち、状態に応じてHWPの指示を出し直している。テーブル自体の書き換えは封印されたシステム領域の改変になり、起動不能のリスクがあるため今回は対象外にしている。
解決方法
1. SIPの無効化
起動直後にCommand+Rを押し続けて復旧モードへ入り、メニューバーのユーティリティからターミナルを開く。画面中央の復元や再インストールの項目には触れない。
csrutil disable
reboot
通常起動後の確認。
csrutil status
# System Integrity Protection status: disabled.
2. VoltageShiftの取得
GitHub上にリリースが登録されておらず、リポジトリ直下にzipが置かれている形式だ。APIで中身を確認してから取得している。
curl -s https://api.github.com/repos/<作者>/VoltageShift/contents/ | grep '"name"'
mkdir -p ~/Downloads/VoltageShift
cd ~/Downloads/VoltageShift
curl -L -o voltageshift_1.25.zip https://github.com/<作者>/VoltageShift/raw/HEAD/voltageshift_1.25.zip
file voltageshift_1.25.zip # Zip archive data なら成功
unzip voltageshift_1.25.zip
sudo chown -R root:wheel VoltageShift.kext
chmod +x voltageshift
grep が何も出力しない場合は該当なしの意味だ。Linuxと同じく無言が成功とは限らない。releases/latest が404を返すのはリリース未登録のためだ。
3. kextの承認
初回の read 実行で「not approved to load」エラーが出る。その直後にシステム環境設定のセキュリティとプライバシーを開き、ロックを解除して開発元の「許可」を押し、再起動が必要になる。ブロック表示は30分程度で消えるため、エラー直後に操作している。
4. 現状の確認
sudo ./voltageshift read 0x1FC # PROCHOT
sudo ./voltageshift read 0x774 # HWP上限
sudo ./voltageshift read 0x771 # 段階表
sudo ./voltageshift info # 電力上限 温度 電圧
出力は2進数8バイトで表示される。PROCHOTの解除は末尾が奇数なら1引いた値を書き込む形になる。
sudo ./voltageshift write 0x1FC 0x24005E
5. kextの常駐化
loadkext で読み込みっぱなしにすると、書き込み1回が1.26秒から0.068秒まで短縮される。
sudo ./voltageshift loadkext
time sudo ./voltageshift write 0x774 0x80001704
# real 0m0.068s
| 方式 | 1回あたり | 主な待ち |
|---|---|---|
| 通常実行 | 1.261秒 | 毎回のkextロードとアンロード |
| loadkext常駐 | 0.068秒 | ほぼなし |
6. 常駐ループスクリプト
2.3GHz版の boost.sh。二重起動防止ロック、終了時のkext解除、回転表示を含んでいる。
#!/bin/bash
cd "$(dirname "$0")"
LOCK=/tmp/boost.lock
if ! mkdir "$LOCK" 2>/dev/null; then
echo "もう動いてるぞ。2本目は起動しない"
exit 1
fi
cleanup() {
./voltageshift unloadkext > /dev/null 2>&1
rmdir "$LOCK"
echo
echo "止めた(拡張も外した)"
exit
}
trap cleanup INT TERM
./voltageshift loadkext > /dev/null
./voltageshift write 0x1FC 0x24005E > /dev/null
s='|/-\'
i=0
while true; do
./voltageshift write 0x774 0x80001704 > /dev/null
printf "\rboost中 %s (止めるときは Control+C) " "${s:i++%4:1}"
sleep 0.05
done
2.8GHz版の boost_high.sh は書き込み値と表示のみ異なる。ロックファイルを共有しているため、2本の同時起動は弾かれる。
./voltageshift write 0x774 0x80001C04 > /dev/null
printf "\rboost_high (2.8GHz) %s (止めるときは Control+C) " "${s:i++%4:1}"
起動と停止。
cd ~/Downloads/VoltageShift
sudo ./boost.sh # 2.3GHz
sudo ./boost_high.sh # 2.8GHz
# 停止は Control+C
前回の停止が異常終了でロックが残った場合の削除。
sudo rmdir /tmp/boost.lock
ヒアドキュメント cat > boost.sh << 'EOF' から EOF までの間が、そのままファイルの中身として書き出される。chmod +x で実行権限を付与している。voltageshiftはroot権限が必要なため、sudo なしの bash boost.sh では動作しない。
7. 効果の確認
voltageshift infoの周波数表示は暇な瞬間を拾いやすく、当てにならない。確認には標準のpowermetricsを使っている。
sudo powermetrics --samplers cpu_power -i 500 | grep --line-buffered -i "CPU Average frequency"
負荷テスト用の一時コマンド。最後の killall yes を忘れると全開のまま回り続ける。
for i in 1 2 3 4; do yes > /dev/null & done
sleep 5
sudo powermetrics --samplers cpu_power -i 1000 -n 1 | grep -i "freq"
killall yes
計測結果
| 状態 | 負荷時の周波数 | 体感 |
|---|---|---|
| 対策なし | 1500MHz固定 | 文字入力にも遅延 |
| PROCHOT解除のみ | 1500MHz固定 | 変化なし |
| 通常実行ループ(1周約1.6秒) | 2300と1500を数秒単位で往復 | サクサクとカクつきの繰り返し |
| 同上で歌声合成フリーズ | 1500MHz固定 | 改善なし |
| loadkext常駐ループ 2.3GHz | 1900〜2300MHz | フリーズ処理が実用速度 |
| loadkext常駐ループ 2.8GHz | 2100〜2800MHz | ゲームも入力も軽快 |
通常実行ループ時の波形は、1500から1540、1670、1960、2300と階段状に戻る形になっていた。論理4コアの平均値で、voltageshiftの書き込みが1回につき実行中の1コアにしか効かないことを示している。
GPU(内蔵Iris Plus 640)は実測で約880MHz(最大約1000MHz)まで回っており、ほぼ制限を受けていない。
余談として、「今はコア数が重要で周波数は昔の話」という説は、世代間でCPUを比較する場面の話だ。同じCPU内で周波数を1.5GHzから2.8GHzに戻すと、1コアあたりの処理速度は約1.9倍になる。ゲームや歌声合成のように1〜2コアに処理が集中するソフトでは、体感差がそのまま出る。
注意点
-
SIPは無効のまま になっている。バッテリー交換後は復旧モードで
csrutil enableが必要だ - kext常駐中は、他のプログラムがroot権限なしでMSRを操作できる状態になる(作者のREADMEに警告あり)
- ブレーキ解除中は重い瞬間に電源が落ちる危険がある。作業ファイルはこまめに保存が前提だ
- 再起動で全設定がリセットされる。起動ごとに
sudo ./boost.shの実行が必要になる - 本質的な解決はバッテリー交換だ。互換バッテリー(A1713相当)にもBMSが搭載されており、SMCと正常に通信する。PSEマーク付きで保証のある製品が前提になる
起動不能が心配な場合の逃げ道として、Shiftを押しながらのセーフモード起動と、Command+Rの復旧モードがある。今回の手順は起動に関わる領域を一切書き換えておらず、自動起動の設定(buildlaunchd)も使っていない。
まとめ
| 論点 | 結論 |
|---|---|
| 重くなった原因 | バッテリー未接続を検知したSMCとmacOSがCPUを1.5GHzに制限していた |
| ブレーキの構成 | BD PROCHOT(0x1FC)とXCPMによるHWP上限(0x774)の2段 |
| PROCHOT解除の効果 | 単独では効果なし |
| 0x774の書き換え | macOSが即座に書き戻すため、常時書き直しが必要 |
| 通常実行ループの限界 | kextの毎回ロードで1回1.26秒かかり、綱引きに負ける |
| 並列実行 | kextの取り合いで詰まり、再起動が必要になる |
| 突破口 | loadkextで常駐させ、0.05秒間隔で連打 |
| 達成値 | 2.3GHz版で安定、2.8GHz版も電源落ちなく動作 |
| 残るリスク | SIP無効、kext常駐中の権限、電源落ち |
| 本命の解決策 | バッテリー交換 |
あとがき
歌声合成のウィスパー調整の相談から始まったやり取りが、気づけばCPUのレジスタとの綱引きになっている。「数秒ごとに書けばいい」という素朴な発想が出発点になり、「コアを選べないのか」という疑問からREADMEを読み直して loadkext に行き着いた。道具の説明書は組む前に読むべきだという教訓が一番大きい。バッテリー交換までのつなぎとしては十分な速度が出ており、交換後はSIPを戻して今回のスクリプト群は役目を終えることになる。