ProfilingManager を使用して複数のトレースを収集すると、パフォーマンスの問題を見つけるために個別にトレースを調べるのは非現実的になります。一括トレース分析を使用すると、トレースのデータセットに対して同時に次の操作を行うことができます。
- 一般的なパフォーマンスの回帰を特定します。
- 統計分布(P50、P90、P99 レイテンシなど)を計算します。
- 複数のトレースにわたるパターンを見つけます。
- 外れ値のトレースを見つけて、パフォーマンスの問題を把握してデバッグします。
このセクションでは、Perfetto Python バッチ トレース プロセッサを使用して、ローカルに保存された一連のトレースの起動指標を分析し、外れ値のトレースを見つけて詳細な分析を行う方法について説明します。
クエリを設計する
一括分析を行う最初の手順は、PerfettoSQL クエリを作成することです。
このセクションでは、アプリの起動レイテンシを測定するクエリの例を示します。具体的には、activityStart から最初のフレームが生成されるまでの時間(Choreographer#doFrame スライスの最初の発生)を測定して、アプリの制御範囲内のアプリの起動レイテンシを測定できます。図 1 は、クエリするセクションを示しています。
CREATE OR REPLACE PERFETTO FUNCTION find_slices(pattern STRING) RETURNS
TABLE (name STRING, ts LONG, dur LONG) AS
SELECT name,ts,dur FROM slice WHERE name GLOB $pattern;
CREATE OR REPLACE PERFETTO FUNCTION generate_start_to_end_slices(startSlicePattern STRING, endSlicePattern STRING, inclusive BOOL) RETURNS
TABLE(name STRING, ts LONG, dur LONG) AS
SELECT name, ts, MIN(startToEndDur) as dur
FROM
(SELECT S.name as name, S.ts as ts, E.ts + IIF($inclusive, E.dur, 0) - S.ts as startToEndDur
FROM find_slices($startSlicePattern) as S CROSS JOIN find_slices($endSlicePattern) as E
WHERE startToEndDur > 0)
GROUP BY name, ts;
SELECT ts,name,dur from generate_start_to_end_slices('activityStart','*Choreographer#doFrame [0-9]*', true)
Perfetto UI 内でクエリを実行し、クエリ結果を使用してデバッグ トラックを生成(図 2)して、タイムライン内で可視化(図 3)できます。
Python 環境を設定する
ローカルマシンに Python とその必要なライブラリをインストールします。
pip install perfetto pandas plotly
一括トレース分析スクリプトを作成する
次のサンプル スクリプトは、Perfetto の Python BatchTraceProcessor を使用して、複数のトレースでクエリを実行します。
from perfetto.batch_trace_processor import BatchTraceProcessor
import glob
import plotly.express as px
traces = glob.glob('*.perfetto-trace')
if __name__ == '__main__':
with BatchTraceProcessor(traces) as btp:
query = """
CREATE OR REPLACE PERFETTO FUNCTION find_slices(pattern STRING) RETURNS
TABLE (name STRING, ts LONG, dur LONG) AS
SELECT name,ts,dur FROM slice WHERE name GLOB $pattern;
CREATE OR REPLACE PERFETTO FUNCTION generate_start_to_end_slices(startSlicePattern STRING, endSlicePattern STRING, inclusive BOOL) RETURNS
TABLE(name STRING, ts LONG, dur LONG) AS
SELECT name, ts, MIN(startToEndDur) as dur
FROM
(SELECT S.name as name, S.ts as ts, E.ts + IIF($inclusive, E.dur, 0) - S.ts as startToEndDur
FROM find_slices($startSlicePattern) as S CROSS JOIN find_slices($endSlicePattern) as E
WHERE startToEndDur > 0)
GROUP BY name, ts;
SELECT ts,name,dur / 1000000 as dur_ms from generate_start_to_end_slices('activityStart','*Choreographer#doFrame [0-9]*', true)
"""
df = btp.query_and_flatten(query)
violin = px.violin(df, x='dur_ms', hover_data='_path', title='startup time', points='all')
violin.show()
スクリプトを理解する
Python スクリプトを実行すると、次のアクションが実行されます。
- このスクリプトは、ローカル ディレクトリで
.perfetto-traceの接尾辞が付いたすべての Perfetto トレースを検索し、それらを分析のソース トレースとして使用します。 - 一括トレース クエリを実行して、
activityStartトレース スライスからアプリが生成した最初のフレームまでの時間に対応する起動時間のサブセットを計算します。 - バイオリン プロットを使用して起動時間の分布を可視化し、レイテンシをミリ秒単位でプロットします。
検索結果の解釈
スクリプトを実行すると、プロットが生成されます。この場合、プロットには 2 つの明確なピークを持つ二峰性分布が表示されます(図 4)。
次に、2 つの母集団の差を求めます。これにより、個々のトレースをより詳細に調べることができます。この例では、データポイント(レイテンシ)にカーソルを合わせると、トレース ファイル名を確認できるようにプロットが設定されています。次に、高レイテンシ グループに属するトレースのいずれかを開きます。
高レイテンシ グループのトレースを開くと(図 5)、起動中に実行される MyFlaggedFeature という名前のスライスが追加されています(図 6)。逆に、低レイテンシの母集団(左端のピーク)からトレースを選択すると、同じスライスが存在しないことが確認されます(図 7)。この比較は、ユーザーのサブセットに対して有効になっている特定の機能フラグが回帰をトリガーしていることを示しています。
この例は、一括トレース分析を使用する多くの方法の 1 つを示しています。その他のユースケースとしては、フィールドから統計情報を抽出して影響を測定する、回帰を検出するなどがあります。