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