Массовый анализ трассировки

Если вы собрали несколько трассировок с помощью ProfilingManager, изучать их по отдельности, чтобы найти проблемы с производительностью, нецелесообразно. Массовый анализ трассировок позволяет одновременно запрашивать набор данных трассировок, чтобы:

  • Выявлять распространенные проблемы с производительностью.
  • Рассчитывать статистические распределения (например, задержку P50, P90, P99).
  • Находить закономерности в нескольких трассировках.
  • Находите трассировки с выбросами, чтобы понять и устранить проблемы производительности.

В этом разделе показано, как использовать Perfetto Python Batch Trace Processor для анализа показателей запуска в наборе локально сохраненных трассировок и поиска выбросов для более глубокого анализа.

Создайте запрос

Чтобы выполнить массовый анализ, сначала создайте запрос PerfettoSQL.

В этом разделе мы приводим пример запроса, который измеряет задержку запуска приложения. В частности, вы можете измерить время от activityStart до первого сгенерированного кадра (первого появления фрагмента Choreographer#doFrame), чтобы определить задержку при запуске приложения, которая зависит от самого приложения. На рисунке 1 показан раздел, к которому нужно выполнить запрос.

Временная шкала трассировки, на которой выделена продолжительность от события activityStart до первого события Choreographer#doFrame.
Рисунок 1. Раздел трассировки от activityStart до первого сгенерированного кадра.
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, а затем использовать результаты запроса, чтобы создать отладочный трек (рис. 2) и визуализировать его на временной шкале (рис. 3).

Скриншот интерфейса Perfetto, на котором показано, как создать отладочный трек для запроса при запуске.
Рисунок 2. Создайте отладочную версию для запроса при запуске.
Временная шкала в интерфейсе Perfetto, на которой показана сгенерированная отладочная дорожка для запроса на запуск.
Рисунок 3. Создан отладочный трек для стартового запроса.

Настройка среды Python

Установите Python на локальный компьютер и необходимые библиотеки:

pip install perfetto pandas plotly

Создайте скрипт для массового анализа трассировки

Приведенный ниже пример скрипта выполняет запрос в нескольких трассировках с помощью Python BatchTraceProcessor в Perfetto.

from perfetto.batch_trace_processor import BatchTraceProcessor
import glob
import plotly.express as px

# Collect all trace files in the local directory
traces = glob.glob('*.perfetto-trace')

if not traces:
    print("No .perfetto-trace files found in the current directory.")
    exit(1)

if __name__ == '__main__':
    # Process all traces in parallel to aggregate metrics across runs
    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)
        # Plot the distribution of startup times, tracking trace file paths on
        # hover
        violin = px.violin(df, x='dur_ms', hover_data='_path', title='startup time', points='all')
        violin.show()

Как работает скрипт

При запуске скрипта Python выполняются следующие действия:

  1. Скрипт ищет в локальном каталоге все трассировки Perfetto с суффиксом .perfetto-trace и использует их в качестве исходных трассировок для анализа.
  2. Он выполняет массовый запрос трассировки, который вычисляет подмножество времени запуска, соответствующее времени от фрагмента трассировки activityStart до первого кадра, сгенерированного вашим приложением.
  3. Задержка в миллисекундах отображается на скрипичной диаграмме, которая позволяет визуализировать распределение времени запуска.

Как интерпретировать результаты

Скрипичная диаграмма, показывающая распределение задержек при запуске.
Рисунок 4. Скрипичная диаграмма задержек при запуске.

После выполнения скрипта будет создан график. В этом случае на графике показано бимодальное распределение с двумя отдельными пиками (рис. 4).

Затем найдите разницу между двумя популяциями. Это позволяет более подробно изучить отдельные трассировки. В этом примере график настроен так, что при наведении указателя на элементы (задержки) можно определить названия файлов трассировки. Затем вы можете открыть одну из трассировок, которая входит в группу с высокой задержкой.

Если вы откроете трассировку из группы с высокой задержкой (рис. 5), то увидите дополнительный фрагмент MyFlaggedFeature, который выполняется во время запуска (рис. 6). И наоборот, выбор трассировки из популяции с меньшей задержкой (крайний левый пик) подтверждает отсутствие того же среза (рис. 7). Это сравнение указывает на то, что регрессия вызвана определенным флагом функции, включенным для подмножества пользователей.

График, на котором выделен след с высокой задержкой.
Рисунок 5. Элемент с высокой задержкой на скрипичной диаграмме.
Трассировка, показывающая высокую задержку при запуске из-за фрагмента MyFlaggedFeature.
Рисунок 6. Высокая задержка при запуске трассировки с дополнительным срезом MyFlaggedFeature.
Трассировка, показывающая запуск с низкой задержкой без фрагмента MyFlaggedFeature.
Рисунок 7. Запуск трассировки с низкой задержкой.

Это лишь один из множества способов использования массового анализа трассировки. Другие варианты использования включают извлечение статистики из поля для оценки воздействия, обнаружение регрессий и многое другое.