1/* 2 * Copyright (C) 2023 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 */ 16import {assertDefined} from 'common/assert_utils'; 17import { 18 TimestampConverterUtils, 19 timestampEqualityTester, 20} from 'common/time/test_utils'; 21import {TraceBuilder} from 'test/unit/trace_builder'; 22import {UnitTestUtils} from 'test/unit/utils'; 23import {CoarseVersion} from 'trace/coarse_version'; 24import {CustomQueryType} from 'trace/custom_query'; 25import {Parser} from 'trace/parser'; 26import {TraceType} from 'trace/trace_type'; 27import {PropertyTreeNode} from 'trace/tree_node/property_tree_node'; 28 29describe('Perfetto ParserTransactions', () => { 30 let parser: Parser<PropertyTreeNode>; 31 32 beforeAll(async () => { 33 jasmine.addCustomEqualityTester(timestampEqualityTester); 34 parser = await UnitTestUtils.getPerfettoParser( 35 TraceType.TRANSACTIONS, 36 'traces/perfetto/transactions_trace.perfetto-trace', 37 ); 38 }); 39 40 it('has expected trace type', () => { 41 expect(parser.getTraceType()).toEqual(TraceType.TRANSACTIONS); 42 }); 43 44 it('has expected coarse version', () => { 45 expect(parser.getCoarseVersion()).toEqual(CoarseVersion.LATEST); 46 }); 47 48 it('provides timestamps', () => { 49 const timestamps = assertDefined(parser.getTimestamps()); 50 51 expect(timestamps.length).toEqual(712); 52 53 const expected = [ 54 TimestampConverterUtils.makeRealTimestamp(1659507541051480997n), 55 TimestampConverterUtils.makeRealTimestamp(1659507541118452067n), 56 TimestampConverterUtils.makeRealTimestamp(1659507542621651001n), 57 ]; 58 expect(timestamps.slice(0, 3)).toEqual(expected); 59 }); 60 61 it('retrieves trace entry from timestamp', async () => { 62 const entry = await parser.getEntry(1); 63 expect(entry.id).toEqual('TransactionsTraceEntry entry'); 64 }); 65 66 it('transforms fake proto built from trace processor args', async () => { 67 const entry0 = await parser.getEntry(0); 68 const entry2 = await parser.getEntry(2); 69 70 // Add empty arrays 71 expect(entry0.getChildByName('addedDisplays')?.getAllChildren()).toEqual( 72 [], 73 ); 74 expect(entry0.getChildByName('destroyedLayers')?.getAllChildren()).toEqual( 75 [], 76 ); 77 expect(entry0.getChildByName('removedDisplays')?.getAllChildren()).toEqual( 78 [], 79 ); 80 expect( 81 entry0.getChildByName('destroyedLayerHandles')?.getAllChildren(), 82 ).toEqual([]); 83 expect(entry0.getChildByName('displays')?.getAllChildren()).toEqual([]); 84 85 // Add default values 86 expect( 87 entry0 88 .getChildByName('transactions') 89 ?.getChildByName('1') 90 ?.getChildByName('pid') 91 ?.getValue(), 92 ).toEqual(0); 93 94 // Convert value types (bigint -> number) 95 expect( 96 entry0 97 .getChildByName('transactions') 98 ?.getChildByName('1') 99 ?.getChildByName('uid') 100 ?.getValue(), 101 ).toEqual(1003); 102 103 // Decode enum IDs 104 expect( 105 entry0 106 .getChildByName('transactions') 107 ?.getChildByName('0') 108 ?.getChildByName('layerChanges') 109 ?.getChildByName('0') 110 ?.getChildByName('dropInputMode') 111 ?.formattedValue(), 112 ).toEqual('NONE'); 113 114 expect( 115 entry2 116 .getChildByName('transactions') 117 ?.getChildByName('0') 118 ?.getChildByName('layerChanges') 119 ?.getChildByName('0') 120 ?.getChildByName('bufferData') 121 ?.getChildByName('pixelFormat') 122 ?.formattedValue(), 123 ).toEqual('PIXEL_FORMAT_RGBA_1010102'); 124 }); 125 126 it("decodes 'what' field in proto", async () => { 127 { 128 const entry = await parser.getEntry(0); 129 const transactions = assertDefined(entry.getChildByName('transactions')); 130 expect( 131 transactions 132 .getChildByName('0') 133 ?.getChildByName('layerChanges') 134 ?.getChildByName('0') 135 ?.getChildByName('what') 136 ?.formattedValue(), 137 ).toEqual('eLayerChanged'); 138 139 expect( 140 transactions 141 .getChildByName('1') 142 ?.getChildByName('layerChanges') 143 ?.getChildByName('0') 144 ?.getChildByName('what') 145 ?.formattedValue(), 146 ).toEqual('eFlagsChanged | eDestinationFrameChanged'); 147 } 148 { 149 const entry = await parser.getEntry(222); 150 const transactions = assertDefined(entry.getChildByName('transactions')); 151 152 expect( 153 transactions 154 .getChildByName('1') 155 ?.getChildByName('displayChanges') 156 ?.getChildByName('0') 157 ?.getChildByName('what') 158 ?.formattedValue(), 159 ).toEqual( 160 'eLayerStackChanged | eDisplayProjectionChanged | eFlagsChanged', 161 ); 162 } 163 }); 164 165 it('supports VSYNCID custom query', async () => { 166 const trace = new TraceBuilder() 167 .setType(TraceType.TRANSACTIONS) 168 .setParser(parser) 169 .build(); 170 const entries = await trace 171 .sliceEntries(0, 3) 172 .customQuery(CustomQueryType.VSYNCID); 173 const values = entries.map((entry) => entry.getValue()); 174 expect(values).toEqual([1n, 2n, 3n]); 175 }); 176}); 177