1 /*
2 * Copyright (C) 2012 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 // TODO(b/129481165): remove the #pragma below and fix conversion issues
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wconversion"
20
21 #include <inttypes.h>
22
23 #include <android-base/stringprintf.h>
24 #include <android/log.h>
25
26 #include <ui/FrameStats.h>
27
28 #include "FrameTracker.h"
29
30 namespace android {
31
FrameTracker()32 FrameTracker::FrameTracker() : mOffset(0), mNumFences(0), mDisplayPeriod(0) {}
33
setDesiredPresentTime(nsecs_t presentTime)34 void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) {
35 Mutex::Autolock lock(mMutex);
36 mFrameRecords[mOffset].desiredPresentTime = presentTime;
37 }
38
setFrameReadyTime(nsecs_t readyTime)39 void FrameTracker::setFrameReadyTime(nsecs_t readyTime) {
40 Mutex::Autolock lock(mMutex);
41 mFrameRecords[mOffset].frameReadyTime = readyTime;
42 }
43
setFrameReadyFence(std::shared_ptr<FenceTime> && readyFence)44 void FrameTracker::setFrameReadyFence(
45 std::shared_ptr<FenceTime>&& readyFence) {
46 Mutex::Autolock lock(mMutex);
47 mFrameRecords[mOffset].frameReadyFence = std::move(readyFence);
48 mNumFences++;
49 }
50
setActualPresentTime(nsecs_t presentTime)51 void FrameTracker::setActualPresentTime(nsecs_t presentTime) {
52 Mutex::Autolock lock(mMutex);
53 mFrameRecords[mOffset].actualPresentTime = presentTime;
54 }
55
setActualPresentFence(const std::shared_ptr<FenceTime> & readyFence)56 void FrameTracker::setActualPresentFence(const std::shared_ptr<FenceTime>& readyFence) {
57 Mutex::Autolock lock(mMutex);
58 mFrameRecords[mOffset].actualPresentFence = readyFence;
59 mNumFences++;
60 }
61
setDisplayRefreshPeriod(nsecs_t displayPeriod)62 void FrameTracker::setDisplayRefreshPeriod(nsecs_t displayPeriod) {
63 Mutex::Autolock lock(mMutex);
64 mDisplayPeriod = displayPeriod;
65 }
66
advanceFrame()67 void FrameTracker::advanceFrame() {
68 Mutex::Autolock lock(mMutex);
69
70 // Advance to the next frame.
71 mOffset = (mOffset+1) % NUM_FRAME_RECORDS;
72 mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
73 mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
74 mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
75
76 if (mFrameRecords[mOffset].frameReadyFence != nullptr) {
77 // We're clobbering an unsignaled fence, so we need to decrement the
78 // fence count.
79 mFrameRecords[mOffset].frameReadyFence = nullptr;
80 mNumFences--;
81 }
82
83 if (mFrameRecords[mOffset].actualPresentFence != nullptr) {
84 // We're clobbering an unsignaled fence, so we need to decrement the
85 // fence count.
86 mFrameRecords[mOffset].actualPresentFence = nullptr;
87 mNumFences--;
88 }
89 }
90
clearStats()91 void FrameTracker::clearStats() {
92 Mutex::Autolock lock(mMutex);
93 for (size_t i = 0; i < NUM_FRAME_RECORDS; i++) {
94 mFrameRecords[i].desiredPresentTime = 0;
95 mFrameRecords[i].frameReadyTime = 0;
96 mFrameRecords[i].actualPresentTime = 0;
97 mFrameRecords[i].frameReadyFence.reset();
98 mFrameRecords[i].actualPresentFence.reset();
99 }
100 mNumFences = 0;
101 mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
102 mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
103 mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
104 }
105
getStats(FrameStats * outStats) const106 void FrameTracker::getStats(FrameStats* outStats) const {
107 Mutex::Autolock lock(mMutex);
108 processFencesLocked();
109
110 outStats->refreshPeriodNano = mDisplayPeriod;
111
112 const size_t offset = mOffset;
113 for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
114 const size_t index = (offset + i) % NUM_FRAME_RECORDS;
115
116 // Skip frame records with no data (if buffer not yet full).
117 if (mFrameRecords[index].desiredPresentTime == 0) {
118 continue;
119 }
120
121 nsecs_t desiredPresentTimeNano = mFrameRecords[index].desiredPresentTime;
122 outStats->desiredPresentTimesNano.push_back(desiredPresentTimeNano);
123
124 nsecs_t actualPresentTimeNano = mFrameRecords[index].actualPresentTime;
125 outStats->actualPresentTimesNano.push_back(actualPresentTimeNano);
126
127 nsecs_t frameReadyTimeNano = mFrameRecords[index].frameReadyTime;
128 outStats->frameReadyTimesNano.push_back(frameReadyTimeNano);
129 }
130 }
131
processFencesLocked() const132 void FrameTracker::processFencesLocked() const {
133 FrameRecord* records = const_cast<FrameRecord*>(mFrameRecords);
134 int& numFences = const_cast<int&>(mNumFences);
135
136 for (int i = 1; i < NUM_FRAME_RECORDS && numFences > 0; i++) {
137 size_t idx = (mOffset + NUM_FRAME_RECORDS - i) % NUM_FRAME_RECORDS;
138
139 const std::shared_ptr<FenceTime>& rfence = records[idx].frameReadyFence;
140 if (rfence != nullptr) {
141 records[idx].frameReadyTime = rfence->getSignalTime();
142 if (records[idx].frameReadyTime < INT64_MAX) {
143 records[idx].frameReadyFence = nullptr;
144 numFences--;
145 }
146 }
147
148 const std::shared_ptr<FenceTime>& pfence =
149 records[idx].actualPresentFence;
150 if (pfence != nullptr) {
151 records[idx].actualPresentTime = pfence->getSignalTime();
152 if (records[idx].actualPresentTime < INT64_MAX) {
153 records[idx].actualPresentFence = nullptr;
154 numFences--;
155 }
156 }
157 }
158 }
159
isFrameValidLocked(size_t idx) const160 bool FrameTracker::isFrameValidLocked(size_t idx) const {
161 return mFrameRecords[idx].actualPresentTime > 0 &&
162 mFrameRecords[idx].actualPresentTime < INT64_MAX;
163 }
164
dumpStats(std::string & result) const165 void FrameTracker::dumpStats(std::string& result) const {
166 Mutex::Autolock lock(mMutex);
167 processFencesLocked();
168
169 const size_t o = mOffset;
170 for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
171 const size_t index = (o+i) % NUM_FRAME_RECORDS;
172 base::StringAppendF(&result, "%" PRId64 "\t%" PRId64 "\t%" PRId64 "\n",
173 mFrameRecords[index].desiredPresentTime,
174 mFrameRecords[index].actualPresentTime,
175 mFrameRecords[index].frameReadyTime);
176 }
177 result.append("\n");
178 }
179
180 } // namespace android
181
182 // TODO(b/129481165): remove the #pragma below and fix conversion issues
183 #pragma clang diagnostic pop // ignored "-Wconversion"
184