Claude Code に「VRChat 重い」とぼやいたら、Process Lasso の ini まで自動でいじって最適化してくれた話
TL;DR
- VRChat が「いつもより重い」状態を、Claude Code(CLI)にシステムスキャンから設定変更まで一気通貫でやらせた
- マシンは Ryzen 9 9950X3D + RTX 5080 + Bigscreen Beyond。Process Lasso は既に入れていたが活かしきれていなかった
- Claude Code に管理者権限を渡し、
prolasso.ini(UTF-16LE)を直接編集して GamingMode 有効化・VR コア優先・バックグラウンド徹底抑制 を適用 - 並行して 9950X3D の V-Cache CCD トポロジを実測(論理0〜15が96MB L3=ゲーム向け、16〜31が32MB L3)、Windows レジストリで HAGS 有効化 / TdrDelay 延長 / VBS 無効化 まで実施
- 結果:VRChat が CPU 首位(13.8%)、抑制対象のバックグラウンドは 0.1〜0.3% まで激減、11時間半連続稼働でクラッシュ兆候ゼロ
- 学び:ボトルネック判定は GPU 3D エンジン使用率を最初に見る、XSOverlay の VRAM commit 巨大表示はカウンタのワナで実害なし など
背景:VRChat が「いつもより重い」
ある日 VRChat にログインしたら、いつもより明らかに重い。気になったので Claude Code に状況を投げた。
「VRチャットを今プレイしています 全体的にシステムがなんかいつもより重い気がしますスキャンしてください」
Claude Code は CLI から PowerShell や Get-Counter、nvidia-smi を呼べる。管理者権限で起動しておけば、レジストリ書き換えやサービス制御まで自動でできる。本記事はそのセッションの記録と、得られた知見をまとめたもの。
環境
| 項目 | 値 |
|---|---|
| CPU | AMD Ryzen 9 9950X3D(16C/32T、AM5、デュアル CCD) |
| GPU | NVIDIA GeForce RTX 5080 16GB(ドライバ 596.02) |
| RAM | DDR5-5600 32GB × 2 = 61.7GB |
| OS | Windows 11 Pro 25H2(Build 26200.8246) |
| HMD | Bigscreen Beyond(推奨 3562×3562/eye @ 75Hz) |
| 常駐 | Process Lasso 18.x(amd3dvcacheSvc も稼働中) |
主な用途は VRChat。フルトラ環境で、ベースステーション5台+トラッカー多数。
ステップ1:まず全系スキャン
Claude Code に「重さ」の正体を多角的に測らせる。Get-Counter、nvidia-smi、Get-Process、Windows イベントログをまとめて並列実行。
出てきた結果:
- CPU:VRChat は 8.5% / 32コア=余裕
- メモリ:51.6% 使用(29GB 空き)
- GPU:温度 67°C、スロットリングなし、利用率 81%、電力 185/360W、PCIe Gen4 x16
-
GPU 3D エンジン:
Get-Counter '\GPU Engine(*)\Utilization Percentage'で 合算 122.9%=飽和 -
vmmem 1.2GB、
amd3dvcacheSvc稼働中、稼働時間 11時間半
ここで Claude Code が出した最初の判定はこう。
「主因は GPU 3D エンジンの演算飽和。CPU・VRAM・温度・電力は全部余裕。描画する仕事量がフレーム予算を超えている」
体感の「重さ」は CPU やメモリ不足ではなく、GPU が描画しきれていないというのが見えた。
ステップ2:9950X3D の V-Cache CCD を実測する
ここからが Claude Code に Process Lasso をいじらせる準備。9950X3D は デュアル CCD 構成で、片側だけに 3D V-Cache(96MB L3)が積まれている非対称設計。ゲームは V-Cache 側に固定したい。
問題は「どの論理プロセッサが V-Cache 側なのか」を確定すること。AMD の公式情報やレビューでは「CCD0=V-Cache」と言われているが、自分のマシンで実測しないと不安。
Claude Code に Win32 API(GetLogicalProcessorInformation)を叩く PowerShell を生成させて実行。
$code = @'
using System;
using System.Runtime.InteropServices;
public static class LPI {
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool GetLogicalProcessorInformation(IntPtr Buffer, ref uint ReturnLength);
public static byte[] Get() {
uint len = 0;
GetLogicalProcessorInformation(IntPtr.Zero, ref len);
IntPtr buf = Marshal.AllocHGlobal((int)len);
try {
if(!GetLogicalProcessorInformation(buf, ref len)) throw new Exception();
byte[] data = new byte[len];
Marshal.Copy(buf, data, 0, (int)len);
return data;
} finally { Marshal.FreeHGlobal(buf); }
}
}
'@
Add-Type -TypeDefinition $code
$data = [LPI]::Get()
for($off=0; $off -lt $data.Length; $off += 32){
$mask = [BitConverter]::ToUInt64($data, $off)
$rel = [BitConverter]::ToInt32($data, $off+8)
if($rel -eq 2){ # RelationCache
$level = $data[$off+16]
$size = [BitConverter]::ToUInt32($data, $off+20)
if($level -eq 3){
$cores = @()
for($b=0; $b -lt 64; $b++){ if(($mask -shr $b) -band 1){ $cores += $b } }
"L3 = {0} MB -> logical CPUs: {1}" -f [math]::Round($size/1MB,0), ($cores -join ',')
}
}
}
結果:
L3 = 96 MB -> logical CPUs: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
L3 = 32 MB -> logical CPUs: 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
論理 0〜15 が V-Cache CCD、16〜31 が高クロック CCD と確定。これで Process Lasso の CPUSets 設定が「VRChat→V-Cache CCD、雑多→高クロック CCD」になっているかを根拠を持って評価できる。
確認したら既存設定は実は最初からこの方針で組まれていた:
CPUSets =
vrchat.exe,(0;2;4;6;8;10;12;14), # V-Cache CCD の偶数コア
c:\program files (x86)\steam\steamapps\common\steamvr\*.exe,(0-15), # V-Cache CCD 全体
vrcfacetracking.exe,(16-31),
baballonia.desktop.exe,(16-31),
vrcx.exe,(16-31),
discord.exe,(16-31),
chrome.exe,(16-31),
...
正しい。CPU アフィニティは触らないことにした。
ステップ3:Process Lasso の ini に決定的な見落としを発見
C:\ProgramData\ProcessLasso\config\prolasso.ini は UTF-16LE BOM 付き。Claude Code が中身を抽出してくれた。
[GamingMode] セクションを見てショック。
[GamingMode]
GamingModeEnabled = false # ← OFF!
GamingChangePowerPlan = true
TargetPowerPlan = 最大パフォーマンス オーバーレイ
GamingModeEngageForSteam = true
AutomaticGamingModeProcessPaths = bfv.exe,vrchat.exe
[ProcessDefaults]
DefaultPowerSchemes = vrserver.exe;bitsum highest performance
仕込みは全部入っているのにマスタースイッチが OFF。VRChat 起動を検知して電源プランを切り替える設定が用意されているのに、ゲーミングモード自体が無効になっていた。
実際 powercfg /getactivescheme を見たら「バランス」のまま。VR プレイ中なのに最適化が一切発火していなかった。
適用
Claude Code に「サービス停止→ ini 編集→サービス起動」を一括でやらせる。Process Lasso は稼働中に設定をメモリ保持して終了時に ini へ書き戻すので、稼働中に外から ini を書き換えても上書きされる。順序が大事。
$p = 'C:\ProgramData\ProcessLasso\config\prolasso.ini'
# 1. バックアップ
Copy-Item $p "$p.bak" -Force
# 2. GUI と セッションエージェントを止める
Get-Process ProcessLasso,bitsumsessionagent -EA SilentlyContinue | Stop-Process -Force
# 3. コアエンジン(サービス)停止
Stop-Service ProcessGovernor -Force
(Get-Service ProcessGovernor).WaitForStatus('Stopped','00:00:20')
Start-Sleep -Milliseconds 800
# 4. UTF-16 を保持したまま編集
$c = [System.IO.File]::ReadAllText($p, [System.Text.Encoding]::Unicode)
$c = $c.Replace('GamingModeEnabled=false', 'GamingModeEnabled=true')
$c = $c.Replace(
'DefaultPowerSchemes=vrserver.exe;bitsum highest performance',
'DefaultPowerSchemes=vrserver.exe;bitsum highest performance,vrchat.exe;bitsum highest performance'
)
[System.IO.File]::WriteAllText($p, $c, [System.Text.Encoding]::Unicode)
# 5. サービス起動 → GUI 復帰
Start-Service ProcessGovernor
Start-Process 'C:\Program Files\Process Lasso\ProcessLasso.exe'
ポイントは2つ。
-
UTF-16LE BOM 付きを維持するため
ReadAllText/WriteAllTextをEncoding.Unicodeで。普通のGet-Content/Set-Contentだと BOM や改行が変わって壊れることがある -
Process Lasso 稼働中の編集は無意味。サービスと GUI と
bitsumsessionagentを全部止めてから書き換える
検証
SteamVR を立ち上げ直してログを見ると:
22:49:55 vrserver.exe パワープラン アクティブ化 → Bitsum Highest Performance
22:49:55 vrserver.exe CPUセット (0-15) 割り当て
22:50:02 vrchat.exe パワープラン アクティブ化 → Bitsum Highest Performance
22:50:02 vrchat.exe 効率モードOff
22:50:02 vrchat.exe CPUセット (0;2;4;6;8;10;12;14) 割り当て
VR 起動で 自動で Bitsum Highest Performance に切替、V-Cache CCD へのコア割り当ても発火。powercfg /getactivescheme も「バランス」から Bitsum Highest Performance に切り替わった。GPU は P5 → P0(最大性能ステート)に上がった。
ステップ4:VR コア優先+バックグラウンド徹底抑制
ここからが「色々大胆に」フェーズ。Claude Code に現状のプロセス優先度を全件サンプリングさせた。
Get-Process | Sort-Object @{E={$_.PriorityClass};Descending=$true} | ...
驚いたのが、VRChat / vrcompositor / vrserver は 既に High 優先度で動いていたこと。SteamVR/VRChat が自分自身を昇格させている。Process Lasso で「Above Normal にする」と書こうとしたら、それは降格になる。
代わりに方針を「VR コアは触らない、バックグラウンドを徹底抑制する」に振り替えた。
[ProcessDefaults]
DefaultPriorities =
xsoverlay.exe,above normal,
alvr dashboard.exe,above normal,
chrome.exe,below normal,
msedgewebview2.exe,below normal, # ← 追加(33プロセスもあった!)
claude.exe,below normal, # ← 自分自身も降格
ollama.exe,idle, # ← VR中はLLM不要
vrcx.exe,below normal,
googledrivefs.exe,below normal
DefaultIOPriorities =
vrchat.exe,3, # ← I/O High(シェーダ/アセットロードのジッター低減)
vrcompositor.exe,3,
chrome.exe,1,
xsoverlay.exe,3,
msedgewebview2.exe,1,
ollama.exe,0
[ProcessAllowances]
EfficiencyMode = ...,
msedgewebview2.exe,1, # ← Windows の Eco モード
ollama.exe,1,
claude.exe,1,
googledrivefs.exe,1,
vrcx.exe,1,
everything.exe,1,
fdm.exe,1,
pfusshmain.exe,1
Win11 の "効率モード"(EcoQoS) はバックグラウンドを E コア相当の低電力レーンに押し込む仕組み。9950X3D には物理 E コアはないが、Process Lasso は EcoQoS をプロセスに適用できる。CPU 全コアを VR に譲る効果がある。
触らないと明言した部分
- 顔トラ系(VRCFaceTracking, Baballonia.Desktop)→ 低遅延が要るので抑制しない
- Standable(フルトラ)→ 同上
- DWM, svchost, explorer → システムコア
-
main× 5(正体不明の Python ツール)→ 触らない方針
ここは Claude Code が「過剰実装を避ける」判断を自分でしていた。プロセス名が不明なものまで抑制するとリスクなので、わかるものだけ。
効果
適用後の per-process CPU%(2秒サンプル、32 コア換算):
| Process | CPU% | 状態 |
|---|---|---|
| VRChat | 13.8 | CPU 首位 |
| claude | 1.7 + 0.3 | 抑制済 |
| vrserver | 1.6 | 通常 |
| googledrivefs | 1.2 | 抑制済 |
| vrcompositor | 0.7 | 通常 |
| chrome | 0.3 + 0.1 | 抑制済 |
| msedgewebview2 | 0.2 + 0.1 | 33→0.1〜0.2%まで激減 |
| vrcx | 0.1 + 0.1 | 抑制済 |
msedgewebview2 33 プロセスを Below Normal + EcoQoS に落とした効果がはっきり出ている。バックグラウンドが VR コアを邪魔しなくなった。
ステップ5:Windows レジストリの「安定化第2陣」
Process Lasso 系が落ち着いたところで、VR を一旦終了して Windows 側の最適化に着手。これらは要再起動なので VR 中はできない。
$gd = 'HKLM:\SYSTEM\CurrentControlSet\Control\GraphicsDrivers'
$dg = 'HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard'
$dgs = 'HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity'
$lsa = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa'
# 1. HAGS(Hardware GPU Scheduling)有効化
Set-ItemProperty $gd -Name HwSchMode -Value 2 -Type DWord
# 2. TDR Delay 延長:2秒 → 8秒
Set-ItemProperty $gd -Name TdrDelay -Value 8 -Type DWord
Set-ItemProperty $gd -Name TdrDdiDelay -Value 8 -Type DWord
# 3. VBS(Virtualization-Based Security)無効化
Set-ItemProperty $dg -Name EnableVirtualizationBasedSecurity -Value 0 -Type DWord
Set-ItemProperty $dgs -Name Enabled -Value 0 -Type DWord
Set-ItemProperty $lsa -Name LsaCfgFlags -Value 0 -Type DWord
& bcdedit /set hypervisorlaunchtype off
それぞれの意味:
- HAGS:GPU スケジューリングをハードウェアにオフロード。CPU オーバーヘッドとレイテンシが下がる
- TdrDelay 8秒:GPU が一時的に応答しないときの BSOD 余裕。VR の高負荷時に nvlddmkm 0x116 でカーネル落ちするのを延命
- VBS 無効化:常時数% の性能税が消える。ただし WSL2 / Docker Desktop / Hyper-V / Windows Sandbox が使えなくなるので、開発用途と相談
VBS は副作用が大きい変更なので、Claude Code は適用前に明示的に警告した上で実行した。バックアップ値も全部ログに残してある(戻すときは元値を逆適用すれば良い)。
ステップ6:ハマったポイントと誤認の訂正
ここからが技術記事として一番役に立つ部分かもしれない。「最初こう思ったけど違った」のリスト。
誤認1:「supersample 2.5倍が GPU 飽和の主因」← 大はずれ
steamvr.vrsettings に supersampleScaleCompositor: 2.5 を見つけて「これだ!」と思った。しかし実機で SteamVR の UI を確認したら 解像度は 100%。supersampleScaleCompositor はコンポジタ内部の別パラメータで、しかも allowSupersampleFiltering: false で一部無効化されていた。
ファイルだけ見て決めつけてはいけない。UI 実測が正。
誤認2:「XSOverlay の VRAM commit が 1TB 超!危ない!」← カウンタのワナ
XSOverlay の Dedicated GPU Memory が Get-Counter '\GPU Process Memory(*)\Dedicated Usage' で 1400GB→1715GB→2755GB と青天井に増えていく。物理 VRAM は 16GB なので「これは大変だ TDR の温床だ」と煽った。
しかし nvidia-smi の memory.used は 8GB前後で安定。1TB 超の表示は WDDM の予約コミットで、実 VRAM を食っていない。Dedicated Usage カウンタは同一プロセスの複数インスタンスを合算して非現実的な数字になる仕様。
→ commit 数字に過剰反応せず、nvidia-smi memory.used で判断する。これは後から VRAM 内訳を取って初めて気づいた。
誤認3:「重さの本命は GPU 3D 飽和」← 半分正解
GPU 3D エンジン使用率は確かに飽和していたが、根本原因はもう一段深かった。VRChat の output_log に内蔵 fps 統計が出ていて、それを見ると:
{"name": "fps", "mean": 73.6, "min": 6.17, "max": 175}
{"name": "cpu_frame_time", "max": 0.16055} // 160ms!
{"name": "avatar_kind_Custom", "mean": 2.8}
{"name": "avatar_perf_rating_VeryPoor", "mean": 2.79}
インスタンスは3人しかいないのに、見えるアバターのほぼ全員が Very Poor。fps min は瞬間6まで落ちている。さらにレジストリを見たら:
VRC_AVATAR_PERFORMANCE_RATING_MINIMUM_TO_DISPLAY = 5 ← Very Poorまで全表示
VRC_LIMIT_PARTICLE_SYSTEMS = 0 ← パーティクル制限OFF
つまり**「重 Very Poor アバターを全部フル描画する設定」**になっていた。これはレジストリを直接書き換えても VRChat が起動中に上書きするので、ゲーム内 UI で操作するしかない。Claude Code が代行できる範囲を超えていた。
学び
「重さ」調査の手順
- まず GPU 3D エンジン使用率(
Get-Counter '\GPU Engine(*)\Utilization Percentage')と nvidia-smi- それが飽和なら原因は描画量。次に VRChat の output_log で fps スパイク・アバター内訳
- CPU/メモリは多くの場合シロ
- XSOverlay や似たオーバーレイの VRAM 計測は実 VRAM(nvidia-smi)で判断、commit カウンタの数字は信用しない
ステップ7:安定性監視
VR の負荷が下がっても、長時間稼働でクラッシュする履歴はあった。これは Claude Code に /loop 30m で 30分ごとに状態を監視させた。
監視項目:
$bt = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
$up = (Get-Date) - $bt
"uptime $([int]$up.TotalHours)h$($up.Minutes)m"
$tdr = @(Get-WinEvent -FilterHashtable @{
LogName='System'; ProviderName='nvlddmkm'; StartTime=$bt
} -EA SilentlyContinue).Count
$whea = @(Get-WinEvent -FilterHashtable @{
LogName='System'; ProviderName='Microsoft-Windows-WHEA-Logger'; StartTime=$bt
} -EA SilentlyContinue).Count
"TDR=$tdr WHEA=$whea"
Get-ChildItem 'C:\Windows\Minidump\*.dmp' -EA SilentlyContinue
nvidia-smi --query-gpu=temperature.gpu,utilization.gpu,memory.used,power.draw --format=csv,noheader
結果、boot から11時間半で TDR・WHEA・新規 minidump すべてゼロ。Process Lasso GamingMode + Bitsum 電源プランで CPU/GPU のクロックが上がり切る状態を維持しつつ、TdrDelay 8秒の延命と HAGS で GPU スケジューラの余裕も取れている。
全体まとめ
最終的に適用したものを一覧で:
Process Lasso(prolasso.ini 直接編集)
-
GamingModeEnabled = true:VR 起動で電源プラン自動切替を発火 -
DefaultPowerSchemesにvrchat.exe;bitsum highest performanceを追加 - バックグラウンド抑制:
msedgewebview2、ollama、claude、vrcx、googledrivefs、everything、fdmを Below Normal + EcoQoS - VR コアの I/O 優先度を High:
vrchat.exe,3vrcompositor.exe,3 - CPU アフィニティ(既存設定が9950X3D の特性に既に合致していたので不変)
Windows レジストリ
- HAGS 有効化(
HwSchMode = 2) - TdrDelay / TdrDdiDelay = 8 秒
- VBS / HVCI / CredGuard / Hyper-V 起動を無効化
- システム復元ポイントを事前作成
結果
| 指標 | Before | After |
|---|---|---|
| 電源プラン(VR中) | バランス | Bitsum Highest Performance(自動切替) |
| GPU pstate(VR中) | P5(アイドル混在) | P0(常時最高性能) |
| VRChat の CPU 順位 | 8.5% | 13.8%(首位) |
msedgewebview2(33本)の CPU 合計 |
数%でばらつき | 0.1〜0.3% に圧縮 |
| 11時間半連続稼働での TDR/WHEA | (履歴上は出る) | 0件継続 |
Claude Code に最適化を任せて良かったこと
「自然言語で投げる→システムスキャン→根拠を出す→可逆な変更を確認しながら適用→効果を数値で検証→次の選択肢を提示」のループが会話のテンポでまわるのが効いた。
特に良かった点:
-
ボトルネック判定が早い。並列で
Get-Counter/nvidia-smi/ イベントログ / Process Lasso ログを引いて、CPU でなく GPU 3D 飽和が主因と数値で示してくれる -
UTF-16 ini や Win32 API のような「面倒な実装」を躊躇なくやる。BOM 維持の ReadAllText/WriteAllText、
GetLogicalProcessorInformationの P/Invoke を1分で書いてくれる -
可逆性とバックアップを勝手に確保する。
.bak/.bak2/.bak3を作る、復元ポイントを切る、バックアップ値を表示で残す - 危険な操作は止まる。VR 中の SteamVR 再起動や Process Lasso のサービス停止+ini 編集の順序など、「落とす」リスクがある操作は手順を組んでから実行
逆に注意した点:
- ファイルの数字だけを見て早合点しない。supersample 2.5 倍説や XSOverlay 1TB 説のように、UI 実測や別カウンタと突き合わせる
- 管理者権限がいる操作は管理者で起動し直す。Stop-Service や HKLM 書き換えは非管理者だと Access denied
- Process Lasso のような「稼働中に設定を上書きするツール」は停止→編集→起動の順を守る
おわりに
VRChat が重いという身近な悩みを、Claude Code に投げたら 9950X3D の V-Cache CCD トポロジ実測から Windows レジストリの第2陣まで一気通貫でやってくれた。Process Lasso は GUI でしか触ったことがなかったが、ini を直接いじってサービスをサイクルする運用に踏み込めたのは、自然言語で「これ、こうしたい」と言いながら相談できる相手がいたからだと思う。
同じワークロード(VRChat や SteamVR ヘビーユーザー)の方の参考になれば。
おまけ:実機の Process Lasso ini 関連抜粋
[GamingMode]
GamingModeEnabled = true ; ← 今回の最大の見落とし
GamingChangePowerPlan = true
TargetPowerPlan = 最大パフォーマンス オーバーレイ
AutomaticGamingModeProcessPaths = bfv.exe,vrchat.exe
DisableEnergySaverDuringGamingMode = true
[ProcessDefaults]
DefaultPowerSchemes = vrserver.exe;bitsum highest performance,vrchat.exe;bitsum highest performance
DefaultPriorities = xsoverlay.exe,above normal,
alvr dashboard.exe,above normal,
chrome.exe,below normal,
msedgewebview2.exe,below normal,
claude.exe,below normal,
ollama.exe,idle,
vrcx.exe,below normal,
googledrivefs.exe,below normal
DefaultIOPriorities = vrchat.exe,3,
vrcompositor.exe,3,
chrome.exe,1,
xsoverlay.exe,3,
msedgewebview2.exe,1,
ollama.exe,0
CPUSets = vrchat.exe,(0;2;4;6;8;10;12;14),
c:\program files (x86)\steam\steamapps\common\steamvr\*.exe,(0-15),
vrcfacetracking.exe,(16-31),
vrcx.exe,(16-31),
discord.exe,(16-31),
chrome.exe,(16-31)
ThreadPriorityBoosts = vrchat.exe;1
[ProcessAllowances]
EfficiencyMode = discord.exe,1,
steamwebhelper.exe,1,
oyasumivr.exe,1,
msedgewebview2.exe,1,
ollama.exe,1,
claude.exe,1,
googledrivefs.exe,1,
vrcx.exe,1,
everything.exe,1,
fdm.exe,1,
pfusshmain.exe,1
この記事は Claude Code で自動生成しました。