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