blob: d40667268b7f8746f95aaeae9a23f053e0835439 [file] [log] [blame]
Jamie Gennis82dbc742012-11-08 19:23:28 -08001/*
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// This is needed for stdint.h to define INT64_MAX in C++
18#define __STDC_LIMIT_MACROS
19
Jamie Gennis6547ff42013-07-16 20:12:42 -070020#include <cutils/log.h>
21
Jamie Gennis82dbc742012-11-08 19:23:28 -080022#include <ui/Fence.h>
23
24#include <utils/String8.h>
25
26#include "FrameTracker.h"
Jamie Gennis6547ff42013-07-16 20:12:42 -070027#include "EventLog/EventLog.h"
Jamie Gennis82dbc742012-11-08 19:23:28 -080028
29namespace android {
30
31FrameTracker::FrameTracker() :
32 mOffset(0),
Jamie Gennis6547ff42013-07-16 20:12:42 -070033 mNumFences(0),
34 mDisplayPeriod(0) {
35 resetFrameCountersLocked();
Jamie Gennis82dbc742012-11-08 19:23:28 -080036}
37
38void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) {
Jamie Gennis4b0eba92013-02-05 13:30:24 -080039 Mutex::Autolock lock(mMutex);
Jamie Gennis82dbc742012-11-08 19:23:28 -080040 mFrameRecords[mOffset].desiredPresentTime = presentTime;
41}
42
43void FrameTracker::setFrameReadyTime(nsecs_t readyTime) {
Jamie Gennis4b0eba92013-02-05 13:30:24 -080044 Mutex::Autolock lock(mMutex);
Jamie Gennis82dbc742012-11-08 19:23:28 -080045 mFrameRecords[mOffset].frameReadyTime = readyTime;
46}
47
48void FrameTracker::setFrameReadyFence(const sp<Fence>& readyFence) {
Jamie Gennis4b0eba92013-02-05 13:30:24 -080049 Mutex::Autolock lock(mMutex);
Jamie Gennis82dbc742012-11-08 19:23:28 -080050 mFrameRecords[mOffset].frameReadyFence = readyFence;
51 mNumFences++;
52}
53
54void FrameTracker::setActualPresentTime(nsecs_t presentTime) {
Jamie Gennis4b0eba92013-02-05 13:30:24 -080055 Mutex::Autolock lock(mMutex);
Jamie Gennis82dbc742012-11-08 19:23:28 -080056 mFrameRecords[mOffset].actualPresentTime = presentTime;
57}
58
59void FrameTracker::setActualPresentFence(const sp<Fence>& readyFence) {
Jamie Gennis4b0eba92013-02-05 13:30:24 -080060 Mutex::Autolock lock(mMutex);
Jamie Gennis82dbc742012-11-08 19:23:28 -080061 mFrameRecords[mOffset].actualPresentFence = readyFence;
62 mNumFences++;
63}
64
Jamie Gennis6547ff42013-07-16 20:12:42 -070065void FrameTracker::setDisplayRefreshPeriod(nsecs_t displayPeriod) {
66 Mutex::Autolock lock(mMutex);
67 mDisplayPeriod = displayPeriod;
68}
69
Jamie Gennis82dbc742012-11-08 19:23:28 -080070void FrameTracker::advanceFrame() {
Jamie Gennis4b0eba92013-02-05 13:30:24 -080071 Mutex::Autolock lock(mMutex);
Jamie Gennis6547ff42013-07-16 20:12:42 -070072
73 // Update the statistic to include the frame we just finished.
74 updateStatsLocked(mOffset);
75
76 // Advance to the next frame.
Jamie Gennis82dbc742012-11-08 19:23:28 -080077 mOffset = (mOffset+1) % NUM_FRAME_RECORDS;
78 mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
79 mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
80 mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
81
82 if (mFrameRecords[mOffset].frameReadyFence != NULL) {
83 // We're clobbering an unsignaled fence, so we need to decrement the
84 // fence count.
85 mFrameRecords[mOffset].frameReadyFence = NULL;
86 mNumFences--;
87 }
88
89 if (mFrameRecords[mOffset].actualPresentFence != NULL) {
90 // We're clobbering an unsignaled fence, so we need to decrement the
91 // fence count.
92 mFrameRecords[mOffset].actualPresentFence = NULL;
93 mNumFences--;
94 }
95
96 // Clean up the signaled fences to keep the number of open fence FDs in
97 // this process reasonable.
Jamie Gennis4b0eba92013-02-05 13:30:24 -080098 processFencesLocked();
Jamie Gennis82dbc742012-11-08 19:23:28 -080099}
100
101void FrameTracker::clear() {
Jamie Gennis4b0eba92013-02-05 13:30:24 -0800102 Mutex::Autolock lock(mMutex);
Jamie Gennis82dbc742012-11-08 19:23:28 -0800103 for (size_t i = 0; i < NUM_FRAME_RECORDS; i++) {
104 mFrameRecords[i].desiredPresentTime = 0;
105 mFrameRecords[i].frameReadyTime = 0;
106 mFrameRecords[i].actualPresentTime = 0;
107 mFrameRecords[i].frameReadyFence.clear();
108 mFrameRecords[i].actualPresentFence.clear();
109 }
110 mNumFences = 0;
Jamie Gennis4b0eba92013-02-05 13:30:24 -0800111 mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
112 mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
113 mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
Jamie Gennis82dbc742012-11-08 19:23:28 -0800114}
115
Jamie Gennis6547ff42013-07-16 20:12:42 -0700116void FrameTracker::logAndResetStats(const String8& name) {
117 Mutex::Autolock lock(mMutex);
118 logStatsLocked(name);
119 resetFrameCountersLocked();
120}
121
Jamie Gennis4b0eba92013-02-05 13:30:24 -0800122void FrameTracker::processFencesLocked() const {
Jamie Gennis82dbc742012-11-08 19:23:28 -0800123 FrameRecord* records = const_cast<FrameRecord*>(mFrameRecords);
124 int& numFences = const_cast<int&>(mNumFences);
125
126 for (int i = 1; i < NUM_FRAME_RECORDS && numFences > 0; i++) {
127 size_t idx = (mOffset+NUM_FRAME_RECORDS-i) % NUM_FRAME_RECORDS;
Jamie Gennis6547ff42013-07-16 20:12:42 -0700128 bool updated = false;
Jamie Gennis82dbc742012-11-08 19:23:28 -0800129
130 const sp<Fence>& rfence = records[idx].frameReadyFence;
131 if (rfence != NULL) {
132 records[idx].frameReadyTime = rfence->getSignalTime();
133 if (records[idx].frameReadyTime < INT64_MAX) {
134 records[idx].frameReadyFence = NULL;
135 numFences--;
Jamie Gennis6547ff42013-07-16 20:12:42 -0700136 updated = true;
Jamie Gennis82dbc742012-11-08 19:23:28 -0800137 }
138 }
139
140 const sp<Fence>& pfence = records[idx].actualPresentFence;
141 if (pfence != NULL) {
142 records[idx].actualPresentTime = pfence->getSignalTime();
143 if (records[idx].actualPresentTime < INT64_MAX) {
144 records[idx].actualPresentFence = NULL;
145 numFences--;
Jamie Gennis6547ff42013-07-16 20:12:42 -0700146 updated = true;
Jamie Gennis82dbc742012-11-08 19:23:28 -0800147 }
148 }
Jamie Gennis6547ff42013-07-16 20:12:42 -0700149
150 if (updated) {
151 updateStatsLocked(idx);
152 }
Jamie Gennis82dbc742012-11-08 19:23:28 -0800153 }
154}
155
Jamie Gennis6547ff42013-07-16 20:12:42 -0700156void FrameTracker::updateStatsLocked(size_t newFrameIdx) const {
157 int* numFrames = const_cast<int*>(mNumFrames);
158
159 if (mDisplayPeriod > 0 && isFrameValidLocked(newFrameIdx)) {
160 size_t prevFrameIdx = (newFrameIdx+NUM_FRAME_RECORDS-1) %
161 NUM_FRAME_RECORDS;
162
163 if (isFrameValidLocked(prevFrameIdx)) {
164 nsecs_t newPresentTime =
165 mFrameRecords[newFrameIdx].actualPresentTime;
166 nsecs_t prevPresentTime =
167 mFrameRecords[prevFrameIdx].actualPresentTime;
168
169 nsecs_t duration = newPresentTime - prevPresentTime;
170 int numPeriods = int((duration + mDisplayPeriod/2) /
171 mDisplayPeriod);
172
173 for (int i = 0; i < NUM_FRAME_BUCKETS-1; i++) {
174 int nextBucket = 1 << (i+1);
175 if (numPeriods < nextBucket) {
176 numFrames[i]++;
177 return;
178 }
179 }
180
181 // The last duration bucket is a catch-all.
182 numFrames[NUM_FRAME_BUCKETS-1]++;
183 }
184 }
185}
186
187void FrameTracker::resetFrameCountersLocked() {
188 for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
189 mNumFrames[i] = 0;
190 }
191}
192
193void FrameTracker::logStatsLocked(const String8& name) const {
194 for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
195 if (mNumFrames[i] > 0) {
196 EventLog::logFrameDurations(name, mNumFrames, NUM_FRAME_BUCKETS);
197 return;
198 }
199 }
200}
201
202bool FrameTracker::isFrameValidLocked(size_t idx) const {
203 return mFrameRecords[idx].actualPresentTime > 0 &&
204 mFrameRecords[idx].actualPresentTime < INT64_MAX;
205}
206
Jamie Gennis82dbc742012-11-08 19:23:28 -0800207void FrameTracker::dump(String8& result) const {
Jamie Gennis4b0eba92013-02-05 13:30:24 -0800208 Mutex::Autolock lock(mMutex);
209 processFencesLocked();
Jamie Gennis82dbc742012-11-08 19:23:28 -0800210
211 const size_t o = mOffset;
212 for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
213 const size_t index = (o+i) % NUM_FRAME_RECORDS;
214 result.appendFormat("%lld\t%lld\t%lld\n",
215 mFrameRecords[index].desiredPresentTime,
216 mFrameRecords[index].actualPresentTime,
217 mFrameRecords[index].frameReadyTime);
218 }
219 result.append("\n");
220}
221
222} // namespace android