MusicAnalysis Executor Trace - log5r/simple-media-player GitHub Wiki
楽曲解析時の utility タスクの開始遅延
対象: #76。確認日: 2026-10-11(JST)。解析時の残る遅延を調べ、アプリの境界に executor preference を付ける候補の効果を比較した。候補は効果がなく、製品コードへ採用していない。
実アプリに合わせた待ち方
採用 Xcode 27 SDK の公開 interface では、MusicUnderstandingSession と analyze/cancel は actor に隔離され、unownedExecutor は defaultActor とされる。ただし default actor は Task executor preference を継承できる。SE-0417 の契約と、実行時の trace を合わせて確認した。
現行 Controller の Task は utility で、実 Player は戻った Task の完了を直接 await しない。初回ハーネスは MainActor から直接 await していたため、trace の framework 解析の priority は Medium(21)へ昇格した。この結果は実アプリの utility 遅延の確認として無効にした。修正版は status を10 ms間隔で観測し、完了後だけ task.value を await する。
Release 調査 binary は Controller を含む現行 source を swiftc -O -g -swift-version 6 でコンパイルし、MainActor 既定と本体の upcoming features を指定した。全曲解析・局所 key/rhythm・結果変換・表示データ計算を通す。解析cacheはnil。WAV用 adapter は拡張形式のdecode経路だけを置き換える。統合版は実 AudioEngine と normalizer を併用し、前曲を正規化 ON で1.5秒再生後、WV の PCM cache と gain を消して解析と load/play を同時に開始する。
非 trace 試行の結果
10 msごとに utility と userInitiated の協調 Task を作り、開始までの遅延を測った。WAV単独の各1回では、既定幅の最大値は utility8.643 ms/userInitiated0.880 ms、strict1は1171.532 ms/7.004 msだった。LIBDISPATCH_COOPERATIVE_POOL_STRICT=1 の実統合1回では、utility1292.536 ms/userInitiated0.293 ms、解析12.364秒で、結果ready・pace256点・tempo645点・再生開始markを確認した。
隔離 copy で Controller の analyze 呼び出し全体を withTaskExecutorPreference(BlockingWorkExecutor.shared) で囲み、MainActor の受理・世代判定・cancel/失敗処理は変えずに比較した。
| 条件 | utility 最大遅延 | 全解析時間 |
|---|---|---|
| preference候補 1回目 | 1281.100 ms | 20.241秒 |
| preference候補 2回目 | 1387.916 ms | 13.544秒 |
| preference候補 3回目 | 1560.555 ms | 12.907秒 |
| 候補の中央値 | 1387.916 ms | 13.544秒 |
| 同じ統合binary、解析なし1回 | 2.386 ms | 対象外 |
候補の userInitiated 最大遅延の中央値は0.588 ms。全3回で結果・表示データと再生開始が成功したが、utility の遅延は改善しなかった。初期 await 版の小さい遅延を修正効果と扱わない。
Task と CPU stack の相関
Swift Concurrency と Time Profiler を同時に採取した。修正前の utility thread 0x1e2d6bc では KeyModelWrapper actor の197.321/128.753/128.269 ms等の Running 区間があった。Task332の4385.190〜4582.511 msと同threadのCPU sample4386.050 msを対応付けると、CoreML predictionからEspressoのmemory bindingへ進むstackだった。
候補でも utility thread 0x1e30219 に156.403/130.321/126.325 ms等の区間が残り、Task274の4002.323〜4158.726 msと同threadのsample4002.356 msにCoreML predictionとMusicUnderstanding内部のframeがあった。framework/CoreML/Espresso の該当sample9175件がこのthreadに集中していた。appの解析frameがありframework/CoreML/Espressoのframeがないsampleはbefore15件、候補13件だった。この採取範囲では、app側の変換・局所処理・表示データ計算に秒単位の占有は観測しなかった。samplingで見えない短い処理の不在までは保証しない。
既定幅の noawait 実統合も、ほかの build/test を止めた専用枠で同時traceを採取した。解析8.718秒、ready・pace256点/tempo647点・再生markがあり、framework Taskは Low/Utility(17)だった。このtrace試行の最大遅延はutility3.540 ms/userInitiated2.372 msで、非trace試行の中央値へ混ぜていない。Task359、KeyModelWrapper actor、thread 0x1e44bf9 のRunning表示と4242.614 msのCPU sampleを相関させると、Espressoのfloat16/float変換、ExecuteSync、CoreML prediction、MusicUnderstanding内部を通るstackだった。既定幅とstrict1の双方で、priorityを昇格させない実統合経路のTask・actor・CPUを確認した。
Dispatch worker は再利用されるため、別時点の Global Concurrent Executor とthreadが同じというだけでは、当該区間のexecutorの証拠にならない。記録されたTask ID・priority・actor・thread・同時刻CPU sampleを相関させた範囲の結論である。正確なqueueラベルやTaskExecutorの列は得られていない。長いRunning表示も、その長さを連続CPU占有時間として扱わずCPU sampleと照合した。
SE-0417はdefault actor/async let/TaskGroupへの継承を定めるが、非構造化のTask/Task.detachedはpreferenceを継承しない。SDK内部のTask生成や継承が切れる位置は公開interfaceと未公開symbolからは特定できなかった。アプリ境界から付けた候補では遅延を解消できなかった、という確認範囲にとどめる。
再現条件と残る範囲
旧 #66 と同じ Apple M3・macOS27.0.1・Xcode27.0 で実行した。旧測定は再生開始後300 msで解析をcancelし、今回の最終統合版は Controller の結果・表示データまで完了を待つ。合成波形のnoise seedは固定されず、消失した旧波形との一致とモデルの初回準備温度は保証できない。
候補比較の数値は非traceの試行を使い、traceの遅延を中央値へ混ぜない。iPhone実機や実楽曲、UI経路はこの検証に含めない。利用者の解析cache・楽曲・設定は変更していない。
元ログ・JSON・TaskとCPUの相関表と再現コードは benchmarks の README に保存する。trace bundleは一時資材 /private/tmp/smp-issues-75-76/ にある。パラメータ化した再現セット全体の再実行は未実施で、実測は固定tmpパスの版を使った。
実compile時のsource、隔離cacheと計測hook、commandはbenchmarksの source-snapshots/ に保存し、source-provenance.md に差替えを記録した。SHA256SUMS はsnapshot・probe・scripts・resultsの147ファイルを対象とする。