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