blob: d5e837f8792cb55f316456851745d6042c7bf509 [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 Nair685cfef2022-02-02 10:01:25 -080026#include "ClientCache.h"
Vishnu Nair7891e962021-11-11 12:07:21 -080027#include "TransactionTracing.h"
Vishnu Nair685cfef2022-02-02 10:01:25 -080028#include "renderengine/ExternalTexture.h"
Vishnu Nair7891e962021-11-11 12:07:21 -080029
30namespace android {
31
Vishnu Nair685cfef2022-02-02 10:01:25 -080032class FlingerDataMapper : public TransactionProtoParser::FlingerDataMapper {
33 std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */>& mLayerHandles;
34
35public:
36 FlingerDataMapper(std::unordered_map<BBinder* /* handle */, int32_t /* id */>& layerHandles)
37 : mLayerHandles(layerHandles) {}
38
39 int32_t getLayerId(const sp<IBinder>& layerHandle) const override {
40 if (layerHandle == nullptr) {
41 return -1;
42 }
43 auto it = mLayerHandles.find(layerHandle->localBinder());
44 if (it == mLayerHandles.end()) {
45 ALOGW("Could not find layer handle %p", layerHandle->localBinder());
46 return -1;
47 }
48 return it->second;
49 }
50
51 void getGraphicBufferPropertiesFromCache(client_cache_t cachedBuffer, uint64_t* outBufferId,
52 uint32_t* outWidth, uint32_t* outHeight,
53 int32_t* outPixelFormat,
54 uint64_t* outUsage) const override {
55 std::shared_ptr<renderengine::ExternalTexture> buffer =
56 ClientCache::getInstance().get(cachedBuffer);
57 if (!buffer || !buffer->getBuffer()) {
58 *outBufferId = 0;
59 *outWidth = 0;
60 *outHeight = 0;
61 *outPixelFormat = 0;
62 *outUsage = 0;
63 return;
64 }
65
66 *outBufferId = buffer->getId();
67 *outWidth = buffer->getWidth();
68 *outHeight = buffer->getHeight();
69 *outPixelFormat = buffer->getPixelFormat();
70 *outUsage = buffer->getUsage();
71 return;
72 }
73};
74
75TransactionTracing::TransactionTracing()
76 : mProtoParser(std::make_unique<FlingerDataMapper>(mLayerHandles)) {
Vishnu Nair7891e962021-11-11 12:07:21 -080077 std::scoped_lock lock(mTraceLock);
Dominik Laskowski46471e62022-01-14 15:34:03 -080078
79 mBuffer.setSize(mBufferSizeInBytes);
Vishnu Nair0cc69e12021-11-18 09:05:49 -080080 mStartingTimestamp = systemTime();
Vishnu Nair7891e962021-11-11 12:07:21 -080081 {
82 std::scoped_lock lock(mMainThreadLock);
Vishnu Nair7891e962021-11-11 12:07:21 -080083 mThread = std::thread(&TransactionTracing::loop, this);
84 }
Vishnu Nair7891e962021-11-11 12:07:21 -080085}
86
Dominik Laskowski46471e62022-01-14 15:34:03 -080087TransactionTracing::~TransactionTracing() {
Vishnu Nair7891e962021-11-11 12:07:21 -080088 std::thread thread;
89 {
90 std::scoped_lock lock(mMainThreadLock);
91 mDone = true;
92 mTransactionsAvailableCv.notify_all();
93 thread = std::move(mThread);
94 }
95 if (thread.joinable()) {
96 thread.join();
97 }
98
Dominik Laskowski46471e62022-01-14 15:34:03 -080099 writeToFile();
Vishnu Nair7891e962021-11-11 12:07:21 -0800100}
101
Vishnu Naird8f5e9f2022-02-03 10:23:28 -0800102status_t TransactionTracing::writeToFile(std::string filename) {
Vishnu Nair7891e962021-11-11 12:07:21 -0800103 std::scoped_lock lock(mTraceLock);
Vishnu Nair7891e962021-11-11 12:07:21 -0800104 proto::TransactionTraceFile fileProto = createTraceFileProto();
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800105 addStartingStateToProtoLocked(fileProto);
Vishnu Naird8f5e9f2022-02-03 10:23:28 -0800106 return mBuffer.writeToFile(fileProto, filename);
Vishnu Nair7891e962021-11-11 12:07:21 -0800107}
108
109void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) {
110 std::scoped_lock lock(mTraceLock);
111 mBufferSizeInBytes = bufferSizeInBytes;
Dominik Laskowski46471e62022-01-14 15:34:03 -0800112 mBuffer.setSize(mBufferSizeInBytes);
Vishnu Nair7891e962021-11-11 12:07:21 -0800113}
114
115proto::TransactionTraceFile TransactionTracing::createTraceFileProto() const {
116 proto::TransactionTraceFile proto;
117 proto.set_magic_number(uint64_t(proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_H) << 32 |
118 proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_L);
119 return proto;
120}
121
122void TransactionTracing::dump(std::string& result) const {
123 std::scoped_lock lock(mTraceLock);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800124 base::StringAppendF(&result,
125 " queued transactions=%zu created layers=%zu handles=%zu states=%zu\n",
126 mQueuedTransactions.size(), mCreatedLayers.size(), mLayerHandles.size(),
127 mStartingStates.size());
Dominik Laskowski46471e62022-01-14 15:34:03 -0800128 mBuffer.dump(result);
Vishnu Nair7891e962021-11-11 12:07:21 -0800129}
130
131void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
132 std::scoped_lock lock(mTraceLock);
133 ATRACE_CALL();
Vishnu Nair685cfef2022-02-02 10:01:25 -0800134 mQueuedTransactions[transaction.id] = mProtoParser.toProto(transaction);
Vishnu Nair7891e962021-11-11 12:07:21 -0800135}
136
137void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
138 int64_t vsyncId) {
139 CommittedTransactions committedTransactions;
140 committedTransactions.vsyncId = vsyncId;
141 committedTransactions.timestamp = systemTime();
142 committedTransactions.transactionIds.reserve(transactions.size());
143 for (const auto& transaction : transactions) {
144 committedTransactions.transactionIds.emplace_back(transaction.id);
145 }
146
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800147 mPendingTransactions.emplace_back(committedTransactions);
148 tryPushToTracingThread();
Vishnu Nair7891e962021-11-11 12:07:21 -0800149}
150
151void TransactionTracing::loop() {
152 while (true) {
153 std::vector<CommittedTransactions> committedTransactions;
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800154 std::vector<int32_t> removedLayers;
Vishnu Nair7891e962021-11-11 12:07:21 -0800155 {
156 std::unique_lock<std::mutex> lock(mMainThreadLock);
157 base::ScopedLockAssertion assumeLocked(mMainThreadLock);
158 mTransactionsAvailableCv.wait(lock, [&]() REQUIRES(mMainThreadLock) {
159 return mDone || !mCommittedTransactions.empty();
160 });
161 if (mDone) {
162 mCommittedTransactions.clear();
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800163 mRemovedLayers.clear();
Vishnu Nair7891e962021-11-11 12:07:21 -0800164 break;
165 }
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800166
167 removedLayers = std::move(mRemovedLayers);
168 mRemovedLayers.clear();
Vishnu Nair7891e962021-11-11 12:07:21 -0800169 committedTransactions = std::move(mCommittedTransactions);
170 mCommittedTransactions.clear();
171 } // unlock mMainThreadLock
172
Vishnu Nairb8f2a2d2022-01-13 08:10:10 -0800173 if (!committedTransactions.empty() || !removedLayers.empty()) {
174 addEntry(committedTransactions, removedLayers);
175 }
Vishnu Nair7891e962021-11-11 12:07:21 -0800176 }
177}
178
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800179void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& committedTransactions,
180 const std::vector<int32_t>& removedLayers) {
Vishnu Nair7891e962021-11-11 12:07:21 -0800181 ATRACE_CALL();
182 std::scoped_lock lock(mTraceLock);
Vishnu Nair62863552021-12-10 13:34:48 -0800183 std::vector<std::string> removedEntries;
184 proto::TransactionTraceEntry entryProto;
Vishnu Nair7891e962021-11-11 12:07:21 -0800185 for (const CommittedTransactions& entry : committedTransactions) {
Vishnu Nair7891e962021-11-11 12:07:21 -0800186 entryProto.set_elapsed_realtime_nanos(entry.timestamp);
187 entryProto.set_vsync_id(entry.vsyncId);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800188 entryProto.mutable_added_layers()->Reserve(static_cast<int32_t>(mCreatedLayers.size()));
189 for (auto& newLayer : mCreatedLayers) {
190 entryProto.mutable_added_layers()->Add(std::move(newLayer));
191 }
192 entryProto.mutable_removed_layers()->Reserve(static_cast<int32_t>(removedLayers.size()));
193 for (auto& removedLayer : removedLayers) {
194 entryProto.mutable_removed_layers()->Add(removedLayer);
195 }
196 mCreatedLayers.clear();
Vishnu Nair7891e962021-11-11 12:07:21 -0800197 entryProto.mutable_transactions()->Reserve(
198 static_cast<int32_t>(entry.transactionIds.size()));
199 for (const uint64_t& id : entry.transactionIds) {
200 auto it = mQueuedTransactions.find(id);
201 if (it != mQueuedTransactions.end()) {
202 entryProto.mutable_transactions()->Add(std::move(it->second));
203 mQueuedTransactions.erase(it);
204 } else {
Vishnu Nair047fb332021-12-09 09:54:36 -0800205 ALOGW("Could not find transaction id %" PRIu64, id);
Vishnu Nair7891e962021-11-11 12:07:21 -0800206 }
207 }
Vishnu Nair62863552021-12-10 13:34:48 -0800208
209 std::string serializedProto;
210 entryProto.SerializeToString(&serializedProto);
211 entryProto.Clear();
Dominik Laskowski46471e62022-01-14 15:34:03 -0800212 std::vector<std::string> entries = mBuffer.emplace(std::move(serializedProto));
Vishnu Nair62863552021-12-10 13:34:48 -0800213 removedEntries.reserve(removedEntries.size() + entries.size());
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800214 removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()),
215 std::make_move_iterator(entries.end()));
Vishnu Naird37343b2022-01-12 16:18:56 -0800216
217 entryProto.mutable_removed_layer_handles()->Reserve(
218 static_cast<int32_t>(mRemovedLayerHandles.size()));
219 for (auto& handle : mRemovedLayerHandles) {
220 entryProto.mutable_removed_layer_handles()->Add(handle);
221 }
222 mRemovedLayerHandles.clear();
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800223 }
224
Vishnu Nair62863552021-12-10 13:34:48 -0800225 proto::TransactionTraceEntry removedEntryProto;
226 for (const std::string& removedEntry : removedEntries) {
227 removedEntryProto.ParseFromString(removedEntry);
228 updateStartingStateLocked(removedEntryProto);
229 removedEntryProto.Clear();
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800230 }
231 mTransactionsAddedToBufferCv.notify_one();
232}
233
234void TransactionTracing::flush(int64_t vsyncId) {
235 while (!mPendingTransactions.empty() || !mPendingRemovedLayers.empty()) {
236 tryPushToTracingThread();
237 }
238 std::unique_lock<std::mutex> lock(mTraceLock);
239 base::ScopedLockAssertion assumeLocked(mTraceLock);
240 mTransactionsAddedToBufferCv.wait(lock, [&]() REQUIRES(mTraceLock) {
Vishnu Nair62863552021-12-10 13:34:48 -0800241 proto::TransactionTraceEntry entry;
Dominik Laskowski46471e62022-01-14 15:34:03 -0800242 if (mBuffer.used() > 0) {
243 entry.ParseFromString(mBuffer.back());
Vishnu Nair62863552021-12-10 13:34:48 -0800244 }
Dominik Laskowski46471e62022-01-14 15:34:03 -0800245 return mBuffer.used() > 0 && entry.vsync_id() >= vsyncId;
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800246 });
247}
248
249void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name,
250 uint32_t flags, int parentId) {
251 std::scoped_lock lock(mTraceLock);
Vishnu Nair84125ac2021-12-02 08:47:48 -0800252 TracingLayerCreationArgs args{layerId, name, flags, parentId, -1 /* mirrorFromId */};
Vishnu Nair047fb332021-12-09 09:54:36 -0800253 if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) {
254 ALOGW("Duplicate handles found. %p", layerHandle);
255 }
Vishnu Nair84125ac2021-12-02 08:47:48 -0800256 mLayerHandles[layerHandle] = layerId;
Vishnu Nair685cfef2022-02-02 10:01:25 -0800257 mCreatedLayers.push_back(mProtoParser.toProto(args));
Vishnu Nair84125ac2021-12-02 08:47:48 -0800258}
259
260void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId,
261 const std::string& name, int mirrorFromId) {
262 std::scoped_lock lock(mTraceLock);
263 TracingLayerCreationArgs args{layerId, name, 0 /* flags */, -1 /* parentId */, mirrorFromId};
Vishnu Nair047fb332021-12-09 09:54:36 -0800264 if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) {
265 ALOGW("Duplicate handles found. %p", layerHandle);
266 }
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800267 mLayerHandles[layerHandle] = layerId;
Vishnu Nair685cfef2022-02-02 10:01:25 -0800268 mCreatedLayers.emplace_back(mProtoParser.toProto(args));
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800269}
270
271void TransactionTracing::onLayerRemoved(int32_t layerId) {
272 mPendingRemovedLayers.emplace_back(layerId);
273 tryPushToTracingThread();
274}
275
Vishnu Nair047fb332021-12-09 09:54:36 -0800276void TransactionTracing::onHandleRemoved(BBinder* layerHandle) {
277 std::scoped_lock lock(mTraceLock);
Vishnu Naird37343b2022-01-12 16:18:56 -0800278 auto it = mLayerHandles.find(layerHandle);
279 if (it == mLayerHandles.end()) {
280 ALOGW("handle not found. %p", layerHandle);
281 return;
282 }
283
284 mRemovedLayerHandles.push_back(it->second);
285 mLayerHandles.erase(it);
Vishnu Nair047fb332021-12-09 09:54:36 -0800286}
287
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800288void TransactionTracing::tryPushToTracingThread() {
289 // Try to acquire the lock from main thread.
290 if (mMainThreadLock.try_lock()) {
291 // We got the lock! Collect any pending transactions and continue.
292 mCommittedTransactions.insert(mCommittedTransactions.end(),
293 std::make_move_iterator(mPendingTransactions.begin()),
294 std::make_move_iterator(mPendingTransactions.end()));
295 mPendingTransactions.clear();
296 mRemovedLayers.insert(mRemovedLayers.end(), mPendingRemovedLayers.begin(),
297 mPendingRemovedLayers.end());
298 mPendingRemovedLayers.clear();
299 mTransactionsAvailableCv.notify_one();
300 mMainThreadLock.unlock();
301 } else {
302 ALOGV("Couldn't get lock");
Vishnu Nair7891e962021-11-11 12:07:21 -0800303 }
304}
305
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800306void TransactionTracing::updateStartingStateLocked(
307 const proto::TransactionTraceEntry& removedEntry) {
Vishnu Nairb8f2a2d2022-01-13 08:10:10 -0800308 mStartingTimestamp = removedEntry.elapsed_realtime_nanos();
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800309 // Keep track of layer starting state so we can reconstruct the layer state as we purge
310 // transactions from the buffer.
311 for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) {
312 TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()];
313 startingState.layerId = addedLayer.layer_id();
Vishnu Nair685cfef2022-02-02 10:01:25 -0800314 mProtoParser.fromProto(addedLayer, startingState.args);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800315 }
316
317 // Merge layer states to starting transaction state.
318 for (const proto::TransactionState& transaction : removedEntry.transactions()) {
319 for (const proto::LayerState& layerState : transaction.layer_changes()) {
320 auto it = mStartingStates.find(layerState.layer_id());
321 if (it == mStartingStates.end()) {
Vishnu Nair047fb332021-12-09 09:54:36 -0800322 ALOGW("Could not find layer id %d", layerState.layer_id());
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800323 continue;
324 }
Vishnu Nair685cfef2022-02-02 10:01:25 -0800325 mProtoParser.mergeFromProto(layerState, it->second);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800326 }
327 }
328
329 // Clean up stale starting states since the layer has been removed and the buffer does not
330 // contain any references to the layer.
331 for (const int32_t removedLayerId : removedEntry.removed_layers()) {
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800332 mStartingStates.erase(removedLayerId);
333 }
334}
335
336void TransactionTracing::addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) {
Vishnu Nair84125ac2021-12-02 08:47:48 -0800337 if (mStartingStates.size() == 0) {
338 return;
339 }
340
Vishnu Nairb8f2a2d2022-01-13 08:10:10 -0800341 proto::TransactionTraceEntry* entryProto = proto.add_entry();
342 entryProto->set_elapsed_realtime_nanos(mStartingTimestamp);
343 entryProto->set_vsync_id(0);
344
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800345 entryProto->mutable_added_layers()->Reserve(static_cast<int32_t>(mStartingStates.size()));
346 for (auto& [layerId, state] : mStartingStates) {
Vishnu Nair685cfef2022-02-02 10:01:25 -0800347 entryProto->mutable_added_layers()->Add(mProtoParser.toProto(state.args));
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800348 }
349
Vishnu Nair685cfef2022-02-02 10:01:25 -0800350 proto::TransactionState transactionProto = mProtoParser.toProto(mStartingStates);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800351 transactionProto.set_vsync_id(0);
352 transactionProto.set_post_time(mStartingTimestamp);
353 entryProto->mutable_transactions()->Add(std::move(transactionProto));
354}
355
356proto::TransactionTraceFile TransactionTracing::writeToProto() {
357 std::scoped_lock<std::mutex> lock(mTraceLock);
358 proto::TransactionTraceFile proto = createTraceFileProto();
359 addStartingStateToProtoLocked(proto);
Dominik Laskowski46471e62022-01-14 15:34:03 -0800360 mBuffer.writeToProto(proto);
Vishnu Nair0cc69e12021-11-18 09:05:49 -0800361 return proto;
Vishnu Nair7891e962021-11-11 12:07:21 -0800362}
363
364} // namespace android