# TraceMetric

Artifact: [androidx.benchmark:benchmark-macro](https://developer.android.com/jetpack/androidx/releases/benchmark) [View Source](https://cs.android.com/search?q=file:androidx/benchmark/macro/Metric.kt+class:androidx.benchmark.macro.TraceMetric) Added in [1.2.0](https://developer.android.com/jetpack/androidx/releases/benchmark#1.2.0)

*** ** * ** ***


```
@ExperimentalMetricApi
public abstract class TraceMetric extends Metric
```

<br />

|---|---|---|
| [java.lang.Object](https://developer.android.com/reference/java/lang/Object.html) |||
| ↳ | [androidx.benchmark.macro.Metric](https://developer.android.com/reference/androidx/benchmark/macro/Metric) ||
|   | ↳ | [androidx.benchmark.macro.TraceMetric](https://developer.android.com/reference/androidx/benchmark/macro/TraceMetric) |

Known direct subclasses [MemoryCountersMetric](https://developer.android.com/reference/androidx/benchmark/macro/MemoryCountersMetric), [MemoryUsageMetric](https://developer.android.com/reference/androidx/benchmark/macro/MemoryUsageMetric)

|---|---|
| `https://developer.android.com/reference/androidx/benchmark/macro/MemoryCountersMetric` | Captures the number of page faults over time for a target package name. |
| `https://developer.android.com/reference/androidx/benchmark/macro/MemoryUsageMetric` | Metric for tracking the memory usage of the target application. |

*** ** * ** ***

Metric which captures results from a Perfetto trace with custom `https://developer.android.com/reference/androidx/benchmark/traceprocessor/TraceProcessor` queries.

This is a more customizable version of `https://developer.android.com/reference/androidx/benchmark/macro/TraceSectionMetric` which can perform arbitrary queries against the captured PerfettoTrace.

Sample metric which finds the duration of the first "activityResume" trace section for the traced package:

```
class ActivityResumeMetric : TraceMetric() {
    override fun getMeasurements(
        captureInfo: CaptureInfo,
        traceSession: TraceProcessor.Session
    ): List<Measurement> {
        val rowSequence = traceSession.query(
            """
            SELECT
                slice.name as name,
                slice.ts as ts,
                slice.dur as dur
            FROM slice
                INNER JOIN thread_track on slice.track_id = thread_track.id
                INNER JOIN thread USING(utid)
                INNER JOIN process USING(upid)
            WHERE
                process.name LIKE ${captureInfo.targetPackageName}
                    AND slice.name LIKE "activityResume"
            """.trimIndent()
        )
        // this metric queries a single slice type to produce submetrics, but could be extended
        // to capture timing of every component of activity lifecycle
        val activityResultNs = rowSequence.firstOrNull()?.double("dur")
        return if (activityResultMs != null) {
            listOf(Measurement("activityResumeMs", activityResultNs / 1_000_000.0))
        } else {
            emptyList()
        }
    }
}
```

| See also |
|---|---|
| `https://developer.android.com/reference/androidx/benchmark/traceprocessor/TraceProcessor` |   |
| `https://developer.android.com/reference/androidx/benchmark/traceprocessor/TraceProcessor.Session` |   |
| `https://developer.android.com/reference/androidx/benchmark/traceprocessor/TraceProcessor.Session#query(kotlin.String)` |   |

## Summary

| ### Public constructors |
|---|
| `https://developer.android.com/reference/androidx/benchmark/macro/TraceMetric#TraceMetric()()` |

| ### Public methods |
|---|---|
| `abstract @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/java/util/List.html<@https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/benchmark/macro/Metric.Measurement>` | `https://developer.android.com/reference/androidx/benchmark/macro/TraceMetric#getMeasurements(androidx.benchmark.macro.Metric.CaptureInfo,androidx.benchmark.traceprocessor.TraceProcessor.Session)( @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/benchmark/macro/Metric.CaptureInfo captureInfo, @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/benchmark/traceprocessor/TraceProcessor.Session traceSession )` Get the metric result for a given iteration given information about the target process and a TraceProcessor session |

## Public constructors

### TraceMetric

Added in [1.2.0](https://developer.android.com/jetpack/androidx/releases/benchmark#1.2.0)

```
public TraceMetric()
```

## Public methods

### getMeasurements

Added in [1.4.0](https://developer.android.com/jetpack/androidx/releases/benchmark#1.4.0)

```
public abstract @NonNull List<@NonNull Metric.Measurement> getMeasurements(
    @NonNull Metric.CaptureInfo captureInfo,
    @NonNull TraceProcessor.Session traceSession
)
```

Get the metric result for a given iteration given information about the target process and a TraceProcessor session

```kotlin
import androidx.benchmark.macro.ExperimentalMetricApi
import androidx.benchmark.macro.TraceMetric
import androidx.benchmark.traceprocessor.TraceProcessor

/**
 * Calculates latency of sections where begin and end trace points are in different processes.
 *
 * @param beginPointName Name of begin tracepoint.
 * @param endPointName Name of end tracepoint.
 * @param eventName Name of the final metric that is spit out after the test run. The metric
 *   name will be {$eventName}LatencyMillis.
 */
@OptIn(ExperimentalMetricApi::class)
class CrossProcessLatencyMetricSample(
    private val beginPointName: String,
    private val endPointName: String,
    private val eventName: String,
) : TraceMetric() {
    @OptIn(ExperimentalMetricApi::class)
    override fun getMeasurements(
        captureInfo: CaptureInfo,
        traceSession: TraceProcessor.Session,
    ): List<Measurement> {
        val query =
            """
         INCLUDE perfetto module slices.with_context;
         SELECT
             event,
             ts2-ts1 AS latency_in_nanos
         FROM
         (
           (SELECT
               ts AS ts1,
               "event" AS event,
               LOWER(TRIM(process_name)) as process_name_1
               FROM thread_slice WHERE name = '${beginPointName}'
           )
           LEFT JOIN
           (SELECT
               ts AS ts2,
               "event" AS event,
               LOWER(TRIM(process_name)) as process_name_2
               FROM thread_slice WHERE name = '${endPointName}'
           )
           USING (event)
         )
           """
                .trimIndent() // maybe add checks for process name etc too in query

        val rowSequence = traceSession.query(query)
        // First row (or null) is returned.
        val latencyResultNanos = rowSequence.firstOrNull()?.long("latency_in_nanos")
        return if (latencyResultNanos != null) {
            listOf(Measurement(eventName + "LatencyMillis", latencyResultNanos / 1_000_000.0))
        } else {
            emptyList()
        }
    }
}
```