FrameTracker.cpp revision 6547ff4327aa320fbc9635668d3fc66db7dd78f6
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// This is needed for stdint.h to define INT64_MAX in C++
18#define __STDC_LIMIT_MACROS
19
20#include <cutils/log.h>
21
22#include <ui/Fence.h>
23
24#include <utils/String8.h>
25
26#include "FrameTracker.h"
27#include "EventLog/EventLog.h"
28
29namespace android {
30
31FrameTracker::FrameTracker() :
32        mOffset(0),
33        mNumFences(0),
34        mDisplayPeriod(0) {
35    resetFrameCountersLocked();
36}
37
38void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) {
39    Mutex::Autolock lock(mMutex);
40    mFrameRecords[mOffset].desiredPresentTime = presentTime;
41}
42
43void FrameTracker::setFrameReadyTime(nsecs_t readyTime) {
44    Mutex::Autolock lock(mMutex);
45    mFrameRecords[mOffset].frameReadyTime = readyTime;
46}
47
48void FrameTracker::setFrameReadyFence(const sp<Fence>& readyFence) {
49    Mutex::Autolock lock(mMutex);
50    mFrameRecords[mOffset].frameReadyFence = readyFence;
51    mNumFences++;
52}
53
54void FrameTracker::setActualPresentTime(nsecs_t presentTime) {
55    Mutex::Autolock lock(mMutex);
56    mFrameRecords[mOffset].actualPresentTime = presentTime;
57}
58
59void FrameTracker::setActualPresentFence(const sp<Fence>& readyFence) {
60    Mutex::Autolock lock(mMutex);
61    mFrameRecords[mOffset].actualPresentFence = readyFence;
62    mNumFences++;
63}
64
65void FrameTracker::setDisplayRefreshPeriod(nsecs_t displayPeriod) {
66    Mutex::Autolock lock(mMutex);
67    mDisplayPeriod = displayPeriod;
68}
69
70void FrameTracker::advanceFrame() {
71    Mutex::Autolock lock(mMutex);
72
73    // Update the statistic to include the frame we just finished.
74    updateStatsLocked(mOffset);
75
76    // Advance to the next frame.
77    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.
98    processFencesLocked();
99}
100
101void FrameTracker::clear() {
102    Mutex::Autolock lock(mMutex);
103    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;
111    mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
112    mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
113    mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
114}
115
116void FrameTracker::logAndResetStats(const String8& name) {
117    Mutex::Autolock lock(mMutex);
118    logStatsLocked(name);
119    resetFrameCountersLocked();
120}
121
122void FrameTracker::processFencesLocked() const {
123    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;
128        bool updated = false;
129
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--;
136                updated = true;
137            }
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--;
146                updated = true;
147            }
148        }
149
150        if (updated) {
151            updateStatsLocked(idx);
152        }
153    }
154}
155
156void 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
207void FrameTracker::dump(String8& result) const {
208    Mutex::Autolock lock(mMutex);
209    processFencesLocked();
210
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
223