Newer
Older
SmTIAS-LightSim / docs / 06_TEST / TEST_04_シミュレーション速度最適化履歴.md

シミュレーション速度最適化履歴 (Performance Optimization History)

本ドキュメントは SmTIAS-LightSim のシミュレーション・可視化処理の 実行時間最適化 の試行を時系列で記録する.

目的:

  • 「どの仮説でどの最適化を入れ,実時間がどう変わったか」を 数値で残す.
  • 効かなかった試行も同等に記録し,同じ最適化を繰り返し試す事態を防ぐ.
  • 各試行の 学び を明示し,次に取り組むべきボトルネックを判断する根拠を蓄積する.

関連ドキュメント:

大前提 (Constraints)

項目値
ターゲット環境Windows 11 Pro 10.0.22631 / PowerShell 5.1
GPUIntel HD Graphics 520(NVIDIA 非搭載)
Mitsuba CUDA variant使用不可(CUDA 対応 GPU が無いため)
精度方針現精度(spp/max_depth)を維持したまま実行時間のみ短縮.サンプル数削減やサンプラ変更による「分散↓→ spp 削減」系の最適化は対象外.
数値同等性各最適化試行は luminance.npy(および bake 出力)の数値同等性を確認した上で適用する.

ベンチマーク条件 (Benchmark Conditions)

すべての試行は以下の固定条件で測定する(条件を変えた場合は当該試行内に明記).

標準ベンチマーク

項目値
標準シーンconfigs/scene_baseline.yaml(メイン構成.llvm_ad_rgb / spp=1024 / max_depth=8)
B1: sm-render コマンドuv run sm-render configs/scene_baseline.yaml --output output/_bench/luminance.npy
B2: sm-visualize (path bake) コマンドuv run sm-visualize configs/scene_baseline.yaml --bake-mode path --bake-samples 16 --bake-cache output/_bench/bake.npz --screenshot output/_bench/bake.png --no-show
計測方法Measure-Command { … } の TotalSeconds.warm-up 1 回を捨て,3 回測って中央値を採用.
環境計測中は他の重い処理を閉じる.電源プロファイル High performance 推奨.
出力先output/_bench/(gitignore 配下,数値のみドキュメントに転記)

計測コマンド(PowerShell スニペット)

# B1: sm-render
1..4 | ForEach-Object {
  $t = Measure-Command {
    uv run sm-render configs/scene_baseline.yaml `
      --output output/_bench/luminance.npy
  }
  "$_  $($t.TotalSeconds) s"
}

# B2: path bake
1..4 | ForEach-Object {
  Remove-Item output/_bench/bake.npz -ErrorAction SilentlyContinue
  $t = Measure-Command {
    uv run sm-visualize configs/scene_baseline.yaml `
      --bake-mode path --bake-samples 16 `
      --bake-cache output/_bench/bake.npz `
      --screenshot output/_bench/bake.png --no-show
  }
  "$_  $($t.TotalSeconds) s"
}

1 回目は warm-up(変動が大きい)として捨て,2〜4 回目の中央値を採用する.

数値同等性検証 (Equivalence Check)

各試行で出力に対し以下を確認する:

出力同等性基準
luminance.npy平均相対誤差 < 1e-6(決定論的最適化=同じビット列出力が理想),MC サンプラの初期化規約が変わる場合は 5σ 以内の統計同等性(同 spp で再計測して比較)
bake.npz(face_values)同上

俯瞰サマリ (Overall Progression)

時系列の主要計測値.速度比 = ベースライン時間 / 当該試行時間(大きいほど速い).

ID試行B1: sm-renderB1 速度比B2: path bakeB2 速度比数値同等性
Speed-0ベースライン(LLVM JIT 復元後)507.86 s1.0×55.97 s1.0×—

(試行を追加するごとに行を append)

イテレーション履歴 (Iteration Log)

イテレーションのテンプレート

各試行は以下の見出しで記述する:

  • 日付: YYYY-MM-DD
  • コミット: <short-hash>(試行が完了した時点のコミット)
  • 背景・問題意識: なぜこの最適化を考えたか
  • 仮説(技術的根拠): なぜ速くなると考えるか(JIT 経路・並列化機構等の物理的・実装的根拠)
  • 試した変更: コード/設定の差分(ファイル名・行レベルで具体的に)
  • 期待した効果: 何倍速くなることを期待したか
  • 計測コマンド: 実行したコマンド全文
  • 計測結果: 3 回計測の中央値(warm-up 除く.生データも参考に記載)
  • 数値同等性: luminance.npy / bake.npz の比較結果
  • 解釈: なぜ効いた/効かなかったか
  • 学び: 次の試行への含意
  • 次のアクション: 次にやること

Speed-0: ベースライン計測 (Baseline)

  • 日付: 2026-05-28
  • コミット: 4e93638(feature/baseline-calibration の最新.feature/perf-optimization から派生)
  • 背景・問題意識: 改善前の実時間を確定する.これ以降の試行はすべてこの値との比較で評価する.
  • 仮説(技術的根拠): なし(計測のみ).

計測前に判明した重大事項(環境破綻と復旧)

現象: 計測を開始しようとしたところ,sm-render が以下のエラーで即時クラッシュした.

jitc_llvm_init(): LLVM API initialization failed ..
ImportError: jit_init_thread_state(): the LLVM backend is inactive because the LLVM shared library
("LLVM-C.dll") could not be found! Set the DRJIT_LIBLLVM_PATH environment variable to specify its path.

feature/baseline-calibration(前ブランチ)でも同じエラー → コード変更に依存しない環境問題であることが確定.

調査結果:

項目状態
LLVM-C.dll の実在あり: C:\Program Files\LLVM\bin\LLVM-C.dll(過去にインストール済み)
DRJIT_LIBLLVM_PATH 環境変数未設定(User / Machine 両方とも)
PATH 内の LLVM bin未登録
sm-visualize の direct bake動く(baker.py が scalar_rgb を内部固定するため LLVM 不要)
sm-renderクラッシュ(scene_baseline.yaml の variant: llvm_ad_rgb が JIT 必須)

解釈: 過去のキャリブ作業時には何らかの方法で DRJIT_LIBLLVM_PATH が設定されていた(手動セットアップ/別シェル等)が,現在の Windows 環境では消えている.LLVM 自体は C:\Program Files\LLVM\bin\ に残っていたため,環境変数を再設定するだけで復旧可能と判明.

復旧手順:

# User scope に永続化(1 度だけ)
[Environment]::SetEnvironmentVariable(
  'DRJIT_LIBLLVM_PATH',
  'C:\Program Files\LLVM\bin\LLVM-C.dll',
  'User'
)

注意: 既に起動済みのプロセスには反映されない.新規 PowerShell を開いた時点から有効化.本セッションの計測では各コマンド先頭で $env:DRJIT_LIBLLVM_PATH = '...' を明示設定して回避.

復旧確認:

DRJIT_LIBLLVM_PATH: C:\Program Files\LLVM\bin\LLVM-C.dll
mi.variant(): llvm_ad_rgb
JIT activation: OK

計測結果

ベンチ環境: Windows 11 Pro 22631 / PowerShell 5.1 / Intel HD Graphics 520 / 電源プロファイル「バランス」(High performance への変更は実施せず,TEST_04 全試行で同条件).

B1: sm-render(configs/scene_baseline.yaml,llvm_ad_rgb,spp=1024,max_depth=8)

ラン時間 (s)
warm-up (run 0, 捨)524.09
run 1507.86
run 2502.32
run 3527.19
中央値507.86 s ≈ 8.46 分

範囲 502.32〜527.19 s(±2.4%),安定.

B2: path bake(configs/scene_baseline.yaml,--bake-mode path --bake-samples 16,scalar_rgb 固定)

ラン時間 (s)
warm-up (run 0, 捨)52.54
run 155.97
run 265.48
run 353.22
中央値55.97 s

範囲 53.22〜65.48 s(±10%),B1 より変動大.bake 自体が短時間で PyVista screenshot や I/O オーバーヘッドの寄与が相対的に大きいため.

出力ファイル ハッシュ・統計(数値同等性検証の基準値):

ファイルSHA256サイズ統計
output/_bench/luminance.npyD8B234BB…D4A17AF2,097,280 Bshape=(512,512), float64, mean=147.693, std=46.158, max=233.626, min=0.0
output/_bench/bake.npz0F28BC6F…BB3A4AA7222,702 Bper-face irradiance, 全メッシュ

JIT 状態診断(最終)

項目値
mi.set_variant("llvm_ad_rgb")成功
mi.variant() 戻り値llvm_ad_rgb
DRJIT_LIBLLVM_PATH 環境変数C:\Program Files\LLVM\bin\LLVM-C.dll(User scope 永続化済み)
jitc_llvm_init 警告出ない(child プロセスで $env:DRJIT_LIBLLVM_PATH を明示設定した場合)

解釈

  • B1 中央値 507.86 s ≈ 8.46 分 が現状の sm-render 1 回の所要時間.これは「LLVM JIT 復元後」の値.JIT 復元前は実行不能だったので「効果無限大」とは言えるが,過去キャリブ時の値と等しいと推定(同条件のはず).
  • B2 中央値 55.97 s は path bake samples=16 の値.samples=64 や 256 にすると線形に伸びると予想(baker.py のループ構造から).
  • B1 と B2 で 9.1× の差があるが,これは spp の差(1024 vs 16 per-face MC)と評価対象規模(512² 画像 vs 全メッシュ per-face)の違いによる.直接比較は意味なし.それぞれ独立に最適化対象.

学び

  1. 環境変数依存の脆弱性が露呈: DRJIT_LIBLLVM_PATH 未設定で sm-render が即死する.docs/02_ENV か README に明記すべき.Speed-1 の方向性に影響.
  2. B1 を 3× 以上速くするには JIT を本物の wavefront 化(バッチ評価)が必要: 既に llvm_ad_rgb 経路に乗っている以上,「JIT 有効化」自体は完了している.純粋な JIT 経路有効化だけでこれ以上速くなる伸びしろは少ない可能性(要検証).
  3. B2 の path bake は per-face Python ループが支配的: samples=16 で 56 秒は十分速いが,samples を増やすと急激に伸びる.Speed-2(wavefront 化)の効果は samples 数に比例して大きくなる.

次のアクション

Speed-1 の方向性を 再定義:

  • 当初想定: 「LLVM JIT を有効化する → 自動的に数倍速くなる」
    → 既に LLVM JIT に乗っていることが判明したため,純粋な「JIT 有効化」だけでは追加の高速化は得られない可能性大.
  • 新方向: 「環境変数未設定でも自動 fallback する仕組み」+「JIT 経路で確実に走っていることをログで明示」 を Speed-1 として実装.これは速度自体は変えないが,再発防止・診断容易化の意味で価値あり.
  • 本命の高速化レバーは Speed-2(path bake wavefront 化)に移る.B2 を 10× 以上速くする道が残る.B1 は Mitsuba 内部の最適化が既に効いているので,追加の打ち手は限定的.

Speed-1: LLVM JIT 自動検出と診断ログ強化 (Robust JIT Activation)

方向修正: Speed-0 の調査で「LLVM JIT は復元後ベースラインに既に乗っている」ことが判明したため,本イテレーションは「JIT 有効化による高速化」ではなく「環境破綻の再発防止+診断容易化」に再定義する.純粋な実行時間短縮ではなく,今後の試行を安全に進めるための土台整備.

  • 日付: 未実施
  • コミット: 未実施
  • 背景・問題意識: Speed-0 計測前に判明したとおり,DRJIT_LIBLLVM_PATH 未設定だと sm-render が即死する.現在は User scope に永続化したが,新規 PC・別ユーザー・CI 環境で同じ問題が再発する.また「現在 JIT 経路に乗っているか」が見えにくく,scalar fallback で密かに遅くなっているケースを取り逃がすリスクがある.
  • 仮説(技術的根拠):
    • (a) 自動検出: C:\Program Files\LLVM\bin\LLVM-C.dll 等の標準パスを mitsuba.set_variant 前に Python 側で探索し,見つかれば os.environ['DRJIT_LIBLLVM_PATH'] をプロセス内で設定する.これにより環境変数未設定でも JIT が起動する.
    • (b) 診断ログ: mi.set_variant 成功時に「実際の variant」と「JIT backend の稼働状態」をログ出力.scalar fallback 時は明示的に警告する.
  • 試した変更: 未実施(実装予定):
    • src/sm_tias_lightsim/render/runner.py: variant 設定前に LLVM-C.dll 自動探索ロジックを追加.候補パス: 環境変数 DRJIT_LIBLLVM_PATH → C:\Program Files\LLVM\bin\LLVM-C.dll → C:\Program Files (x86)\LLVM\bin\LLVM-C.dll → LLVM_DIR/bin/LLVM-C.dll 等.発見時に os.environ 更新.
    • src/sm_tias_lightsim/visualize/baker.py: 同等のロジック(path bake は scalar_rgb 固定だが,将来 wavefront 化で LLVM 経路に乗るため統一).
    • docs/02_ENV/ENV_02_環境構築手順.md: LLVM のインストール手順と DRJIT_LIBLLVM_PATH 設定を明記.
    • テスト: LLVM-C.dll の探索ロジックを単体テスト(モックパスで Test-Path 相当を確認).
  • 期待した効果:
    • B1 / B2 の 計測値は不変(既に JIT 経路に乗っているため).
    • 再現性向上:環境変数未設定の新環境でも自動復旧.
    • 診断容易化:JIT 経路で走っていることがログから確認できる.
  • 計測コマンド: ベンチマーク条件参照(Speed-0 と同じ条件)
  • 計測結果: 未実施
  • 数値同等性: 未確認(luminance.npy のハッシュが Speed-0 と一致すること)
  • 解釈: 未実施
  • 学び: 未実施
  • 次のアクション: 未定

Speed-2: path bake wavefront 化 (Wavefront Bake)

  • 日付: 未実施
  • コミット: 未実施
  • 背景・問題意識: src/sm_tias_lightsim/visualize/baker.py の path bake は per-face で hemisphere モンテカルロ積分を回しており,scalar_rgb variant 固定.現状で「高 samples が非現実的」と CLAUDE.md にも明記されているように,最大のボトルネックの 1 つ.
  • 仮説(技術的根拠): per-face ループを Vector3f バッチに置換し,llvm_ad_rgb(JIT 有効)で 1 回のベクトル化レイ評価に変換すれば,10〜100× の高速化が見込める.精度は不変(同じ式を別の評価戦略で解くだけ).
  • 試した変更: 未実施
  • 期待した効果: B2 (path bake) で 10× 以上.B1 (sm-render) には影響なし.
  • 計測コマンド: ベンチマーク条件参照
  • 計測結果: 未実施
  • 数値同等性: 未確認(bake.npz の face_values が ±5σ 以内)
  • 解釈: 未実施
  • 学び: 未実施
  • 次のアクション: 未定

終了条件 (Exit Criteria)

以下のいずれかに到達したらこのドキュメントの初版(Speed-0〜Speed-2)を完了とする.

  • B1 (sm-render) が 3× 以上速くなる,もしくは「JIT は既に走っており LLVM 経路に乗っている」ことが確認できる.
  • B2 (path bake) が 10× 以上速くなる,もしくは「wavefront 化に必要な前提(per-ray の独立性等)が破れているため不可」と判明する.
  • 数値同等性が破れた最適化は不採用とする.

それ以降の最適化(denoiser・サンプラ・クラウド GPU 等)は Speed-3 以降で別途検討する.