• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 #include "FrameStatistics.h"
18 
19 #define LOG_TAG "FrameStatistics"
20 
21 #include <cmath>
22 #include <inttypes.h>
23 #include <string>
24 
25 #include "EGL.h"
26 
27 #include "Log.h"
28 
29 
30 namespace swappy {
31 
32 // NB This is only needed for C++14
33 constexpr std::chrono::nanoseconds FrameStatistics::LOG_EVERY_N_NS;
34 
updateFrames(EGLnsecsANDROID start,EGLnsecsANDROID end,uint64_t stat[])35 void FrameStatistics::updateFrames(EGLnsecsANDROID start, EGLnsecsANDROID end, uint64_t stat[]) {
36     const uint64_t deltaTimeNano = end - start;
37 
38     uint32_t numFrames = deltaTimeNano / mRefreshPeriod.count();
39     numFrames = std::min(numFrames, static_cast<uint32_t>(MAX_FRAME_BUCKETS));
40     stat[numFrames]++;
41 }
42 
updateIdleFrames(EGL::FrameTimestamps & frameStats)43 void FrameStatistics::updateIdleFrames(EGL::FrameTimestamps& frameStats) {
44     updateFrames(frameStats.renderingCompleted,
45                  frameStats.compositionLatched,
46                  mStats.idleFrames);
47 }
48 
updateLatencyFrames(swappy::EGL::FrameTimestamps & frameStats,TimePoint frameStartTime)49 void FrameStatistics::updateLatencyFrames(swappy::EGL::FrameTimestamps &frameStats,
50                                                                         TimePoint frameStartTime) {
51     updateFrames(frameStartTime.time_since_epoch().count(),
52                  frameStats.presented,
53                  mStats.latencyFrames);
54 }
55 
updateLateFrames(EGL::FrameTimestamps & frameStats)56 void FrameStatistics::updateLateFrames(EGL::FrameTimestamps& frameStats) {
57     updateFrames(frameStats.requested,
58                  frameStats.presented,
59                  mStats.lateFrames);
60 }
61 
updateOffsetFromPreviousFrame(swappy::EGL::FrameTimestamps & frameStats)62 void FrameStatistics::updateOffsetFromPreviousFrame(swappy::EGL::FrameTimestamps &frameStats) {
63     if (mPrevFrameTime != 0) {
64         updateFrames(mPrevFrameTime,
65                      frameStats.presented,
66                      mStats.offsetFromPreviousFrame);
67     }
68     mPrevFrameTime = frameStats.presented;
69 }
70 
71 // called once per swap
capture(EGLDisplay dpy,EGLSurface surface)72 void FrameStatistics::capture(EGLDisplay dpy, EGLSurface surface) {
73     const TimePoint frameStartTime = std::chrono::steady_clock::now();
74 
75     // first get the next frame id
76     std::pair<bool,EGLuint64KHR> nextFrameId = mEgl->getNextFrameId(dpy, surface);
77     if (nextFrameId.first) {
78         mPendingFrames.push_back({dpy, surface, nextFrameId.second, frameStartTime});
79     }
80 
81     if (mPendingFrames.empty()) {
82         return;
83     }
84 
85 
86     EGLFrame frame = mPendingFrames.front();
87     // make sure we don't lag behind the stats too much
88     if (nextFrameId.first && nextFrameId.second - frame.id > MAX_FRAME_LAG) {
89         while (mPendingFrames.size() > 1)
90             mPendingFrames.erase(mPendingFrames.begin());
91         mPrevFrameTime = 0;
92         frame = mPendingFrames.front();
93     }
94 
95     std::unique_ptr<EGL::FrameTimestamps> frameStats =
96             mEgl->getFrameTimestamps(frame.dpy, frame.surface, frame.id);
97 
98     if (!frameStats) {
99         return;
100     }
101 
102     mPendingFrames.erase(mPendingFrames.begin());
103 
104     std::lock_guard<std::mutex> lock(mMutex);
105     mStats.totalFrames++;
106     updateIdleFrames(*frameStats);
107     updateLateFrames(*frameStats);
108     updateOffsetFromPreviousFrame(*frameStats);
109     updateLatencyFrames(*frameStats, frame.startFrameTime);
110 
111     logFrames();
112 }
113 
logFrames()114 void FrameStatistics::logFrames() {
115     static auto previousLogTime = std::chrono::steady_clock::now();
116 
117     if (std::chrono::steady_clock::now() - previousLogTime < LOG_EVERY_N_NS) {
118         return;
119     }
120 
121     std::string message;
122     ALOGI("== Frame statistics ==");
123     ALOGI("total frames: %" PRIu64, mStats.totalFrames);
124     message += "Buckets:                    ";
125     for (int i = 0; i < MAX_FRAME_BUCKETS; i++)
126         message += "\t[" + swappy::to_string(i) + "]";
127     ALOGI("%s", message.c_str());
128 
129     message = "";
130     message += "idle frames:                ";
131     for (int i = 0; i < MAX_FRAME_BUCKETS; i++)
132         message += "\t " + swappy::to_string(mStats.idleFrames[i]);
133     ALOGI("%s", message.c_str());
134 
135     message = "";
136     message += "late frames:                ";
137     for (int i = 0; i < MAX_FRAME_BUCKETS; i++)
138         message += "\t " + swappy::to_string(mStats.lateFrames[i]);
139     ALOGI("%s", message.c_str());
140 
141     message = "";
142     message += "offset from previous frame: ";
143     for (int i = 0; i < MAX_FRAME_BUCKETS; i++)
144         message += "\t " + swappy::to_string(mStats.offsetFromPreviousFrame[i]);
145     ALOGI("%s", message.c_str());
146 
147     message = "";
148     message += "frame latency:              ";
149     for (int i = 0; i < MAX_FRAME_BUCKETS; i++)
150         message += "\t " + swappy::to_string(mStats.latencyFrames[i]);
151     ALOGI("%s", message.c_str());
152 
153     previousLogTime = std::chrono::steady_clock::now();
154 }
155 
getStats()156 Swappy_Stats FrameStatistics::getStats() {
157     std::lock_guard<std::mutex> lock(mMutex);
158     return mStats;
159 }
160 
161 } // namespace swappy
162