Trace analysis

Trace analysis refers to a set of features built into the Perfetto trace processor and Perfetto UI which enrich a trace with extra information synthesized during the import of a trace. There are three features which currently part of this project:

Adding descriptions to slices

Descriptions in action Description for the measure slice

Background

Descriptions attach a human-readable description to a slice in the trace. This can include information like the source of a slice, why a slice is important and links to documentation where the viewer can learn more about the slice. In essence, descriptions act as if an expert was telling the user what the slice means.

For example, consider the inflate slice which occurs during view inflation in Android. We can add the following description and link:

Description: Constructing a View hierarchy from pre-processed XML via LayoutInflater#layout. This includes constructing all of the View objects in the hierarchy, and applying styled attributes.

Link: https://developer.android.com/reference/android/view/layoutinflater#inflate(int,%20android.view.viewgroup)

Adding descriptions to a slice

Adding a new event just requires a self-contained change to the DescribeSlice function. The inputs are the table containing all the slices from the trace and the id of the slice which an embedder (e.g. the UI) is requesting a description for. The output is a SliceDescription which is simply a pair<description, doc link>.

Currently, all implemented descriptions are based on only the name of the slice itself. However, it is straightforward to extend this to also consider the ancestor slices and other similar properties of the slice and we plan on doing this in the future.

Using descriptions as a trace processor embedder

The DescribeSlice function is exposed to SQL through the describe_slice table. This table has the following schema:

NameTypeMeaning
descriptionstringProvides the description for the given slice
doc_linkstringProvides a hyperlink to documentation which gives more context for the slice

The table also has a hidden column slice_id which need to be set equal to the id of the slice that you want to obtain the description from. For example, to get the description and doc link for slice with id 5:

select description, doc_link
from describe_slice
where slice_id = 5

You can also join the describe_slice table with the slice table to obtain descriptions for more than one slice. For example, to get the ts, duration and description for all measure slices:

select ts, dur, description
from slice s
join desribe_slice d on s.id = d.slice_id
where name = 'measure'

Annotating the trace with new events

Slice annotations Annotation slice track containing app startups

Counter annotations Annotation counter track added to measure ION allocations

Background

The annotations feature allows creation of new events (slices and counters) from the data in the trace. These events can then be displayed in the UI tracks as if they were part of the trace itself.

This feature is useful as often the data in the trace is very low-level. While this low level information is important to expose for experts to perform deep debugging, often the user is looking to get a high level overview without needing to piece together events from multiple places in the trace.

For example, an app startup in Android spans multiple components including ActivityManager, system_server and the newly created app process derived from zygote. Most users do not need startup broken down to this level of detail; instead they are simply interested in a single slice spanning the whole startup duration.

The annotations feature is tied very closely to metrics subsystem; Often the SQL-based metrics often need to create higher-level abstractions from raw slices as intermediate artifacts. From previous example, the startup metric, it creates the exact launching slice we want to display in the UI.

The other benefit of aligning the two is that changes in metrics are automatically kept in sync with what the user sees in the UI.

Adding annotations to a new or existing metric

As annotations depend on metrics, the initial steps are same as that of developing a metric. In summary:

  • Create a new proto message for your metric and add it to the TraceMetrics proto
  • Write a new SQL metric file in the metrics folder. Good examples to follow are ion and startup metrics

Note: the metric can be just an empty proto message during prototyping or if you think that no summarisation is necessary. However, generally if an event is important enough to display in the UI, it should also be tracked in benchmarks as a metric.

To extend a metric with annotations, a new table or view with the name <metric name>_annotations needs to be created (the trailing _annotations suffix in the table name is important). For example, for the android_startup metric, we create a view named android_startup_annotations.

The schema of this table/view is as follows:

NameTypePresenceMeaning
track_typestringMandatory‘slice’ for slices, ‘counter’ for counters
track_namestringMandatoryName of the track to display in the UI
tsint64MandatoryThe timestamp of the event (slice or counter)
durint64Mandatory for slice, NULL for counterThe duration of the slice
slice_namestringMandatory for slice, NULL for counterThe name of the slice
valuedoubleMandatory for counter, NULL for sliceThe value of the counter

Note: track_name acts as the track identifier i.e. all events with the same track_name are placed onto the same track.

Currently, there are a few limitations to what can be displayed with annotations:

  • Nested slices within the same track are not supported. We plan to support this once we have a concrete usecase.
  • Tracks are always created in the global scope. We plan to extend this to threads and processes in the near future with additional contexts added as necessary.
  • Instant events are currently not supported in the UI but this will be implemented in the near future. In trace processor, instants are always 0 duration slices with special rendering on the UI side.
  • There is no way to tie newly added events back to the source events in the trace which were used to generate them. This is not currently a priority but something we may add in the future.

Using annotations as a trace processor embedder

As annotations are tied to the metrics subsystem, the ComputeMetrics function in the trace processor API should be called with the appropriate metrics. This will create the <metric_name>_annotations table/view which can then be queried using the ExectueQuery function.

Note: We plan at some point to have an API which does not create and return the full metrics proto but instead just executes the queries in the metric.

Alerts

Background

Alerts are used to draw the attention of the user to interesting parts of the trace; this are usually warnings or errors about anomalies which occured in the trace.

Current status

Currently, alerts are not implemented in the trace processor but the annotations feature was designed with them in mind. We plan on adding another column alert_type (name to be finalized) to the annotations table which can have the value warning, error or null. Depending on this value, the Perfetto UI will flag these events to the user.

Note: we do not plan on supporting case where alerts need to be added to existing events. Instead, new events should be created using annotations and alerts added on these instead; this is because the trace processor storage is append-only.