1 /*
<lambda>null2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.benchmark.traceprocessor
18 
19 import androidx.annotation.RequiresApi
20 import androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi
21 import androidx.benchmark.perfetto.PerfettoCapture
22 import androidx.benchmark.perfetto.PerfettoCapture.PerfettoSdkConfig.InitialProcessState
23 import androidx.benchmark.perfetto.PerfettoCaptureWrapper
24 import androidx.benchmark.perfetto.PerfettoConfig
25 import androidx.benchmark.perfetto.UiState
26 import androidx.benchmark.perfetto.appendUiState
27 import androidx.test.platform.app.InstrumentationRegistry
28 import java.io.File
29 
30 /**
31  * Record a Perfetto System Trace for the specified [block].
32  *
33  * ```
34  * PerfettoTrace.record("myTrace") {
35  *     // content in here is traced to myTrace_<timestamp>.perfetto_trace
36  * }
37  * ```
38  *
39  * Reentrant Perfetto trace capture is not supported, so this API may not be combined with
40  * `BenchmarkRule`, `MacrobenchmarkRule`, or `PerfettoTraceRule`.
41  *
42  * If the block throws, the trace is still captured and passed to [traceCallback].
43  */
44 @RequiresApi(23)
45 @ExperimentalPerfettoCaptureApi
46 fun PerfettoTrace.Companion.record(
47     /**
48      * Output trace file names are labelled `<fileLabel>_<timestamp>.perfetto_trace`
49      *
50      * This timestamp is used for uniqueness when trace files are pulled automatically to Studio.
51      */
52     fileLabel: String,
53     /**
54      * Target process to trace with app tag (enables android.os.Trace / androidx.Trace).
55      *
56      * By default, traces this process.
57      */
58     appTagPackages: List<String> =
59         listOf(InstrumentationRegistry.getInstrumentation().targetContext.packageName),
60     /**
61      * Process to trace with userspace tracing, i.e. `androidx.tracing:tracing-perfetto`, ignored
62      * below API 30.
63      *
64      * This tracing is lower overhead than standard `android.os.Trace` tracepoints, but is currently
65      * experimental.
66      */
67     userspaceTracingPackage: String? = null,
68     /**
69      * Callback for trace capture.
70      *
71      * This callback allows you to process the trace even if the block throws, e.g. during a test
72      * failure.
73      */
74     traceCallback: ((PerfettoTrace) -> Unit)? = null,
75     /** Block to be traced. */
76     block: () -> Unit
77 ) =
78     record(
79         fileLabel = fileLabel,
80         config =
81             PerfettoConfig.Benchmark(
82                 appTagPackages = appTagPackages,
83                 useStackSamplingConfig = true
84             ),
85         userspaceTracingPackage = userspaceTracingPackage,
86         traceCallback = traceCallback,
87         block = block
88     )
89 
90 /**
91  * Record a Perfetto System Trace for the specified [block], with a fully custom Perfetto config,
92  * either text or binary.
93  *
94  * ```
95  * PerfettoTrace.record("myTrace", config = """...""") {
96  *     // content in here is traced to myTrace_<timestamp>.perfetto_trace
97  * }
98  * ```
99  *
100  * Reentrant Perfetto trace capture is not supported, so this API may not be combined with
101  * `BenchmarkRule`, `MacrobenchmarkRule`, or `PerfettoTraceRule`.
102  *
103  * If the block throws, the trace is still captured and passed to [traceCallback].
104  */
105 @RequiresApi(23)
106 @ExperimentalPerfettoCaptureApi
107 fun PerfettoTrace.Companion.record(
108     /**
109      * Output trace file names are labelled `<fileLabel>_<timestamp>.perfetto_trace`
110      *
111      * This timestamp is used for uniqueness when trace files are pulled automatically to Studio.
112      */
113     fileLabel: String,
114     /** Trace recording configuration. */
115     config: PerfettoConfig,
116     /**
117      * Process to emphasize in the tracing UI.
118      *
119      * Used to emphasize the target process, e.g. by pre-populating Studio trace viewer process
120      * selection.
121      *
122      * Defaults to the test's target process. Note that for self-instrumenting tests that measure
123      * another app, you must pass that target app package.
124      */
125     highlightPackage: String =
126         InstrumentationRegistry.getInstrumentation().targetContext.packageName,
127     /**
128      * Process to trace with userspace tracing, i.e. `androidx.tracing:tracing-perfetto`, ignored
129      * below API 30.
130      *
131      * This tracing is lower overhead than standard `android.os.Trace` tracepoints, but is currently
132      * experimental.
133      */
134     userspaceTracingPackage: String? = null,
135     /**
136      * Callback for trace capture.
137      *
138      * This callback allows you to process the trace even if the block throws, e.g. during a test
139      * failure.
140      */
141     traceCallback: ((PerfettoTrace) -> Unit)? = null,
142     /** Block to be traced. */
143     block: () -> Unit
144 ) {
145     PerfettoCaptureWrapper()
146         .record(
147             fileLabel = fileLabel,
148             config,
149             perfettoSdkConfig =
150                 userspaceTracingPackage?.let {
151                     PerfettoCapture.PerfettoSdkConfig(it, InitialProcessState.Unknown)
152                 },
153             traceCallback = { path ->
154                 File(path)
155                     .appendUiState(
156                         UiState(
157                             timelineStart = null,
158                             timelineEnd = null,
159                             highlightPackage = highlightPackage
160                         )
161                     )
162                 traceCallback?.invoke(PerfettoTrace(path))
163             },
164             block = block
165         )
166 }
167