blob: c1b3d2e90e358e1287223061d3d1bebafd17e93a [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
26#include "RingBuffer.h"
27#include "TransactionTracing.h"
28
29namespace android {
30
31TransactionTracing::TransactionTracing() {
32 mBuffer = std::make_unique<
33 RingBuffer<proto::TransactionTraceFile, proto::TransactionTraceEntry>>();
34}
35
36TransactionTracing::~TransactionTracing() = default;
37
38bool TransactionTracing::enable() {
39 std::scoped_lock lock(mTraceLock);
40 if (mEnabled) {
41 return false;
42 }
43 mBuffer->setSize(mBufferSizeInBytes);
Vishnu Nair0cc69e12021-11-18 09:05:49 -080044 mStartingTimestamp = systemTime();
Vishnu Nair7891e962021-11-11 12:07:21 -080045 mEnabled = true;
46 {
47 std::scoped_lock lock(mMainThreadLock);
48 mDone = false;
49 mThread = std::thread(&TransactionTracing::loop, this);
50 }
51 return true;
52}
53
54bool TransactionTracing::disable() {
55 std::thread thread;
56 {
57 std::scoped_lock lock(mMainThreadLock);
58 mDone = true;
59 mTransactionsAvailableCv.notify_all();
60 thread = std::move(mThread);
61 }
62 if (thread.joinable()) {
63 thread.join();
64 }
65
66 std::scoped_lock lock(mTraceLock);
67 if (!mEnabled) {
68 return false;
69 }
70 mEnabled = false;
71
Vishnu Nair0cc69e12021-11-18 09:05:49 -080072 writeToFileLocked();
73 mBuffer->reset();
Vishnu Nair7891e962021-11-11 12:07:21 -080074 mQueuedTransactions.clear();
Vishnu Nair0cc69e12021-11-18 09:05:49 -080075 mStartingStates.clear();
76 mLayerHandles.clear();
Vishnu Nair7891e962021-11-11 12:07:21 -080077 return true;
78}
79
80bool TransactionTracing::isEnabled() const {
81 std::scoped_lock lock(mTraceLock);
82 return mEnabled;
83}
84
85status_t TransactionTracing::writeToFile() {
86 std::scoped_lock lock(mTraceLock);
87 if (!mEnabled) {
88 return STATUS_OK;
89 }
Vishnu Nair0cc69e12021-11-18 09:05:49 -080090 return writeToFileLocked();
91}
92
93status_t TransactionTracing::writeToFileLocked() {
Vishnu Nair7891e962021-11-11 12:07:21 -080094 proto::TransactionTraceFile fileProto = createTraceFileProto();
Vishnu Nair0cc69e12021-11-18 09:05:49 -080095 addStartingStateToProtoLocked(fileProto);
Vishnu Nair7891e962021-11-11 12:07:21 -080096 return mBuffer->writeToFile(fileProto, FILE_NAME);
97}
98
99void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) {
100 std::scoped_lock lock(mTraceLock);
101 mBufferSizeInBytes = bufferSizeInBytes;
102 mBuffer->setSize(mBufferSizeInBytes);
103}
104
105proto::TransactionTraceFile TransactionTracing::createTraceFileProto() const {
106 proto::TransactionTraceFile proto;
107 proto.set_magic_number(uint64_t(proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_H) << 32 |
108 proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_L);
109 return proto;
110}
111
112void TransactionTracing::dump(std::string& result) const {
113 std::scoped_lock lock(mTraceLock);
114 base::StringAppendF(&result, "Transaction tracing state: %s\n",
115 mEnabled ? "enabled" : "disabled");
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800116 base::StringAppendF(&result,
117 " queued transactions=%zu created layers=%zu handles=%zu states=%zu\n",
118 mQueuedTransactions.size(), mCreatedLayers.size(), mLayerHandles.size(),
119 mStartingStates.size());
Vishnu Nair7891e962021-11-11 12:07:21 -0800120 mBuffer->dump(result);
121}
122
123void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
124 std::scoped_lock lock(mTraceLock);
125 ATRACE_CALL();
126 if (!mEnabled) {
127 return;
128 }
129 mQueuedTransactions[transaction.id] =
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800130 TransactionProtoParser::toProto(transaction,
131 std::bind(&TransactionTracing::getLayerIdLocked, this,
132 std::placeholders::_1),
133 nullptr);
Vishnu Nair7891e962021-11-11 12:07:21 -0800134}
135
136void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
137 int64_t vsyncId) {
138 CommittedTransactions committedTransactions;
139 committedTransactions.vsyncId = vsyncId;
140 committedTransactions.timestamp = systemTime();
141 committedTransactions.transactionIds.reserve(transactions.size());
142 for (const auto& transaction : transactions) {
143 committedTransactions.transactionIds.emplace_back(transaction.id);
144 }
145
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800146 mPendingTransactions.emplace_back(committedTransactions);
147 tryPushToTracingThread();
Vishnu Nair7891e962021-11-11 12:07:21 -0800148}
149
150void TransactionTracing::loop() {
151 while (true) {
152 std::vector<CommittedTransactions> committedTransactions;
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800153 std::vector<int32_t> removedLayers;
Vishnu Nair7891e962021-11-11 12:07:21 -0800154 {
155 std::unique_lock<std::mutex> lock(mMainThreadLock);
156 base::ScopedLockAssertion assumeLocked(mMainThreadLock);
157 mTransactionsAvailableCv.wait(lock, [&]() REQUIRES(mMainThreadLock) {
158 return mDone || !mCommittedTransactions.empty();
159 });
160 if (mDone) {
161 mCommittedTransactions.clear();
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800162 mRemovedLayers.clear();
Vishnu Nair7891e962021-11-11 12:07:21 -0800163 break;
164 }
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800165
166 removedLayers = std::move(mRemovedLayers);
167 mRemovedLayers.clear();
Vishnu Nair7891e962021-11-11 12:07:21 -0800168 committedTransactions = std::move(mCommittedTransactions);
169 mCommittedTransactions.clear();
170 } // unlock mMainThreadLock
171
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800172 addEntry(committedTransactions, removedLayers);
Vishnu Nair7891e962021-11-11 12:07:21 -0800173 }
174}
175
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800176void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& committedTransactions,
177 const std::vector<int32_t>& removedLayers) {
Vishnu Nair7891e962021-11-11 12:07:21 -0800178 ATRACE_CALL();
179 std::scoped_lock lock(mTraceLock);
180 std::vector<proto::TransactionTraceEntry> removedEntries;
181 for (const CommittedTransactions& entry : committedTransactions) {
182 proto::TransactionTraceEntry entryProto;
183 entryProto.set_elapsed_realtime_nanos(entry.timestamp);
184 entryProto.set_vsync_id(entry.vsyncId);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800185 entryProto.mutable_added_layers()->Reserve(static_cast<int32_t>(mCreatedLayers.size()));
186 for (auto& newLayer : mCreatedLayers) {
187 entryProto.mutable_added_layers()->Add(std::move(newLayer));
188 }
189 entryProto.mutable_removed_layers()->Reserve(static_cast<int32_t>(removedLayers.size()));
190 for (auto& removedLayer : removedLayers) {
191 entryProto.mutable_removed_layers()->Add(removedLayer);
192 }
193 mCreatedLayers.clear();
Vishnu Nair7891e962021-11-11 12:07:21 -0800194 entryProto.mutable_transactions()->Reserve(
195 static_cast<int32_t>(entry.transactionIds.size()));
196 for (const uint64_t& id : entry.transactionIds) {
197 auto it = mQueuedTransactions.find(id);
198 if (it != mQueuedTransactions.end()) {
199 entryProto.mutable_transactions()->Add(std::move(it->second));
200 mQueuedTransactions.erase(it);
201 } else {
Vishnu Nair047fb332021-12-09 09:54:36 -0800202 ALOGW("Could not find transaction id %" PRIu64, id);
Vishnu Nair7891e962021-11-11 12:07:21 -0800203 }
204 }
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800205 std::vector<proto::TransactionTraceEntry> entries = mBuffer->emplace(std::move(entryProto));
206 removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()),
207 std::make_move_iterator(entries.end()));
208 }
209
210 for (const proto::TransactionTraceEntry& removedEntry : removedEntries) {
211 updateStartingStateLocked(removedEntry);
212 }
213 mTransactionsAddedToBufferCv.notify_one();
214}
215
216void TransactionTracing::flush(int64_t vsyncId) {
217 while (!mPendingTransactions.empty() || !mPendingRemovedLayers.empty()) {
218 tryPushToTracingThread();
219 }
220 std::unique_lock<std::mutex> lock(mTraceLock);
221 base::ScopedLockAssertion assumeLocked(mTraceLock);
222 mTransactionsAddedToBufferCv.wait(lock, [&]() REQUIRES(mTraceLock) {
223 return mBuffer->used() > 0 && mBuffer->back().vsync_id() >= vsyncId;
224 });
225}
226
227void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name,
228 uint32_t flags, int parentId) {
229 std::scoped_lock lock(mTraceLock);
Vishnu Nair84125ac2021-12-02 08:47:48 -0800230 TracingLayerCreationArgs args{layerId, name, flags, parentId, -1 /* mirrorFromId */};
Vishnu Nair047fb332021-12-09 09:54:36 -0800231 if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) {
232 ALOGW("Duplicate handles found. %p", layerHandle);
233 }
Vishnu Nair84125ac2021-12-02 08:47:48 -0800234 mLayerHandles[layerHandle] = layerId;
235 proto::LayerCreationArgs protoArgs = TransactionProtoParser::toProto(args);
236 proto::LayerCreationArgs protoArgsCopy = protoArgs;
237 mCreatedLayers.push_back(protoArgs);
238}
239
240void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId,
241 const std::string& name, int mirrorFromId) {
242 std::scoped_lock lock(mTraceLock);
243 TracingLayerCreationArgs args{layerId, name, 0 /* flags */, -1 /* parentId */, mirrorFromId};
Vishnu Nair047fb332021-12-09 09:54:36 -0800244 if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) {
245 ALOGW("Duplicate handles found. %p", layerHandle);
246 }
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800247 mLayerHandles[layerHandle] = layerId;
248 mCreatedLayers.emplace_back(TransactionProtoParser::toProto(args));
249}
250
251void TransactionTracing::onLayerRemoved(int32_t layerId) {
252 mPendingRemovedLayers.emplace_back(layerId);
253 tryPushToTracingThread();
254}
255
Vishnu Nair047fb332021-12-09 09:54:36 -0800256void TransactionTracing::onHandleRemoved(BBinder* layerHandle) {
257 std::scoped_lock lock(mTraceLock);
258 mLayerHandles.erase(layerHandle);
259}
260
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800261void TransactionTracing::tryPushToTracingThread() {
262 // Try to acquire the lock from main thread.
263 if (mMainThreadLock.try_lock()) {
264 // We got the lock! Collect any pending transactions and continue.
265 mCommittedTransactions.insert(mCommittedTransactions.end(),
266 std::make_move_iterator(mPendingTransactions.begin()),
267 std::make_move_iterator(mPendingTransactions.end()));
268 mPendingTransactions.clear();
269 mRemovedLayers.insert(mRemovedLayers.end(), mPendingRemovedLayers.begin(),
270 mPendingRemovedLayers.end());
271 mPendingRemovedLayers.clear();
272 mTransactionsAvailableCv.notify_one();
273 mMainThreadLock.unlock();
274 } else {
275 ALOGV("Couldn't get lock");
Vishnu Nair7891e962021-11-11 12:07:21 -0800276 }
277}
278
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800279int32_t TransactionTracing::getLayerIdLocked(const sp<IBinder>& layerHandle) {
280 if (layerHandle == nullptr) {
281 return -1;
282 }
283 auto it = mLayerHandles.find(layerHandle->localBinder());
Vishnu Nair047fb332021-12-09 09:54:36 -0800284 if (it == mLayerHandles.end()) {
285 ALOGW("Could not find layer handle %p", layerHandle->localBinder());
286 return -1;
287 }
288 return it->second;
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800289}
290
291void TransactionTracing::updateStartingStateLocked(
292 const proto::TransactionTraceEntry& removedEntry) {
293 // Keep track of layer starting state so we can reconstruct the layer state as we purge
294 // transactions from the buffer.
295 for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) {
296 TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()];
297 startingState.layerId = addedLayer.layer_id();
Vishnu Nair84125ac2021-12-02 08:47:48 -0800298 TransactionProtoParser::fromProto(addedLayer, startingState.args);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800299 }
300
301 // Merge layer states to starting transaction state.
302 for (const proto::TransactionState& transaction : removedEntry.transactions()) {
303 for (const proto::LayerState& layerState : transaction.layer_changes()) {
304 auto it = mStartingStates.find(layerState.layer_id());
305 if (it == mStartingStates.end()) {
Vishnu Nair047fb332021-12-09 09:54:36 -0800306 ALOGW("Could not find layer id %d", layerState.layer_id());
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800307 continue;
308 }
309 TransactionProtoParser::fromProto(layerState, nullptr, it->second);
310 }
311 }
312
313 // Clean up stale starting states since the layer has been removed and the buffer does not
314 // contain any references to the layer.
315 for (const int32_t removedLayerId : removedEntry.removed_layers()) {
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800316 mStartingStates.erase(removedLayerId);
317 }
318}
319
320void TransactionTracing::addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) {
321 proto::TransactionTraceEntry* entryProto = proto.add_entry();
322 entryProto->set_elapsed_realtime_nanos(mStartingTimestamp);
323 entryProto->set_vsync_id(0);
Vishnu Nair84125ac2021-12-02 08:47:48 -0800324 if (mStartingStates.size() == 0) {
325 return;
326 }
327
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800328 entryProto->mutable_added_layers()->Reserve(static_cast<int32_t>(mStartingStates.size()));
329 for (auto& [layerId, state] : mStartingStates) {
Vishnu Nair84125ac2021-12-02 08:47:48 -0800330 entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(state.args));
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800331 }
332
333 proto::TransactionState transactionProto = TransactionProtoParser::toProto(mStartingStates);
334 transactionProto.set_vsync_id(0);
335 transactionProto.set_post_time(mStartingTimestamp);
336 entryProto->mutable_transactions()->Add(std::move(transactionProto));
337}
338
339proto::TransactionTraceFile TransactionTracing::writeToProto() {
340 std::scoped_lock<std::mutex> lock(mTraceLock);
341 proto::TransactionTraceFile proto = createTraceFileProto();
342 addStartingStateToProtoLocked(proto);
343 mBuffer->writeToProto(proto);
344 return proto;
Vishnu Nair7891e962021-11-11 12:07:21 -0800345}
346
347} // namespace android