blob: db78f1db2e09bfc3828306ca1164cfa45548109d [file] [log] [blame]
Adrian Roos1e1a1282017-11-01 19:05:31 +01001/*
2 * Copyright 2017 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#undef LOG_TAG
17#define LOG_TAG "SurfaceTracing"
18#define ATRACE_TAG ATRACE_TAG_GRAPHICS
19
20#include "SurfaceTracing.h"
Nataniel Borges2b796da2019-02-15 13:32:18 -080021#include <SurfaceFlinger.h>
Adrian Roos1e1a1282017-11-01 19:05:31 +010022
23#include <android-base/file.h>
Yiwei Zhang5434a782018-12-05 18:06:32 -080024#include <android-base/stringprintf.h>
Adrian Roos1e1a1282017-11-01 19:05:31 +010025#include <log/log.h>
26#include <utils/SystemClock.h>
27#include <utils/Trace.h>
28
29namespace android {
30
Nataniel Borges2b796da2019-02-15 13:32:18 -080031void SurfaceTracing::mainLoop() {
32 bool enabled = true;
33 // Upon activation, logs the first frame
34 traceLayers("tracing.enable");
35 do {
36 std::unique_lock<std::mutex> sfLock(mFlinger.mDrawingStateLock);
37 mConditionalVariable.wait(sfLock);
38 LayersTraceProto entry = traceLayersLocked(mWhere);
39 sfLock.unlock();
40 {
41 std::scoped_lock bufferLock(mTraceLock);
42 mBuffer.emplace(std::move(entry));
43 if (mWriteToFile) {
44 writeProtoFileLocked();
45 mWriteToFile = false;
46 }
47
48 enabled = mEnabled;
49 }
50 } while (enabled);
51}
52
53void SurfaceTracing::traceLayers(const char* where) {
54 std::unique_lock<std::mutex> sfLock(mFlinger.mDrawingStateLock);
55 LayersTraceProto entry = traceLayersLocked(where);
56 sfLock.unlock();
57 std::scoped_lock bufferLock(mTraceLock);
58 mBuffer.emplace(std::move(entry));
59}
60
61void SurfaceTracing::notify(const char* where) {
62 std::lock_guard<std::mutex> sfLock(mFlinger.mDrawingStateLock);
Vishnu Nairb0159482019-03-18 12:48:46 -070063 mWhere = where;
Nataniel Borges2b796da2019-02-15 13:32:18 -080064 mConditionalVariable.notify_one();
65}
66
67void SurfaceTracing::writeToFileAsync() {
68 std::lock_guard<std::mutex> bufferLock(mTraceLock);
69 mWriteToFile = true;
70 mConditionalVariable.notify_one();
71}
72
Yichi Chen9c696ed2018-10-01 22:32:30 +080073void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
74 // use the swap trick to make sure memory is released
75 std::queue<LayersTraceProto>().swap(mStorage);
76 mSizeInBytes = newSize;
77 mUsedInBytes = 0U;
78}
79
80void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) {
81 auto protoSize = proto.ByteSize();
82 while (mUsedInBytes + protoSize > mSizeInBytes) {
83 if (mStorage.empty()) {
84 return;
85 }
86 mUsedInBytes -= mStorage.front().ByteSize();
87 mStorage.pop();
88 }
89 mUsedInBytes += protoSize;
90 mStorage.emplace();
91 mStorage.back().Swap(&proto);
92}
93
94void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) {
95 fileProto->mutable_entry()->Reserve(mStorage.size());
96
97 while (!mStorage.empty()) {
98 auto entry = fileProto->add_entry();
99 entry->Swap(&mStorage.front());
100 mStorage.pop();
101 }
102}
103
Nataniel Borges2b796da2019-02-15 13:32:18 -0800104void SurfaceTracing::enable() {
105 std::lock_guard<std::mutex> bufferLock(mTraceLock);
Chia-I Wua3e7ddc2018-09-20 11:42:46 -0700106
Adrian Roos1e1a1282017-11-01 19:05:31 +0100107 if (mEnabled) {
108 return;
109 }
Nataniel Borges2b796da2019-02-15 13:32:18 -0800110
111 mBuffer.reset(mBufferSize);
Adrian Roos1e1a1282017-11-01 19:05:31 +0100112 mEnabled = true;
Nataniel Borges2b796da2019-02-15 13:32:18 -0800113 mThread = std::thread(&SurfaceTracing::mainLoop, this);
Adrian Roos1e1a1282017-11-01 19:05:31 +0100114}
115
Nataniel Borges2b796da2019-02-15 13:32:18 -0800116status_t SurfaceTracing::writeToFile() {
117 mThread.join();
118 return mLastErr;
119}
120
121bool SurfaceTracing::disable() {
122 std::lock_guard<std::mutex> bufferLock(mTraceLock);
Chia-I Wua3e7ddc2018-09-20 11:42:46 -0700123
Adrian Roos1e1a1282017-11-01 19:05:31 +0100124 if (!mEnabled) {
Nataniel Borges2b796da2019-02-15 13:32:18 -0800125 return false;
Adrian Roos1e1a1282017-11-01 19:05:31 +0100126 }
Nataniel Borges2b796da2019-02-15 13:32:18 -0800127
Adrian Roos1e1a1282017-11-01 19:05:31 +0100128 mEnabled = false;
Nataniel Borges2b796da2019-02-15 13:32:18 -0800129 mWriteToFile = true;
130 mConditionalVariable.notify_all();
131 return true;
Adrian Roos1e1a1282017-11-01 19:05:31 +0100132}
133
Yichi Chenadc69612018-09-15 14:51:18 +0800134bool SurfaceTracing::isEnabled() const {
Nataniel Borges2b796da2019-02-15 13:32:18 -0800135 std::lock_guard<std::mutex> bufferLock(mTraceLock);
Adrian Roos1e1a1282017-11-01 19:05:31 +0100136 return mEnabled;
137}
138
Nataniel Borges2b796da2019-02-15 13:32:18 -0800139void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) {
140 std::lock_guard<std::mutex> bufferLock(mTraceLock);
141 mBufferSize = bufferSizeInByte;
142 mBuffer.setSize(bufferSizeInByte);
143}
144
145LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
146 ATRACE_CALL();
Yichi Chenadc69612018-09-15 14:51:18 +0800147
Yichi Chen9c696ed2018-10-01 22:32:30 +0800148 LayersTraceProto entry;
149 entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
150 entry.set_where(where);
Nataniel Borges2b796da2019-02-15 13:32:18 -0800151 LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing));
Yichi Chen9c696ed2018-10-01 22:32:30 +0800152 entry.mutable_layers()->Swap(&layers);
153
Nataniel Borges2b796da2019-02-15 13:32:18 -0800154 return entry;
Adrian Roos1e1a1282017-11-01 19:05:31 +0100155}
156
Nataniel Borges2b796da2019-02-15 13:32:18 -0800157void SurfaceTracing::writeProtoFileLocked() {
Adrian Roos1e1a1282017-11-01 19:05:31 +0100158 ATRACE_CALL();
159
Yichi Chen9c696ed2018-10-01 22:32:30 +0800160 LayersTraceFileProto fileProto;
Adrian Roos1e1a1282017-11-01 19:05:31 +0100161 std::string output;
Yichi Chen9c696ed2018-10-01 22:32:30 +0800162
163 fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
164 LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
165 mBuffer.flush(&fileProto);
Nataniel Borges2b796da2019-02-15 13:32:18 -0800166 mBuffer.reset(mBufferSize);
Yichi Chen9c696ed2018-10-01 22:32:30 +0800167
168 if (!fileProto.SerializeToString(&output)) {
Nataniel Borges2b796da2019-02-15 13:32:18 -0800169 ALOGE("Could not save the proto file! Permission denied");
170 mLastErr = PERMISSION_DENIED;
Adrian Roos1e1a1282017-11-01 19:05:31 +0100171 }
Nataniel Borges2b796da2019-02-15 13:32:18 -0800172 if (!android::base::WriteStringToFile(output, kDefaultFileName, S_IRWXU | S_IRGRP, getuid(),
173 getgid(), true)) {
174 ALOGE("Could not save the proto file! There are missing fields");
175 mLastErr = PERMISSION_DENIED;
Adrian Roos1e1a1282017-11-01 19:05:31 +0100176 }
177
Nataniel Borges2b796da2019-02-15 13:32:18 -0800178 mLastErr = NO_ERROR;
Adrian Roos1e1a1282017-11-01 19:05:31 +0100179}
180
Yiwei Zhang5434a782018-12-05 18:06:32 -0800181void SurfaceTracing::dump(std::string& result) const {
Nataniel Borges2b796da2019-02-15 13:32:18 -0800182 std::lock_guard<std::mutex> bufferLock(mTraceLock);
Yichi Chenadc69612018-09-15 14:51:18 +0800183
Yiwei Zhang5434a782018-12-05 18:06:32 -0800184 base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
185 base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB)\n",
186 mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
187 float(mBuffer.size()) / float(1_MB));
Yichi Chenadc69612018-09-15 14:51:18 +0800188}
189
Adrian Roos1e1a1282017-11-01 19:05:31 +0100190} // namespace android