• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 #ifndef FRAMEINFO_H_
17 #define FRAMEINFO_H_
18 
19 #include <cutils/compiler.h>
20 #include <memory.h>
21 #include <utils/Timers.h>
22 
23 #include <array>
24 #include <optional>
25 #include <string>
26 
27 #include "SkippedFrameInfo.h"
28 #include "utils/Macros.h"
29 
30 namespace android {
31 namespace uirenderer {
32 
33 static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 12;
34 
35 enum class FrameInfoIndex {
36     Flags = 0,
37     FrameTimelineVsyncId,
38     IntendedVsync,
39     Vsync,
40     InputEventId,
41     HandleInputStart,
42     AnimationStart,
43     PerformTraversalsStart,
44     DrawStart,
45     FrameDeadline,
46     FrameStartTime,
47     FrameInterval,
48     // End of UI frame info
49 
50     SyncQueued,
51 
52     SyncStart,
53     IssueDrawCommandsStart,
54     SwapBuffers,
55     FrameCompleted,
56 
57     DequeueBufferDuration,
58     QueueBufferDuration,
59 
60     GpuCompleted,
61     SwapBuffersCompleted,
62     DisplayPresentTime,
63     CommandSubmissionCompleted,
64 
65     // Must be the last value!
66     // Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT
67     NumIndexes
68 };
69 
70 extern const std::array<const char*, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames;
71 
72 namespace FrameInfoFlags {
73 enum {
74     WindowVisibilityChanged = 1 << 0,
75     RTAnimation = 1 << 1,
76     SurfaceCanvas = 1 << 2,
77     SkippedFrame = 1 << 3,
78 };
79 };
80 
81 class UiFrameInfoBuilder {
82 public:
83     static constexpr int64_t INVALID_VSYNC_ID = -1;
84     static constexpr int64_t UNKNOWN_DEADLINE = std::numeric_limits<int64_t>::max();
85     static constexpr int64_t UNKNOWN_FRAME_INTERVAL = -1;
86 
87 
UiFrameInfoBuilder(int64_t * buffer)88     explicit UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) {
89         memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
90         set(FrameInfoIndex::FrameTimelineVsyncId) = INVALID_VSYNC_ID;
91         // The struct is zeroed by memset above. That also sets FrameInfoIndex::InputEventId to
92         // equal android::os::IInputConstants::INVALID_INPUT_EVENT_ID == 0.
93         // Therefore, we can skip setting the value for InputEventId here. If the value for
94         // INVALID_INPUT_EVENT_ID changes, this code would have to be updated, as well.
95         set(FrameInfoIndex::FrameDeadline) = std::numeric_limits<int64_t>::max();
96     }
97 
setVsync(nsecs_t vsyncTime,nsecs_t intendedVsync,int64_t vsyncId,int64_t frameDeadline,nsecs_t frameInterval)98     UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync,
99                                  int64_t vsyncId, int64_t frameDeadline, nsecs_t frameInterval) {
100         set(FrameInfoIndex::FrameTimelineVsyncId) = vsyncId;
101         set(FrameInfoIndex::Vsync) = vsyncTime;
102         set(FrameInfoIndex::IntendedVsync) = intendedVsync;
103         // Pretend the other fields are all at vsync, too, so that naive
104         // duration calculations end up being 0 instead of very large
105         set(FrameInfoIndex::HandleInputStart) = vsyncTime;
106         set(FrameInfoIndex::AnimationStart) = vsyncTime;
107         set(FrameInfoIndex::PerformTraversalsStart) = vsyncTime;
108         set(FrameInfoIndex::DrawStart) = vsyncTime;
109         set(FrameInfoIndex::FrameStartTime) = vsyncTime;
110         set(FrameInfoIndex::FrameDeadline) = frameDeadline;
111         set(FrameInfoIndex::FrameInterval) = frameInterval;
112         return *this;
113     }
114 
addFlag(int frameInfoFlag)115     UiFrameInfoBuilder& addFlag(int frameInfoFlag) {
116         set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
117         return *this;
118     }
119 
120 private:
set(FrameInfoIndex index)121     inline int64_t& set(FrameInfoIndex index) { return mBuffer[static_cast<int>(index)]; }
122 
123     int64_t* mBuffer;
124 };
125 
126 class FrameInfo {
127 public:
128     void importUiThreadInfo(int64_t* info);
129 
markSyncStart()130     void markSyncStart() { set(FrameInfoIndex::SyncStart) = systemTime(SYSTEM_TIME_MONOTONIC); }
131 
markIssueDrawCommandsStart()132     void markIssueDrawCommandsStart() {
133         set(FrameInfoIndex::IssueDrawCommandsStart) = systemTime(SYSTEM_TIME_MONOTONIC);
134     }
135 
markSwapBuffers()136     void markSwapBuffers() { set(FrameInfoIndex::SwapBuffers) = systemTime(SYSTEM_TIME_MONOTONIC); }
137 
markSwapBuffersCompleted()138     void markSwapBuffersCompleted() {
139         set(FrameInfoIndex::SwapBuffersCompleted) = systemTime(SYSTEM_TIME_MONOTONIC);
140     }
141 
markFrameCompleted()142     void markFrameCompleted() { set(FrameInfoIndex::FrameCompleted) = systemTime(SYSTEM_TIME_MONOTONIC); }
143 
addFlag(int frameInfoFlag)144     void addFlag(int frameInfoFlag) {
145         set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
146     }
147 
data()148     const int64_t* data() const { return mFrameInfo; }
149 
150     inline int64_t operator[](FrameInfoIndex index) const { return get(index); }
151 
152     inline int64_t operator[](int index) const {
153         if (index < 0 || index >= static_cast<int>(FrameInfoIndex::NumIndexes)) return 0;
154         return mFrameInfo[index];
155     }
156 
duration(FrameInfoIndex start,FrameInfoIndex end)157     inline int64_t duration(FrameInfoIndex start, FrameInfoIndex end) const {
158         int64_t endtime = get(end);
159         int64_t starttime = get(start);
160         int64_t gap = endtime - starttime;
161         gap = starttime > 0 ? gap : 0;
162         if (end > FrameInfoIndex::SyncQueued && start < FrameInfoIndex::SyncQueued) {
163             // Need to subtract out the time spent in a stalled state
164             // as this will be captured by the previous frame's info
165             int64_t offset = get(FrameInfoIndex::SyncStart) - get(FrameInfoIndex::SyncQueued);
166             if (offset > 0) {
167                 gap -= offset;
168             }
169         }
170         return gap > 0 ? gap : 0;
171     }
172 
totalDuration()173     inline int64_t totalDuration() const {
174         return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted);
175     }
176 
gpuDrawTime()177     inline int64_t gpuDrawTime() const {
178         // GPU start time is approximated to the moment before swapBuffer is invoked.
179         // We could add an EGLSyncKHR fence at the beginning of the frame, but that is an overhead.
180         int64_t endTime = get(FrameInfoIndex::GpuCompleted);
181         return endTime > 0 ? endTime - get(FrameInfoIndex::SwapBuffers) : -1;
182     }
183 
set(FrameInfoIndex index)184     inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; }
185 
get(FrameInfoIndex index)186     inline int64_t get(FrameInfoIndex index) const {
187         if (index == FrameInfoIndex::NumIndexes) return 0;
188         return mFrameInfo[static_cast<int>(index)];
189     }
190 
191     void setSkippedFrameReason(SkippedFrameReason reason);
getSkippedFrameReason()192     inline std::optional<SkippedFrameReason> getSkippedFrameReason() const {
193         return mSkippedFrameReason;
194     }
195 
196 private:
197     int64_t mFrameInfo[static_cast<int>(FrameInfoIndex::NumIndexes)];
198     std::optional<SkippedFrameReason> mSkippedFrameReason;
199 };
200 
201 } /* namespace uirenderer */
202 } /* namespace android */
203 
204 #endif /* FRAMEINFO_H_ */
205