Repository navigation
Large Library Input Performance
Release の実 PlaylistAddItemsView をライブラリ10,000曲・空/5,000件登録済みプレイリストで操作した。検索を値のsnapshotから背景で計算する変更後、macOS・iPhone/iPad Simulatorの連続入力・削除・再入力と単独5キーが、最終文字列 UI Test Track 9999・候補1件に一致した。入力中のsnapshot再捕捉は0回だった。初回MainActor捕捉は残るため、入力時の改善と分けて評価する。
実 ExportMissingTitlesView の1,000件planでも、複数行の文字列保持と、999欄を埋めた最後の空欄の入力→全削除→再入力を3platformで確認した。最後の欄は Final complete name を保持し、Exportは入力済みで有効、全削除で無効、再入力で有効になった。製品の名前validationは変更していない。
| 採用条件 / 指標 | iPhone17e Simulator27.0 | iPad Pro13 M5 Simulator27.0 | MacBook Pro / Apple M3 / macOS27.0.1 |
|---|---|---|---|
| before・空playlist、再評価時の同期候補抽出中央値 | 42.036ms / 6評価、profilerなし | 未計測 | 未計測 |
| before・5,000件playlist、再評価時の同期候補抽出中央値 | 29.154ms / 6評価、profilerなし | 31.162ms / 6評価、TPあり | 21.265ms / 20評価、標準SwiftUI+TPあり |
| before・5,000件playlist、初回空queryの同期候補抽出 | 284.052ms / 1評価 | 初回値は採用表対象外 | 301.635ms / 1評価 |
| after・単独5キー試験の初回MainActor capture | 310.456ms / 1回 | 352.784ms / 1回 | 341.657ms / 1回 |
| after・単独5キーのMainActor enqueue | 0.014625–0.019000ms | 0.012791–0.034083ms | 0.105375–0.131916ms |
| after・単独5キーの背景worker | 9.939–11.919ms | 9.045–13.353ms | 9.126–10.282ms |
| after・単独5キーのMainActor publish | 0.031875–0.089125ms | 0.017042–0.031292ms | 0.133667–0.201916ms |
| after・単独5キー、enqueue開始→有効publish終了 | 10.281–22.086ms | 11.876–31.776ms | 10.171–15.643ms |
| after・入力中の再capture / 各キーの有効worker・publish | 0回 / 各1回 | 0回 / 各1回 | 0回 / 各1回 |
| after・連続入力、空/5,000件playlist | 両方成功 | 両方成功 | 両方成功 |
| Export複数行入力 / 最後の空欄入力 | 両方成功 | 両方成功、複数行の全計時は不採用 | 両方成功 |
| Export最後の欄validation、中央値 / 最大 | 0.099083 / 0.137958ms、41評価 | 0.096042 / 0.229750ms、30評価 | 0.122458 / 0.145000ms、67評価 |
beforeの手計時は Set(playlist.entries.compactMap) と同期候補抽出を囲った区間であり、body構築全体・SwiftUI更新全体の時間ではない。評価回数はキー数でもない。表の各指標と具体case/JSON fieldの対応は metric-source-map.json に記録した。before iPhoneの5,000件profilerなし値とTP証跡は別の採用runであり、同runの計時として混同しない。afterの4段階計時にはSwiftUI描画、source equality、AX照会やキーボード全体の処理を含めていない。壁時計のpipelineは要求から有効結果の反映までで、利用者の1キー遅延ではない。重なる段階を合算しない。
単独5キーの各要求はquery・request世代・source世代を対応付け、enqueue/publishがmain=true、workerがmain=false、入力中capture0を検証した。連続prefixはOSごとに実要求がcoalesceされ、iPhone2 / iPad4 / Mac17要求になった。prefixのpipeline範囲は31.867–82.545 / 26.497–37.817 / 12.162–33.504msで、単独5キーだけを連続入力の代表値にはしない。初回のpipelineは533.943 / 268.647 / 169.845ms、初回captureの末尾にenqueueを含み、一部重なるため合算しない。
入力区間を含むTime Profilerを9本採用し、全てTOCの対象PIDとdirect process列、実入力epochを照合した。beforeは連続入力、afterの主要traceはprefix入力後に単独5キーを追加する別操作なので、入力全区間のCPU合計・秒数を前後改善率へ変換しない。XCTestのtyping・AX照会・状態待ちの1.7–2.5秒も利用者の1キー遅延には使わない。
iOSの採用Time Profiler記録では、before iPadのMain Threadに同期filter131 samples / 131ms inclusiveを確認した。after両OSのMain Threadでは候補filter0 samples、各キーのworker区間では背景threadに8–11 samplesが現れた。初回captureのMain Thread CPU重みはiPhone302 / iPad344msだった。1ms sample間隔より短いenqueue/publishにsampleが無い場合もCPUゼロの証明にはしない。
Macの標準SwiftUI templateはTime Profilerを含み、before122,899 / after168,648 SwiftUI rowsを取得した。対象PID・入力epochで絞った PlaylistAddItemsView.body はbefore20評価、中央値36.234ms / 最大51.313ms。afterの単独5キーは各3評価、各キー内最大0.134 / 0.169 / 0.154 / 0.131 / 0.209msだった。この実body区間は前表の手計時区間とは範囲が異なる。イベントdurationは入れ子・重複を持つため、合計や4stageと重ねてUI全体遅延へ換算しない。
Mac TPにはbeforeのMain Threadの候補filter326.7ms inclusive、afterではMain Thread filter0、単独worker区間の背景filter8.6 / 8.8 / 8.8 / 8.4 / 8.8ms inclusiveを確認した。初回captureのMain Thread CPU重み341.4msは入力前として分けた。Macの標準templateは100µs sample重みで、iOSの1ms sample数と単純比較しない。afterのMain Threadには行の構築やAppKit layout等が残り、画面全体の同期処理を除去したという結論にはしない。
Export最後の欄の新TP3本にも対象CPU samplesを確認した(Mac1574 / iPhone1507 / iPad2367、全入力がtrace内)。iOSの当該traceにはunknown input sourceのtable警告があるが、取得済みTPの範囲とsamplesは確認できている。SwiftUI成功とは扱わない。
Xcode27.1 RC(27A9275)のDEVELOPER_DIRを一貫して指定した。iOS SDK27.1、Simulator runtime27.0、macOS SDK27.0を使用。測定appはRelease、UI-only・coverageなしの隔離コピー。実iPhone/iPadの速度ではなくSimulatorでの観察である。Appleは実機での性能試験を案内している。
before v3.1 / afterはApp初期化時にfixtureを1回準備し、Ready1行・items10000・entries0/5000・missing1000・context内playlist1・entries0/5000を各caseで確認した。fixture準備と画面到達は入力区間外。source/app/dSYM/xctestrunを凍結し、build開始/終了source hash一致を確認した。before原本はafterで上書きしていない。
Macの計測コピーは専用bundle ID・executableを使い、毎run前に前target0、起動後に実PIDのcommand path・bundle ID・実行fileSHAとxctestrun参照先の一致を確認した。自作のコピーapp/Runnerだけad-hoc署名し、Runner-only更新後もapp MachO SHAは不変だった。before df12769c…d50b97、after 01cafc5f…f10b6a、Export setup 11c56729…c6cf5。フル値とRunner SHAはsignatures JSONにある。システム設定・認証操作・privacy設定は変更していない。
record準備完了→入力開始→入力完了marker→targetが生きた状態でrecord停止/保存→Runner解除→target終了をhandshakeで実施。Mac beforeは入力1791696622.821–6626.776、停止6626.865・保存6648.765・解除6648.929。Mac afterは入力1791697128.214–7139.216、停止7139.422・保存7168.346・解除7168.474。各caseのtrace/test抜粋にUTC/epochを残した。全record/xcodebuild/対象app/UI Runnerを終了してから最終解析へ移った。
Export最後の欄はcopy-onlyの明示row IDと、layout後1回だけscrollToする準備を追加した。setupのbegin/end1組が入力より前にあり、typing中の再scrollが無いことを3platformで確認した。検索用凍結appとExport準備appは別保存。validation式自体は不変更。
検索Add callbackは性能コピーのno-op。通常アプリの重要操作は別のiPhone UI回帰で、Track1選択→検索で隠す→標準検索を閉じる→選択保持して実Add→playlistのTrack1確認→Rename→Remove→No Mediaまで成功した。検索中に標準toolbarが隠れる仕様のため、queryを閉じてAddする実到達操作と、隠れた選択をselectedItemsが返すunit契約を分けた。検索・helper変更後の通常scheme iOS全809件とmacOS Release全816件、関連unit・lintも成功している。
| 試行 / 制限 | 扱い |
|---|---|
| v2 Harness initでfixture二重生成 | 探索値だけ保持、最終比較から除外 |
| 旧Mac Runner署名待ち・Window0・AXのlabel/value/TouchBar差 | 入力未到達またはtest query誤りとして保存。既存Cmd-N fallbackとRunner-only AX query修正後のrunを採用 |
| 旧Export最後の欄scroll未到達 | 製品validation不具合としない。copy-only setup後の成功を採用 |
| iPad Exportmultipleの60秒quiescence待ちと後半の他作業併走 | 最終値保持・Export無効は成功。validationを含む全計時は不採用 |
| iOS SwiftUI0 rows | app生存中の停止/保存handshake後も未取得。原因をSimulator不具合と断定しない |
| before iPhoneのシンボル | app/dSYM UUID一致でもsymbolicate exit55。所有frameを推測しない。before iPad/after両iOSは解決成功 |
| 実機・全画面の利用者遅延 | 未検証。stage/イベント/CPUの計測範囲を超える主張をしない |
実装と通常回帰テストはPR #77を参照する。検索は PlaylistAddCandidateProjection/PlaylistAddCandidateFilter、画面は PlaylistAddItemsView、名前検証は ExportMissingTitlesView に対応する。
- Release・coverage OFFの検証コピーを用意し、専用bundle ID/inMemory store/専用tempで、ライブラリ10,000曲、プレイリスト0件と5,000件、名前plan1,000件を各1回だけ生成する。生成と画面到達を計時区間から除き、起動時の件数を確認する。
- 検索へ
UI Test Track 9999を連続入力し、全削除と再入力を行う。別試行ではprefixの後に単独5キーを入力し、各queryの候補反映を待つ。最終候補1件、request/source世代の一致、入力中capture0を照合する。 - 初回captureと要求enqueue/背景worker/結果publishの開始終了を同じ単調時計で記録する。計測hookは検証コピーだけへ置き、MainActor/背景threadの所属を記録する。要求と反映の壁時計差を利用者の1キー遅延へ読み替えない。
- 名前planの複数行と、999欄を埋めた最後の空欄を分けて入力・削除・再入力する。最終文字列保持とExportの有効→無効→有効を照合する。必要なscrollは入力前に完了させ、validationの式は変更しない。
- Time Profiler/取得可能なSwiftUI instrumentを、準備完了→実入力→対象app生存中の停止・保存の順で記録する。実PID・binaryのSHAと入力epochがtrace範囲に属することを確認し、初回capture、filter、keyboard/XCTestの仕事を分離する。他のbuild/性能試験を停止し、OSごとのsample間隔を記録する。
採用20casesの計測JSON、対応表、対象ログ、計測コピーのsourceとSHA、再現スクリプトはローカルに保全した。今回の公開は技術本文と公開済み製品実装・テストへの参照に限定する。