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