blob: a46b79578f350b733e1a3e35d68f497f8ed0a8fc [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#undef LOG_TAG
18#define LOG_TAG "TransactionTracing"
19#define ATRACE_TAG ATRACE_TAG_GRAPHICS
20
21#include <android-base/stringprintf.h>
22#include <log/log.h>
23#include <utils/SystemClock.h>
24#include <utils/Trace.h>
25
Vishnu Nair7891e962021-11-11 12:07:21 -080026#include "TransactionTracing.h"
27
28namespace android {
29
30TransactionTracing::TransactionTracing() {
Vishnu Nair7891e962021-11-11 12:07:21 -080031 std::scoped_lock lock(mTraceLock);
Dominik Laskowski46471e62022-01-14 15:34:03 -080032
33 mBuffer.setSize(mBufferSizeInBytes);
Vishnu Nair0cc69e12021-11-18 09:05:49 -080034 mStartingTimestamp = systemTime();
Vishnu Nair7891e962021-11-11 12:07:21 -080035 {
36 std::scoped_lock lock(mMainThreadLock);
Vishnu Nair7891e962021-11-11 12:07:21 -080037 mThread = std::thread(&TransactionTracing::loop, this);
38 }
Vishnu Nair7891e962021-11-11 12:07:21 -080039}
40
Dominik Laskowski46471e62022-01-14 15:34:03 -080041TransactionTracing::~TransactionTracing() {
Vishnu Nair7891e962021-11-11 12:07:21 -080042 std::thread thread;
43 {
44 std::scoped_lock lock(mMainThreadLock);
45 mDone = true;
46 mTransactionsAvailableCv.notify_all();
47 thread = std::move(mThread);
48 }
49 if (thread.joinable()) {
50 thread.join();
51 }
52
Dominik Laskowski46471e62022-01-14 15:34:03 -080053 writeToFile();
Vishnu Nair7891e962021-11-11 12:07:21 -080054}
55
56status_t TransactionTracing::writeToFile() {
57 std::scoped_lock lock(mTraceLock);
Vishnu Nair7891e962021-11-11 12:07:21 -080058 proto::TransactionTraceFile fileProto = createTraceFileProto();
Vishnu Nair0cc69e12021-11-18 09:05:49 -080059 addStartingStateToProtoLocked(fileProto);
Dominik Laskowski46471e62022-01-14 15:34:03 -080060 return mBuffer.writeToFile(fileProto, FILE_NAME);
Vishnu Nair7891e962021-11-11 12:07:21 -080061}
62
63void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) {
64 std::scoped_lock lock(mTraceLock);
65 mBufferSizeInBytes = bufferSizeInBytes;
Dominik Laskowski46471e62022-01-14 15:34:03 -080066 mBuffer.setSize(mBufferSizeInBytes);
Vishnu Nair7891e962021-11-11 12:07:21 -080067}
68
69proto::TransactionTraceFile TransactionTracing::createTraceFileProto() const {
70 proto::TransactionTraceFile proto;
71 proto.set_magic_number(uint64_t(proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_H) << 32 |
72 proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_L);
73 return proto;
74}
75
76void TransactionTracing::dump(std::string& result) const {
77 std::scoped_lock lock(mTraceLock);
Vishnu Nair0cc69e12021-11-18 09:05:49 -080078 base::StringAppendF(&result,
79 " queued transactions=%zu created layers=%zu handles=%zu states=%zu\n",
80 mQueuedTransactions.size(), mCreatedLayers.size(), mLayerHandles.size(),
81 mStartingStates.size());
Dominik Laskowski46471e62022-01-14 15:34:03 -080082 mBuffer.dump(result);
Vishnu Nair7891e962021-11-11 12:07:21 -080083}
84
85void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
86 std::scoped_lock lock(mTraceLock);
87 ATRACE_CALL();
Vishnu Nair7891e962021-11-11 12:07:21 -080088 mQueuedTransactions[transaction.id] =
Vishnu Nair0cc69e12021-11-18 09:05:49 -080089 TransactionProtoParser::toProto(transaction,
90 std::bind(&TransactionTracing::getLayerIdLocked, this,
91 std::placeholders::_1),
92 nullptr);
Vishnu Nair7891e962021-11-11 12:07:21 -080093}
94
95void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
96 int64_t vsyncId) {
97 CommittedTransactions committedTransactions;
98 committedTransactions.vsyncId = vsyncId;
99 committedTransactions.timestamp = systemTime();
100 committedTransactions.transactionIds.reserve(transactions.size());
101 for (const auto& transaction : transactions) {
102 committedTransactions.transactionIds.emplace_back(transaction.id);
103 }
104
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800105 mPendingTransactions.emplace_back(committedTransactions);
106 tryPushToTracingThread();
Vishnu Nair7891e962021-11-11 12:07:21 -0800107}
108
109void TransactionTracing::loop() {
110 while (true) {
111 std::vector<CommittedTransactions> committedTransactions;
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800112 std::vector<int32_t> removedLayers;
Vishnu Nair7891e962021-11-11 12:07:21 -0800113 {
114 std::unique_lock<std::mutex> lock(mMainThreadLock);
115 base::ScopedLockAssertion assumeLocked(mMainThreadLock);
116 mTransactionsAvailableCv.wait(lock, [&]() REQUIRES(mMainThreadLock) {
117 return mDone || !mCommittedTransactions.empty();
118 });
119 if (mDone) {
120 mCommittedTransactions.clear();
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800121 mRemovedLayers.clear();
Vishnu Nair7891e962021-11-11 12:07:21 -0800122 break;
123 }
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800124
125 removedLayers = std::move(mRemovedLayers);
126 mRemovedLayers.clear();
Vishnu Nair7891e962021-11-11 12:07:21 -0800127 committedTransactions = std::move(mCommittedTransactions);
128 mCommittedTransactions.clear();
129 } // unlock mMainThreadLock
130
Vishnu Nairb8f2a2d2022-01-13 08:10:10 -0800131 if (!committedTransactions.empty() || !removedLayers.empty()) {
132 addEntry(committedTransactions, removedLayers);
133 }
Vishnu Nair7891e962021-11-11 12:07:21 -0800134 }
135}
136
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800137void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& committedTransactions,
138 const std::vector<int32_t>& removedLayers) {
Vishnu Nair7891e962021-11-11 12:07:21 -0800139 ATRACE_CALL();
140 std::scoped_lock lock(mTraceLock);
Vishnu Nair62863552021-12-10 13:34:48 -0800141 std::vector<std::string> removedEntries;
142 proto::TransactionTraceEntry entryProto;
Vishnu Nair7891e962021-11-11 12:07:21 -0800143 for (const CommittedTransactions& entry : committedTransactions) {
Vishnu Nair7891e962021-11-11 12:07:21 -0800144 entryProto.set_elapsed_realtime_nanos(entry.timestamp);
145 entryProto.set_vsync_id(entry.vsyncId);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800146 entryProto.mutable_added_layers()->Reserve(static_cast<int32_t>(mCreatedLayers.size()));
147 for (auto& newLayer : mCreatedLayers) {
148 entryProto.mutable_added_layers()->Add(std::move(newLayer));
149 }
150 entryProto.mutable_removed_layers()->Reserve(static_cast<int32_t>(removedLayers.size()));
151 for (auto& removedLayer : removedLayers) {
152 entryProto.mutable_removed_layers()->Add(removedLayer);
153 }
154 mCreatedLayers.clear();
Vishnu Nair7891e962021-11-11 12:07:21 -0800155 entryProto.mutable_transactions()->Reserve(
156 static_cast<int32_t>(entry.transactionIds.size()));
157 for (const uint64_t& id : entry.transactionIds) {
158 auto it = mQueuedTransactions.find(id);
159 if (it != mQueuedTransactions.end()) {
160 entryProto.mutable_transactions()->Add(std::move(it->second));
161 mQueuedTransactions.erase(it);
162 } else {
Vishnu Nair047fb332021-12-09 09:54:36 -0800163 ALOGW("Could not find transaction id %" PRIu64, id);
Vishnu Nair7891e962021-11-11 12:07:21 -0800164 }
165 }
Vishnu Nair62863552021-12-10 13:34:48 -0800166
167 std::string serializedProto;
168 entryProto.SerializeToString(&serializedProto);
169 entryProto.Clear();
Dominik Laskowski46471e62022-01-14 15:34:03 -0800170 std::vector<std::string> entries = mBuffer.emplace(std::move(serializedProto));
Vishnu Nair62863552021-12-10 13:34:48 -0800171 removedEntries.reserve(removedEntries.size() + entries.size());
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800172 removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()),
173 std::make_move_iterator(entries.end()));
Vishnu Naird37343b2022-01-12 16:18:56 -0800174
175 entryProto.mutable_removed_layer_handles()->Reserve(
176 static_cast<int32_t>(mRemovedLayerHandles.size()));
177 for (auto& handle : mRemovedLayerHandles) {
178 entryProto.mutable_removed_layer_handles()->Add(handle);
179 }
180 mRemovedLayerHandles.clear();
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800181 }
182
Vishnu Nair62863552021-12-10 13:34:48 -0800183 proto::TransactionTraceEntry removedEntryProto;
184 for (const std::string& removedEntry : removedEntries) {
185 removedEntryProto.ParseFromString(removedEntry);
186 updateStartingStateLocked(removedEntryProto);
187 removedEntryProto.Clear();
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800188 }
189 mTransactionsAddedToBufferCv.notify_one();
190}
191
192void TransactionTracing::flush(int64_t vsyncId) {
193 while (!mPendingTransactions.empty() || !mPendingRemovedLayers.empty()) {
194 tryPushToTracingThread();
195 }
196 std::unique_lock<std::mutex> lock(mTraceLock);
197 base::ScopedLockAssertion assumeLocked(mTraceLock);
198 mTransactionsAddedToBufferCv.wait(lock, [&]() REQUIRES(mTraceLock) {
Vishnu Nair62863552021-12-10 13:34:48 -0800199 proto::TransactionTraceEntry entry;
Dominik Laskowski46471e62022-01-14 15:34:03 -0800200 if (mBuffer.used() > 0) {
201 entry.ParseFromString(mBuffer.back());
Vishnu Nair62863552021-12-10 13:34:48 -0800202 }
Dominik Laskowski46471e62022-01-14 15:34:03 -0800203 return mBuffer.used() > 0 && entry.vsync_id() >= vsyncId;
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800204 });
205}
206
207void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name,
208 uint32_t flags, int parentId) {
209 std::scoped_lock lock(mTraceLock);
Vishnu Nair84125ac2021-12-02 08:47:48 -0800210 TracingLayerCreationArgs args{layerId, name, flags, parentId, -1 /* mirrorFromId */};
Vishnu Nair047fb332021-12-09 09:54:36 -0800211 if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) {
212 ALOGW("Duplicate handles found. %p", layerHandle);
213 }
Vishnu Nair84125ac2021-12-02 08:47:48 -0800214 mLayerHandles[layerHandle] = layerId;
215 proto::LayerCreationArgs protoArgs = TransactionProtoParser::toProto(args);
216 proto::LayerCreationArgs protoArgsCopy = protoArgs;
217 mCreatedLayers.push_back(protoArgs);
218}
219
220void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId,
221 const std::string& name, int mirrorFromId) {
222 std::scoped_lock lock(mTraceLock);
223 TracingLayerCreationArgs args{layerId, name, 0 /* flags */, -1 /* parentId */, mirrorFromId};
Vishnu Nair047fb332021-12-09 09:54:36 -0800224 if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) {
225 ALOGW("Duplicate handles found. %p", layerHandle);
226 }
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800227 mLayerHandles[layerHandle] = layerId;
228 mCreatedLayers.emplace_back(TransactionProtoParser::toProto(args));
229}
230
231void TransactionTracing::onLayerRemoved(int32_t layerId) {
232 mPendingRemovedLayers.emplace_back(layerId);
233 tryPushToTracingThread();
234}
235
Vishnu Nair047fb332021-12-09 09:54:36 -0800236void TransactionTracing::onHandleRemoved(BBinder* layerHandle) {
237 std::scoped_lock lock(mTraceLock);
Vishnu Naird37343b2022-01-12 16:18:56 -0800238 auto it = mLayerHandles.find(layerHandle);
239 if (it == mLayerHandles.end()) {
240 ALOGW("handle not found. %p", layerHandle);
241 return;
242 }
243
244 mRemovedLayerHandles.push_back(it->second);
245 mLayerHandles.erase(it);
Vishnu Nair047fb332021-12-09 09:54:36 -0800246}
247
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800248void TransactionTracing::tryPushToTracingThread() {
249 // Try to acquire the lock from main thread.
250 if (mMainThreadLock.try_lock()) {
251 // We got the lock! Collect any pending transactions and continue.
252 mCommittedTransactions.insert(mCommittedTransactions.end(),
253 std::make_move_iterator(mPendingTransactions.begin()),
254 std::make_move_iterator(mPendingTransactions.end()));
255 mPendingTransactions.clear();
256 mRemovedLayers.insert(mRemovedLayers.end(), mPendingRemovedLayers.begin(),
257 mPendingRemovedLayers.end());
258 mPendingRemovedLayers.clear();
259 mTransactionsAvailableCv.notify_one();
260 mMainThreadLock.unlock();
261 } else {
262 ALOGV("Couldn't get lock");
Vishnu Nair7891e962021-11-11 12:07:21 -0800263 }
264}
265
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800266int32_t TransactionTracing::getLayerIdLocked(const sp<IBinder>& layerHandle) {
267 if (layerHandle == nullptr) {
268 return -1;
269 }
270 auto it = mLayerHandles.find(layerHandle->localBinder());
Vishnu Nair047fb332021-12-09 09:54:36 -0800271 if (it == mLayerHandles.end()) {
272 ALOGW("Could not find layer handle %p", layerHandle->localBinder());
273 return -1;
274 }
275 return it->second;
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800276}
277
278void TransactionTracing::updateStartingStateLocked(
279 const proto::TransactionTraceEntry& removedEntry) {
Vishnu Nairb8f2a2d2022-01-13 08:10:10 -0800280 mStartingTimestamp = removedEntry.elapsed_realtime_nanos();
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800281 // Keep track of layer starting state so we can reconstruct the layer state as we purge
282 // transactions from the buffer.
283 for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) {
284 TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()];
285 startingState.layerId = addedLayer.layer_id();
Vishnu Nair84125ac2021-12-02 08:47:48 -0800286 TransactionProtoParser::fromProto(addedLayer, startingState.args);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800287 }
288
289 // Merge layer states to starting transaction state.
290 for (const proto::TransactionState& transaction : removedEntry.transactions()) {
291 for (const proto::LayerState& layerState : transaction.layer_changes()) {
292 auto it = mStartingStates.find(layerState.layer_id());
293 if (it == mStartingStates.end()) {
Vishnu Nair047fb332021-12-09 09:54:36 -0800294 ALOGW("Could not find layer id %d", layerState.layer_id());
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800295 continue;
296 }
Vishnu Nair7b0f18b2022-01-12 16:39:08 -0800297 TransactionProtoParser::mergeFromProto(layerState, nullptr, it->second);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800298 }
299 }
300
301 // Clean up stale starting states since the layer has been removed and the buffer does not
302 // contain any references to the layer.
303 for (const int32_t removedLayerId : removedEntry.removed_layers()) {
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800304 mStartingStates.erase(removedLayerId);
305 }
306}
307
308void TransactionTracing::addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) {
Vishnu Nair84125ac2021-12-02 08:47:48 -0800309 if (mStartingStates.size() == 0) {
310 return;
311 }
312
Vishnu Nairb8f2a2d2022-01-13 08:10:10 -0800313 proto::TransactionTraceEntry* entryProto = proto.add_entry();
314 entryProto->set_elapsed_realtime_nanos(mStartingTimestamp);
315 entryProto->set_vsync_id(0);
316
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800317 entryProto->mutable_added_layers()->Reserve(static_cast<int32_t>(mStartingStates.size()));
318 for (auto& [layerId, state] : mStartingStates) {
Vishnu Nair84125ac2021-12-02 08:47:48 -0800319 entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(state.args));
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800320 }
321
322 proto::TransactionState transactionProto = TransactionProtoParser::toProto(mStartingStates);
323 transactionProto.set_vsync_id(0);
324 transactionProto.set_post_time(mStartingTimestamp);
325 entryProto->mutable_transactions()->Add(std::move(transactionProto));
326}
327
328proto::TransactionTraceFile TransactionTracing::writeToProto() {
329 std::scoped_lock<std::mutex> lock(mTraceLock);
330 proto::TransactionTraceFile proto = createTraceFileProto();
331 addStartingStateToProtoLocked(proto);
Dominik Laskowski46471e62022-01-14 15:34:03 -0800332 mBuffer.writeToProto(proto);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800333 return proto;
Vishnu Nair7891e962021-11-11 12:07:21 -0800334}
335
336} // namespace android