• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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