tree: 258a3b03b6e6812a6a8c240def549db40b566147 [path history] [tgz]
  1. profile/
  2. res/
  3. .style.yapf
  4. __init__.py
  5. chrome.py
  6. command_line.py
  7. OWNERS
  8. perfetto_ui.py
  9. plot.py
  10. README.md
  11. trace.py
  12. wpr.py
tools/android/colabutils/README.md

Colab Utilities for Android

This directory contains a collection of Python utilities designed to facilitate Android performance analysis, particularly within a Colab or Jupyter notebook environment. These tools provide a programmatic interface for controlling Chrome on a connected Android device, recording Perfetto traces, and analyzing the collected data.

Googlers-only: go/chrome-colabutils-example contains a Colab notebook with examples of how to use colabutils.

Making colabutils available to the python runtime

The colabutils module assumes that the notebook's current working directory is the Chromium source directory. With that in mind, the colabutils module requires the following code snippet to be run to be make available to the python runtime for importing:

import sys
import os

colabutils_path = os.path.abspath(os.path.join(os.getcwd(), 'tools', 'android'))
if colabutils_path not in sys.path:
    sys.path.append(colabutils_path)

Example: Record a perfetto trace of cold launch of Chrome

Create a custom configuration using Perfetto UI and then save it as a file that can be accessed by the python notebook.

Then, use asyncio to concurrently launch Chrome and record a trace.

import asyncio
from colabutils import chrome, trace

# Kill the current chrome instance
app = chrome.App(chrome.Channel.STABLE)
await app.stop()

# Use asyncio.gather with asyncio.create_task to run the two async functions
# concurrently
recorded_trace = trace.TraceFile("/tmp/recorded_trace.pftrace")
async with recorded_trace.record():
  await asyncio.sleep(2) # wait for trace recording to start
  await app.start(url="https://chromium.org")

Once you have a trace file, you can use the perfetto_ui.open_trace function to immediately open and visualize it in the Perfetto UI.

# Opens the trace on https://ui.perfetto.dev
from colabutils import perfetto_ui
perfetto_ui.open_trace(recorded_trace)

Furthermore, you can also programmatically query the trace data using PerfettoSQL.

# PerfettoSQL query to search for slices with the name
# RenderFrameHostImpl::DidCommitNavigation
perfetto_query = r"""
    INCLUDE PERFETTO MODULE viz.slices;

    SELECT
      _viz_slices_for_ui_table_0.id AS id,
      _viz_slices_for_ui_table_0.ts AS ts,
      _viz_slices_for_ui_table_0.dur AS dur,
      _viz_slices_for_ui_table_0.category AS category,
      _viz_slices_for_ui_table_0.name AS name,
      _viz_slices_for_ui_table_0.utid AS utid,
      thread_1.tid AS thread__utid____tid,
      thread_1.name AS thread__utid____name,
      _viz_slices_for_ui_table_0.upid AS upid,
      process_2.pid AS process__upid____pid,
      process_2.name AS process__upid____name,
      _viz_slices_for_ui_table_0.parent_id AS parent_id
    FROM _viz_slices_for_ui_table AS _viz_slices_for_ui_table_0
    LEFT JOIN thread AS thread_1 ON thread_1.id = _viz_slices_for_ui_table_0.utid
    LEFT JOIN process AS process_2 ON process_2.id = _viz_slices_for_ui_table_0.upid
    WHERE
      _viz_slices_for_ui_table_0.name = 'RenderFrameHostImpl::DidCommitNavigation'
"""

import pandas as pd

# The query result is returned as a pandas dataframe. So the the total duration
# can be calculated from the 'dur' column.
df = await recorded_trace.query(perfetto_query)
total_duration_ms = df['dur'].sum() / 1_000_000
print(f"Total time spent in RenderFrameHostImpl::DidCommitNavigation = {total_duration_ms} milliseconds")

Example: Using Web Page Replay

Web Page Replay (WPR) is a tool for capturing and replaying network traffic. This is useful for eliminating network variability. WPR can be integrated with other automation as shown below:

# Create the archive file
wpr_archive = wpr.WebPageReplayArchive(f"/tmp/wpr_archive_{session_id}.wprgo")

# Record into the archive file
async with wpr_archive.record():
  # Run an automation that simulates the network traffic expected during replay
  await app.stop()
  await app.start(url="https://chromium.org")
  await asyncio.sleep(10)
  await app.stop()

# Replay the archive file
async with wpr_archive.replay():
  # Run the test automation while network traffic is replayed. This example
  # extends the previous example which records a cold launch of Chrome.
  recorded_trace = trace.TraceFile("/tmp/recorded_trace.pftrace")
  async with recorded_trace.record():
    await asyncio.sleep(2) # wait for trace recording to start
    await app.start(url="https://chromium.org")