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::FrameStartTime) = vsyncTime;
108         set(FrameInfoIndex::FrameDeadline) = frameDeadline;
109         set(FrameInfoIndex::FrameInterval) = frameInterval;
110         return *this;
111     }
112 
addFlag(int frameInfoFlag)113     UiFrameInfoBuilder& addFlag(int frameInfoFlag) {
114         set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
115         return *this;
116     }
117 
118 private:
set(FrameInfoIndex index)119     inline int64_t& set(FrameInfoIndex index) { return mBuffer[static_cast<int>(index)]; }
120 
121     int64_t* mBuffer;
122 };
123 
124 class FrameInfo {
125 public:
126     void importUiThreadInfo(int64_t* info);
127 
markSyncStart()128     void markSyncStart() { set(FrameInfoIndex::SyncStart) = systemTime(SYSTEM_TIME_MONOTONIC); }
129 
markIssueDrawCommandsStart()130     void markIssueDrawCommandsStart() {
131         set(FrameInfoIndex::IssueDrawCommandsStart) = systemTime(SYSTEM_TIME_MONOTONIC);
132     }
133 
markSwapBuffers()134     void markSwapBuffers() { set(FrameInfoIndex::SwapBuffers) = systemTime(SYSTEM_TIME_MONOTONIC); }
135 
markSwapBuffersCompleted()136     void markSwapBuffersCompleted() {
137         set(FrameInfoIndex::SwapBuffersCompleted) = systemTime(SYSTEM_TIME_MONOTONIC);
138     }
139 
markFrameCompleted()140     void markFrameCompleted() { set(FrameInfoIndex::FrameCompleted) = systemTime(SYSTEM_TIME_MONOTONIC); }
141 
addFlag(int frameInfoFlag)142     void addFlag(int frameInfoFlag) {
143         set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
144     }
145 
data()146     const int64_t* data() const { return mFrameInfo; }
147 
148     inline int64_t operator[](FrameInfoIndex index) const { return get(index); }
149 
150     inline int64_t operator[](int index) const {
151         if (index < 0 || index >= static_cast<int>(FrameInfoIndex::NumIndexes)) return 0;
152         return mFrameInfo[index];
153     }
154 
duration(FrameInfoIndex start,FrameInfoIndex end)155     inline int64_t duration(FrameInfoIndex start, FrameInfoIndex end) const {
156         int64_t endtime = get(end);
157         int64_t starttime = get(start);
158         int64_t gap = endtime - starttime;
159         gap = starttime > 0 ? gap : 0;
160         if (end > FrameInfoIndex::SyncQueued && start < FrameInfoIndex::SyncQueued) {
161             // Need to subtract out the time spent in a stalled state
162             // as this will be captured by the previous frame's info
163             int64_t offset = get(FrameInfoIndex::SyncStart) - get(FrameInfoIndex::SyncQueued);
164             if (offset > 0) {
165                 gap -= offset;
166             }
167         }
168         return gap > 0 ? gap : 0;
169     }
170 
totalDuration()171     inline int64_t totalDuration() const {
172         return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted);
173     }
174 
gpuDrawTime()175     inline int64_t gpuDrawTime() const {
176         // GPU start time is approximated to the moment before swapBuffer is invoked.
177         // We could add an EGLSyncKHR fence at the beginning of the frame, but that is an overhead.
178         int64_t endTime = get(FrameInfoIndex::GpuCompleted);
179         return endTime > 0 ? endTime - get(FrameInfoIndex::SwapBuffers) : -1;
180     }
181 
set(FrameInfoIndex index)182     inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; }
183 
get(FrameInfoIndex index)184     inline int64_t get(FrameInfoIndex index) const {
185         if (index == FrameInfoIndex::NumIndexes) return 0;
186         return mFrameInfo[static_cast<int>(index)];
187     }
188 
189 private:
190     int64_t mFrameInfo[static_cast<int>(FrameInfoIndex::NumIndexes)];
191 };
192 
193 } /* namespace uirenderer */
194 } /* namespace android */
195 
196 #endif /* FRAMEINFO_H_ */
197