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