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ファイルを対象とする。