blob: ffe567193529ab6f0b6b16c1d9bcf9bb8532e14d [file] [log] [blame]
Vishnu Nair7891e962021-11-11 12:07:21 -08001/*
2 * 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#include <gmock/gmock.h>
18#include <gtest/gtest.h>
19
20#include <gui/SurfaceComposerClient.h>
21
22#include "Tracing/RingBuffer.h"
23#include "Tracing/TransactionTracing.h"
24
25using namespace android::surfaceflinger;
26
27namespace android {
28
29class TransactionTracingTest : public testing::Test {
30protected:
Vishnu Nair0cc69e12021-11-18 09:05:49 -080031 static constexpr size_t SMALL_BUFFER_SIZE = 1024;
Vishnu Nair7891e962021-11-11 12:07:21 -080032 std::unique_ptr<android::TransactionTracing> mTracing;
Vishnu Nair7891e962021-11-11 12:07:21 -080033 void SetUp() override { mTracing = std::make_unique<android::TransactionTracing>(); }
34
Vishnu Nair0cc69e12021-11-18 09:05:49 -080035 void TearDown() override {
36 mTracing->disable();
37 mTracing.reset();
38 }
Vishnu Nair7891e962021-11-11 12:07:21 -080039
40 auto getCommittedTransactions() {
41 std::scoped_lock<std::mutex> lock(mTracing->mMainThreadLock);
42 return mTracing->mCommittedTransactions;
43 }
44
45 auto getQueuedTransactions() {
46 std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
47 return mTracing->mQueuedTransactions;
48 }
49
50 auto getUsedBufferSize() {
51 std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
52 return mTracing->mBuffer->used();
53 }
54
Vishnu Nair0cc69e12021-11-18 09:05:49 -080055 auto flush(int64_t vsyncId) { return mTracing->flush(vsyncId); }
Vishnu Nair7891e962021-11-11 12:07:21 -080056
57 auto bufferFront() {
58 std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
59 return mTracing->mBuffer->front();
60 }
61
62 bool threadIsJoinable() {
63 std::scoped_lock lock(mTracing->mMainThreadLock);
64 return mTracing->mThread.joinable();
65 }
66
Vishnu Nair0cc69e12021-11-18 09:05:49 -080067 proto::TransactionTraceFile writeToProto() { return mTracing->writeToProto(); }
68
69 auto getCreatedLayers() {
Vishnu Nair7891e962021-11-11 12:07:21 -080070 std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
Vishnu Nair0cc69e12021-11-18 09:05:49 -080071 return mTracing->mCreatedLayers;
72 }
73
74 auto getStartingStates() {
75 std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
76 return mTracing->mStartingStates;
77 }
78
79 void queueAndCommitTransaction(int64_t vsyncId) {
80 TransactionState transaction;
81 transaction.id = static_cast<uint64_t>(vsyncId * 3);
82 transaction.originUid = 1;
83 transaction.originPid = 2;
84 mTracing->addQueuedTransaction(transaction);
85 std::vector<TransactionState> transactions;
86 transactions.emplace_back(transaction);
87 mTracing->addCommittedTransactions(transactions, vsyncId);
88 flush(vsyncId);
Vishnu Nair7891e962021-11-11 12:07:21 -080089 }
90
91 // Test that we clean up the tracing thread and free any memory allocated.
92 void verifyDisabledTracingState() {
93 EXPECT_FALSE(mTracing->isEnabled());
94 EXPECT_FALSE(threadIsJoinable());
95 EXPECT_EQ(getCommittedTransactions().size(), 0u);
96 EXPECT_EQ(getQueuedTransactions().size(), 0u);
97 EXPECT_EQ(getUsedBufferSize(), 0u);
Vishnu Nair0cc69e12021-11-18 09:05:49 -080098 EXPECT_EQ(getStartingStates().size(), 0u);
Vishnu Nair7891e962021-11-11 12:07:21 -080099 }
100
101 void verifyEntry(const proto::TransactionTraceEntry& actualProto,
102 const std::vector<TransactionState> expectedTransactions,
103 int64_t expectedVsyncId) {
104 EXPECT_EQ(actualProto.vsync_id(), expectedVsyncId);
105 EXPECT_EQ(actualProto.transactions().size(),
106 static_cast<int32_t>(expectedTransactions.size()));
107 for (uint32_t i = 0; i < expectedTransactions.size(); i++) {
108 EXPECT_EQ(actualProto.transactions(static_cast<int32_t>(i)).pid(),
109 expectedTransactions[i].originPid);
110 }
111 }
112};
113
114TEST_F(TransactionTracingTest, enable) {
115 EXPECT_FALSE(mTracing->isEnabled());
116 mTracing->enable();
117 EXPECT_TRUE(mTracing->isEnabled());
118 mTracing->disable();
119 verifyDisabledTracingState();
120}
121
122TEST_F(TransactionTracingTest, addTransactions) {
123 mTracing->enable();
124 std::vector<TransactionState> transactions;
125 transactions.reserve(100);
126 for (uint64_t i = 0; i < 100; i++) {
127 TransactionState transaction;
128 transaction.id = i;
129 transaction.originPid = static_cast<int32_t>(i);
130 transactions.emplace_back(transaction);
131 mTracing->addQueuedTransaction(transaction);
132 }
133
134 // Split incoming transactions into two and commit them in reverse order to test out of order
135 // commits.
136 std::vector<TransactionState> firstTransactionSet =
137 std::vector<TransactionState>(transactions.begin() + 50, transactions.end());
138 int64_t firstTransactionSetVsyncId = 42;
139 mTracing->addCommittedTransactions(firstTransactionSet, firstTransactionSetVsyncId);
140
141 int64_t secondTransactionSetVsyncId = 43;
142 std::vector<TransactionState> secondTransactionSet =
143 std::vector<TransactionState>(transactions.begin(), transactions.begin() + 50);
144 mTracing->addCommittedTransactions(secondTransactionSet, secondTransactionSetVsyncId);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800145 flush(secondTransactionSetVsyncId);
Vishnu Nair7891e962021-11-11 12:07:21 -0800146
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800147 proto::TransactionTraceFile proto = writeToProto();
148 EXPECT_EQ(proto.entry().size(), 3);
149 // skip starting entry
150 verifyEntry(proto.entry(1), firstTransactionSet, firstTransactionSetVsyncId);
151 verifyEntry(proto.entry(2), secondTransactionSet, secondTransactionSetVsyncId);
Vishnu Nair7891e962021-11-11 12:07:21 -0800152
153 mTracing->disable();
154 verifyDisabledTracingState();
155}
156
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800157class TransactionTracingLayerHandlingTest : public TransactionTracingTest {
158protected:
159 void SetUp() override {
160 TransactionTracingTest::SetUp();
161 mTracing->enable();
162 // add layers
163 mTracing->setBufferSize(SMALL_BUFFER_SIZE);
164 const sp<IBinder> fakeLayerHandle = new BBinder();
165 mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent",
166 123 /* flags */, -1 /* parentId */);
167 const sp<IBinder> fakeChildLayerHandle = new BBinder();
168 mTracing->onLayerAdded(fakeChildLayerHandle->localBinder(), 2 /* layerId */, "child",
169 456 /* flags */, mParentLayerId);
170
171 // add some layer transaction
172 {
173 TransactionState transaction;
174 transaction.id = 50;
175 ComposerState layerState;
176 layerState.state.surface = fakeLayerHandle;
177 layerState.state.what = layer_state_t::eLayerChanged;
178 layerState.state.z = 42;
179 transaction.states.add(layerState);
180 ComposerState childState;
181 childState.state.surface = fakeChildLayerHandle;
182 layerState.state.z = 43;
183 transaction.states.add(childState);
184 mTracing->addQueuedTransaction(transaction);
185
186 std::vector<TransactionState> transactions;
187 transactions.emplace_back(transaction);
188 VSYNC_ID_FIRST_LAYER_CHANGE = ++mVsyncId;
189 mTracing->addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE);
190 flush(VSYNC_ID_FIRST_LAYER_CHANGE);
191 }
192
193 // add transactions that modify the layer state further so we can test that layer state
194 // gets merged
195 {
196 TransactionState transaction;
197 transaction.id = 51;
198 ComposerState layerState;
199 layerState.state.surface = fakeLayerHandle;
200 layerState.state.what = layer_state_t::eLayerChanged | layer_state_t::ePositionChanged;
201 layerState.state.z = 41;
202 layerState.state.x = 22;
203 transaction.states.add(layerState);
204 mTracing->addQueuedTransaction(transaction);
205
206 std::vector<TransactionState> transactions;
207 transactions.emplace_back(transaction);
208 VSYNC_ID_SECOND_LAYER_CHANGE = ++mVsyncId;
209 mTracing->addCommittedTransactions(transactions, VSYNC_ID_SECOND_LAYER_CHANGE);
210 flush(VSYNC_ID_SECOND_LAYER_CHANGE);
211 }
212
213 // remove child layer
214 mTracing->onLayerRemoved(2);
215 VSYNC_ID_CHILD_LAYER_REMOVED = ++mVsyncId;
216 queueAndCommitTransaction(VSYNC_ID_CHILD_LAYER_REMOVED);
217
218 // remove layer
219 mTracing->onLayerRemoved(1);
220 queueAndCommitTransaction(++mVsyncId);
221 }
222
223 void TearDown() override {
224 mTracing->disable();
225 verifyDisabledTracingState();
226 TransactionTracingTest::TearDown();
227 }
228
229 int mParentLayerId = 1;
230 int64_t mVsyncId = 0;
231 int64_t VSYNC_ID_FIRST_LAYER_CHANGE;
232 int64_t VSYNC_ID_SECOND_LAYER_CHANGE;
233 int64_t VSYNC_ID_CHILD_LAYER_REMOVED;
234};
235
236TEST_F(TransactionTracingLayerHandlingTest, addStartingState) {
237 // add transactions until we drop the transaction with the first layer change
238 while (bufferFront().vsync_id() <= VSYNC_ID_FIRST_LAYER_CHANGE) {
239 queueAndCommitTransaction(++mVsyncId);
240 }
241 proto::TransactionTraceFile proto = writeToProto();
242 // verify we can still retrieve the layer change from the first entry containing starting
243 // states.
244 EXPECT_GT(proto.entry().size(), 0);
245 EXPECT_GT(proto.entry(0).transactions().size(), 0);
246 EXPECT_GT(proto.entry(0).added_layers().size(), 0);
247 EXPECT_GT(proto.entry(0).transactions(0).layer_changes().size(), 0);
248 EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 42);
249}
250
251TEST_F(TransactionTracingLayerHandlingTest, updateStartingState) {
252 // add transactions until we drop the transaction with the second layer change
253 while (bufferFront().vsync_id() <= VSYNC_ID_SECOND_LAYER_CHANGE) {
254 queueAndCommitTransaction(++mVsyncId);
255 }
256 proto::TransactionTraceFile proto = writeToProto();
257 // verify starting states are updated correctly
258 EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 41);
259}
260
261TEST_F(TransactionTracingLayerHandlingTest, removeStartingState) {
262 // add transactions until we drop the transaction which removes the child layer
263 while (bufferFront().vsync_id() <= VSYNC_ID_CHILD_LAYER_REMOVED) {
264 queueAndCommitTransaction(++mVsyncId);
265 }
266 proto::TransactionTraceFile proto = writeToProto();
267 // verify the child layer has been removed from the trace
268 EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 1);
269 EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
270}
271
272TEST_F(TransactionTracingLayerHandlingTest, startingStateSurvivesBufferFlush) {
273 // add transactions until we drop the transaction with the second layer change
274 while (bufferFront().vsync_id() <= VSYNC_ID_SECOND_LAYER_CHANGE) {
275 queueAndCommitTransaction(++mVsyncId);
276 }
277 proto::TransactionTraceFile proto = writeToProto();
278 // verify we have two starting states
279 EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2);
280
281 // Continue adding transactions until child layer is removed
282 while (bufferFront().vsync_id() <= VSYNC_ID_CHILD_LAYER_REMOVED) {
283 queueAndCommitTransaction(++mVsyncId);
284 }
285 proto = writeToProto();
286 // verify we still have the parent layer state
287 EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 1);
288 EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
289}
290
Vishnu Nair7891e962021-11-11 12:07:21 -0800291} // namespace android