1 /* <lambda>null2 * Copyright 2021 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.macro.perfetto 18 19 import androidx.benchmark.macro.FileLinkingRule 20 import androidx.benchmark.macro.Packages 21 import androidx.benchmark.macro.runSingleSessionServer 22 import androidx.benchmark.perfetto.PerfettoCapture 23 import androidx.benchmark.perfetto.PerfettoConfig 24 import androidx.benchmark.perfetto.PerfettoHelper 25 import androidx.benchmark.perfetto.PerfettoHelper.Companion.isAbiSupported 26 import androidx.benchmark.traceprocessor.TraceProcessor 27 import androidx.benchmark.traceprocessor.toSlices 28 import androidx.test.ext.junit.runners.AndroidJUnit4 29 import androidx.test.filters.LargeTest 30 import androidx.test.filters.SdkSuppress 31 import androidx.tracing.Trace 32 import androidx.tracing.trace 33 import kotlin.test.assertEquals 34 import kotlin.test.assertTrue 35 import org.junit.After 36 import org.junit.Assert.assertTrue 37 import org.junit.Assume.assumeTrue 38 import org.junit.Before 39 import org.junit.Rule 40 import org.junit.Test 41 import org.junit.runner.RunWith 42 43 /** 44 * Tests for androidx.tracing.Trace, which validate actual trace content 45 * 46 * These can't be defined in the androidx.tracing library, as Trace capture / validation APIs are 47 * only available to the benchmark group. 48 */ 49 @SdkSuppress(minSdkVersion = 23) 50 @RunWith(AndroidJUnit4::class) 51 class AndroidxTracingTraceTest { 52 @get:Rule val linkRule = FileLinkingRule() 53 54 @Before 55 @After 56 fun cleanup() { 57 PerfettoHelper.cleanupPerfettoState() 58 } 59 60 @LargeTest 61 @Test 62 fun captureAndValidateTrace() { 63 assumeTrue(isAbiSupported()) 64 65 val traceFilePath = linkRule.createReportedTracePath(Packages.TEST) 66 val perfettoCapture = PerfettoCapture() 67 68 perfettoCapture.start( 69 PerfettoConfig.Benchmark( 70 appTagPackages = listOf(Packages.TEST), 71 useStackSamplingConfig = false 72 ) 73 ) 74 75 assertTrue( 76 Trace.isEnabled(), 77 "In-process tracing should be enabled immediately after trace capture is started" 78 ) 79 80 repeat(20) { 81 "$PREFIX$it" 82 .also { label -> 83 // actual test content. This is done in the middle of the other sections 84 // to isolate it from trace truncation issues 85 if (it == 10) { 86 Trace.setCounter("${PREFIX}counter", 1) 87 Trace.beginSection("${PREFIX}beginSection") 88 Trace.beginAsyncSection("${PREFIX}beginAsyncSection", 9827) 89 Thread.sleep(50) 90 Trace.setCounter("${PREFIX}counter", 0) 91 Trace.endSection() 92 Trace.endAsyncSection("${PREFIX}beginAsyncSection", 9827) 93 } 94 95 // trace sections before and after actual test content, to look for problems in 96 // front/back trace truncation. If these sections are missing, it's most likely 97 // issues in trace capture 98 trace(label) { Thread.sleep(50) } 99 } 100 } 101 102 perfettoCapture.stop(traceFilePath) 103 104 val queryResult = 105 TraceProcessor.runSingleSessionServer(traceFilePath) { query(query = QUERY) } 106 107 val matchingSlices = queryResult.toSlices() 108 assertEquals( 109 List(10) { "$PREFIX$it" } + 110 listOf( 111 "${PREFIX}counter1.0", 112 "${PREFIX}beginSection", 113 "${PREFIX}beginAsyncSection", 114 "${PREFIX}counter0.0", 115 ) + 116 List(10) { "$PREFIX${it + 10}" }, 117 matchingSlices.map { it.name } 118 ) 119 matchingSlices.forEach { 120 if (it.name.startsWith("${PREFIX}counter")) { 121 assertEquals(0L, it.dur) // counter has no length 122 } else { 123 assertTrue(it.dur > 30_000_000) // should be at least 30ms 124 } 125 } 126 } 127 128 companion object { 129 const val PREFIX = "AndroidxTracingTraceTest_" 130 131 const val QUERY = 132 """ 133 ------ select all relevant standard slices 134 SELECT 135 slice.name as name, 136 slice.ts as ts, 137 slice.dur as dur 138 FROM slice 139 INNER JOIN thread_track on slice.track_id = thread_track.id 140 INNER JOIN thread USING(utid) 141 INNER JOIN process USING(upid) 142 WHERE 143 slice.name LIKE "$PREFIX%" AND 144 process.name LIKE "androidx.benchmark.macro.test" 145 UNION 146 ------ add in async slices 147 SELECT 148 slice.name as name, 149 slice.ts as ts, 150 slice.dur as dur 151 FROM slice 152 INNER JOIN process_track on slice.track_id = process_track.id 153 INNER JOIN process USING(upid) 154 WHERE 155 slice.name LIKE "$PREFIX%" AND 156 process.name LIKE "androidx.benchmark.macro.test" 157 UNION 158 ------ add in the counter values, with value prepended to name 159 SELECT 160 counter_track.name || counter.value as name, 161 counter.ts as ts, 162 0 as dur 163 FROM counter 164 INNER JOIN counter_track on counter.track_id = counter_track.id 165 WHERE 166 counter_track.name LIKE "${PREFIX}counter" 167 ------ order the whole thing by timestamp 168 ORDER BY 169 ts 170 """ 171 } 172 } 173