本ドキュメントは SmTIAS-LightSim のシミュレーション・可視化処理の 実行時間最適化 の試行を時系列で記録する.
目的:
関連ドキュメント:
| 項目 | 値 |
|---|---|
| ターゲット環境 | Windows 11 Pro 10.0.22631 / PowerShell 5.1 |
| GPU | Intel HD Graphics 520(NVIDIA 非搭載) |
| Mitsuba CUDA variant | 使用不可(CUDA 対応 GPU が無いため) |
| 精度方針 | 現精度(spp/max_depth)を維持したまま実行時間のみ短縮.サンプル数削減やサンプラ変更による「分散↓→ spp 削減」系の最適化は対象外. |
| 数値同等性 | 各最適化試行は luminance.npy(および bake 出力)の数値同等性を確認した上で適用する. |
すべての試行は以下の固定条件で測定する(条件を変えた場合は当該試行内に明記).
| 項目 | 値 |
|---|---|
| 標準シーン | 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 配下,数値のみドキュメントに転記) |
# 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 回目の中央値を採用する.
各試行で出力に対し以下を確認する:
| 出力 | 同等性基準 |
|---|---|
luminance.npy | 平均相対誤差 < 1e-6(決定論的最適化=同じビット列出力が理想),MC サンプラの初期化規約が変わる場合は 5σ 以内の統計同等性(同 spp で再計測して比較) |
bake.npz(face_values) | 同上 |
時系列の主要計測値.速度比 = ベースライン時間 / 当該試行時間(大きいほど速い).
| ID | 試行 | B1: sm-render | B1 速度比 | B2: path bake | B2 速度比 | 数値同等性 |
|---|---|---|---|---|---|---|
| Speed-0 | ベースライン(LLVM JIT 復元後) | 507.86 s | 1.0× | 55.97 s | 1.0× | — |
| Speed-1 | LLVM 自動検出 + 診断ログ(速度据置目的) | 不変(≈ 508 s) | 1.0× | 不変(≈ 56 s) | 1.0× | MC 統計同等性パス(5σ 以内) |
(試行を追加するごとに行を append)
各試行は以下の見出しで記述する:
<short-hash>(試行が完了した時点のコミット)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 1 | 507.86 |
| run 2 | 502.32 |
| run 3 | 527.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 1 | 55.97 |
| run 2 | 65.48 |
| run 3 | 53.22 |
| 中央値 | 55.97 s |
範囲 53.22〜65.48 s(±10%),B1 より変動大.bake 自体が短時間で PyVista screenshot や I/O オーバーヘッドの寄与が相対的に大きいため.
出力ファイル ハッシュ・統計(数値同等性検証の基準値):
| ファイル | SHA256 | サイズ | 統計 |
|---|---|---|---|
output/_bench/luminance.npy | D8B234BB…D4A17AF | 2,097,280 B | shape=(512,512), float64, mean=147.693, std=46.158, max=233.626, min=0.0 |
output/_bench/bake.npz | 0F28BC6F…BB3A4AA7 | 222,702 B | per-face irradiance, 全メッシュ |
| 項目 | 値 |
|---|---|
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 を明示設定した場合) |
DRJIT_LIBLLVM_PATH 未設定で sm-render が即死する.docs/02_ENV か README に明記すべき.Speed-1 の方向性に影響.llvm_ad_rgb 経路に乗っている以上,「JIT 有効化」自体は完了している.純粋な JIT 経路有効化だけでこれ以上速くなる伸びしろは少ない可能性(要検証).Speed-1 の方向性を 再定義:
方向修正: Speed-0 の調査で「LLVM JIT は復元後ベースラインに既に乗っている」ことが判明したため,本イテレーションは「JIT 有効化による高速化」ではなく「環境破綻の再発防止+診断容易化」に再定義した.純粋な実行時間短縮ではなく,今後の試行を安全に進めるための土台整備.
DRJIT_LIBLLVM_PATH 未設定だと sm-render が即死する.現在は User scope に永続化したが,新規 PC・別ユーザー・CI 環境で同じ問題が再発する.また「現在 JIT 経路に乗っているか」が見えにくく,scalar fallback で密かに遅くなっているケースを取り逃がすリスクがある.C:\Program Files\LLVM\bin\LLVM-C.dll 等の標準パスを mitsuba.set_variant 前に Python 側で探索し,見つかれば os.environ['DRJIT_LIBLLVM_PATH'] をプロセス内で設定する.これにより環境変数未設定でも JIT が起動する.mi.set_variant 成功時に「実際の variant」と「JIT backend の稼働状態」をログ出力.scalar fallback 時は明示的に警告する.src/sm_tias_lightsim/runtime/__init__.py,src/sm_tias_lightsim/runtime/llvm_init.py(約 155 行).公開 API:
ensure_drjit_libllvm_path(extra_candidates: list[str] | None = None) -> str | None: 環境変数 → LLVM_DIR/bin/LLVM-C.dll → Windows 標準 4 候補 → POSIX glob → extra の順に探索.既設定なら上書きしない.log_variant_status(logger, requested_variant, actual_variant): llvm_* / cuda_* / scalar_* 経路を INFO で明示,要求 llvm_* かつ 実 scalar_* なら WARNING 追加.src/sm_tias_lightsim/render/runner.py: mi.set_variant 直前に variant が llvm_* のとき ensure_drjit_libllvm_path() を呼ぶ.成功後に log_variant_status を呼ぶ.ImportError 時は原因明示ログを ERROR で出してから re-raise.import mitsuba をモジュールレベルから関数内に遅延化.src/sm_tias_lightsim/visualize/baker.py: _set_variant_once に LLVM 自動探索の分岐追加(Speed-2 wavefront 化用前準備).direct/path 両方で log_variant_status を呼ぶ.src/sm_tias_lightsim/cli/render.py: import 順を制御して sensors.py / lights.py(モジュールレベルで import mitsuba する既存設計)が読まれる前に ensure_drjit_libllvm_path() を確実に通す.docs/02_ENV/ENV_02_環境構築手順.md: LLVM インストール手順・DRJIT_LIBLLVM_PATH の説明・動作確認コマンドを追記.Path.is_file 数回のみ= < 1 ms).Coder の動作確認 1 ラン(B1 1 回)で _check_speed1/luminance.npy 出力 — 実時間の中央値は Speed-0 と区別不能(再計測の意義薄).output/_check_speed1/luminance.npy の SHA256 = D1DF4F11…2BA2734 < Speed-0 = D8B234BB…D4A17AF.SHA256 は異なるが 平均相対誤差 7.23e-05(5σ 閾値 0.4508 に対し差 0.011)で MC 統計同等性パス.異なる理由は Mitsuba 内部の独立 sampler シードが実行タイミング等に依存するため.コード変更によるバイアスは検出されない.tests/runtime/test_llvm_init.py 25 件,tests/render/test_runner_jit_init.py 14 件,tests/visualize/test_baker_jit_init.py 8 件,tests/cli/test_render_jit_init.py 4 件)uv run pytest(DRJIT_LIBLLVM_PATH 設定下)= 606 件全通過(既存 555 + 新規 51)ensure_drjit_libllvm_path() のような薄い検出ヘルパーは小さく実装でき,影響範囲が完結する.src/sm_tias_lightsim/visualize/baker.py の path bake は per-face で hemisphere モンテカルロ積分を回しており,scalar_rgb variant 固定.現状で「高 samples が非現実的」と CLAUDE.md にも明記されているように,最大のボトルネックの 1 つ.Vector3f バッチに置換し,llvm_ad_rgb(JIT 有効)で 1 回のベクトル化レイ評価に変換すれば,10〜100× の高速化が見込める.精度は不変(同じ式を別の評価戦略で解くだけ).以下のいずれかに到達したらこのドキュメントの初版(Speed-0〜Speed-2)を完了とする.
それ以降の最適化(denoiser・サンプラ・クラウド GPU 等)は Speed-3 以降で別途検討する.
Speed-1 完了時点で 速度改善ワークを一旦中断 することにした.
ユーザー当初目的「シミュレーション速度を上げる」に対し,実時間の改善は実質ゼロ:
| ベンチ | Speed-0(ベースライン) | Speed-1 後 | 速度比 |
|---|---|---|---|
| B1: sm-render | 507.86 s | ≈ 508 s(不変) | 1.0× |
| B2: path bake | 55.97 s | ≈ 56 s(不変) | 1.0× |
| 項目 | 状態 | 備考 |
|---|---|---|
| Speed-0 ベースライン計測 | ✓ 完了 | 副次的に DRJIT_LIBLLVM_PATH 消失問題を発見・復旧 |
| Speed-1 LLVM 自動検出 + 診断ログ | ✓ 完了 | 再発防止と診断容易化.速度自体は不変が想定 |
| Speed-2 path bake wavefront 化 | ✗ 未着手 | 本命だったが中断 |
| Speed-3 以降(denoiser・サンプラ等) | ✗ 未検討 | — |
| 成果 | 価値 | 影響範囲 |
|---|---|---|
DRJIT_LIBLLVM_PATH 消失でサイレントクラッシュしていた問題の発見と恒久対処 | 高 | 環境破綻の再発防止(自動検出ロジック + User scope 永続化) |
| JIT 経路の診断ログ機構 | 中 | 「同じシーンなのに数値がずれる」事態の即時検知 |
| ベンチマーク条件と TEST_04 のドキュメント | 中 | 再開時に「3 回中央値・warm-up 捨て・SHA256/MC 統計同等性」の手順がそのまま使える |
| テスト 51 件追加(606 件全通過) | 中 | runtime 層の安全網 |
以下のいずれかに該当した時は速度改善ワークを再開する:
runtime/llvm_init.py と同じ思想で「未検出時の自動 fallback」を入れる.Speed-2 のテンプレートは下記に未実施のまま保持しており,上記再開条件に該当した時にそのまま /implement で着手可能.