1 /* 2 * Copyright 2018 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 17 #pragma once 18 19 #include <cstdint> 20 #include <deque> 21 #include <mutex> 22 #include <optional> 23 #include <unordered_map> 24 #include <variant> 25 26 #include <android/hardware/graphics/composer/2.4/IComposerClient.h> 27 #include <gui/JankInfo.h> 28 #include <gui/LayerMetadata.h> 29 #include <timestatsproto/TimeStatsHelper.h> 30 #include <timestatsproto/TimeStatsProtoHeader.h> 31 #include <ui/FenceTime.h> 32 #include <utils/String16.h> 33 #include <utils/Vector.h> 34 35 #include <scheduler/Fps.h> 36 37 using namespace android::surfaceflinger; 38 39 namespace android { 40 41 class TimeStats { 42 public: 43 using SetFrameRateVote = TimeStatsHelper::SetFrameRateVote; 44 45 virtual ~TimeStats() = default; 46 47 // Process a pull request from statsd. 48 virtual bool onPullAtom(const int atomId, std::string* pulledData) = 0; 49 50 virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0; 51 virtual bool isEnabled() = 0; 52 virtual std::string miniDump() = 0; 53 54 virtual void incrementTotalFrames() = 0; 55 virtual void incrementMissedFrames() = 0; 56 // Increments the number of times the display refresh rate changed. 57 virtual void incrementRefreshRateSwitches() = 0; 58 // Records the most up-to-date count of display event connections. 59 // The stored count will be the maximum ever recoded. 60 virtual void recordDisplayEventConnectionCount(int32_t count) = 0; 61 62 // Records the start and end times for a frame. 63 // The start time is the same as the beginning of a SurfaceFlinger 64 // invalidate message. 65 // The end time corresponds to when SurfaceFlinger finishes submitting the 66 // request to HWC to present a frame. 67 virtual void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) = 0; 68 // Records the start time and end times for when RenderEngine begins work. 69 // The start time corresponds to the beginning of RenderEngine::drawLayers. 70 // The end time corresponds to when RenderEngine finishes rendering. 71 virtual void recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) = 0; 72 // Same as above, but passes in a fence representing the end time. 73 virtual void recordRenderEngineDuration(nsecs_t startTime, 74 const std::shared_ptr<FenceTime>& readyFence) = 0; 75 76 virtual void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, 77 uid_t uid, nsecs_t postTime, GameMode) = 0; 78 virtual void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) = 0; 79 // Reasons why latching a particular buffer may be skipped 80 enum class LatchSkipReason { 81 // If the acquire fence did not fire on some devices we skip latching 82 // the buffer until the fence fires. 83 LateAcquire, 84 }; 85 // Increments the counter of skipped latch buffers. 86 virtual void incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) = 0; 87 // Increments the counter of bad desired present times for this layer. 88 // Bad desired present times are "implausible" and cause SurfaceFlinger to 89 // latch a buffer immediately to avoid stalling. 90 virtual void incrementBadDesiredPresent(int32_t layerId) = 0; 91 virtual void setDesiredTime(int32_t layerId, uint64_t frameNumber, nsecs_t desiredTime) = 0; 92 virtual void setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) = 0; 93 virtual void setAcquireFence(int32_t layerId, uint64_t frameNumber, 94 const std::shared_ptr<FenceTime>& acquireFence) = 0; 95 // SetPresent{Time, Fence} are not expected to be called in the critical 96 // rendering path, as they flush prior fences if those fences have fired. 97 virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, 98 Fps displayRefreshRate, std::optional<Fps> renderRate, 99 SetFrameRateVote frameRateVote, GameMode) = 0; 100 virtual void setPresentFence(int32_t layerId, uint64_t frameNumber, 101 const std::shared_ptr<FenceTime>& presentFence, 102 Fps displayRefreshRate, std::optional<Fps> renderRate, 103 SetFrameRateVote frameRateVote, GameMode) = 0; 104 105 // Increments janky frames, blamed to the provided {refreshRate, renderRate, uid, layerName} 106 // key, with JankMetadata as supplementary reasons for the jank. Because FrameTimeline is the 107 // infrastructure responsible for computing jank in the system, this is expected to be called 108 // from FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there 109 // are no jank reasons, then total frames are incremented but jank is not, for accurate 110 // accounting of janky frames. 111 // displayDeadlineDelta, displayPresentJitter, and appDeadlineDelta are also provided in order 112 // to provide contextual information about a janky frame. These values may only be uploaded if 113 // there was an associated valid jank reason, and they must be positive. When these frame counts 114 // are incremented, these are also aggregated into a global reporting packet to help with data 115 // validation and assessing of overall device health. 116 struct JankyFramesInfo { 117 Fps refreshRate; 118 std::optional<Fps> renderRate; 119 uid_t uid = 0; 120 std::string layerName; 121 GameMode gameMode = GameMode::Unsupported; 122 int32_t reasons = 0; 123 nsecs_t displayDeadlineDelta = 0; 124 nsecs_t displayPresentJitter = 0; 125 nsecs_t appDeadlineDelta = 0; 126 isOptApproxEqualJankyFramesInfo127 static bool isOptApproxEqual(std::optional<Fps> lhs, std::optional<Fps> rhs) { 128 return (!lhs && !rhs) || (lhs && rhs && isApproxEqual(*lhs, *rhs)); 129 } 130 131 bool operator==(const JankyFramesInfo& o) const { 132 return isApproxEqual(refreshRate, o.refreshRate) && 133 isOptApproxEqual(renderRate, o.renderRate) && uid == o.uid && 134 layerName == o.layerName && gameMode == o.gameMode && reasons == o.reasons && 135 displayDeadlineDelta == o.displayDeadlineDelta && 136 displayPresentJitter == o.displayPresentJitter && 137 appDeadlineDelta == o.appDeadlineDelta; 138 } 139 140 friend std::ostream& operator<<(std::ostream& os, const JankyFramesInfo& info) { 141 os << "JankyFramesInfo {"; 142 os << "\n .refreshRate = " << info.refreshRate; 143 os << "\n .renderRate = " 144 << (info.renderRate ? to_string(*info.renderRate) : "nullopt"); 145 os << "\n .uid = " << info.uid; 146 os << "\n .layerName = " << info.layerName; 147 os << "\n .reasons = " << info.reasons; 148 os << "\n .displayDeadlineDelta = " << info.displayDeadlineDelta; 149 os << "\n .displayPresentJitter = " << info.displayPresentJitter; 150 os << "\n .appDeadlineDelta = " << info.appDeadlineDelta; 151 return os << "\n}"; 152 } 153 }; 154 155 struct ClientCompositionRecord { 156 // Frame had client composition or mixed composition 157 bool hadClientComposition = false; 158 // Composition changed between hw composition and mixed/client composition 159 bool changed = false; 160 // Frame reused the client composition result from a previous frame 161 bool reused = false; 162 // Composition strategy predicted for frame 163 bool predicted = false; 164 // Composition strategy prediction succeeded 165 bool predictionSucceeded = false; 166 167 // Whether there is data we want to record. hasInterestingDataClientCompositionRecord168 bool hasInterestingData() const { 169 return hadClientComposition || changed || reused || predicted; 170 } 171 }; 172 173 virtual void incrementJankyFrames(const JankyFramesInfo& info) = 0; 174 // Clean up the layer record 175 virtual void onDestroy(int32_t layerId) = 0; 176 // If SF skips or rejects a buffer, remove the corresponding TimeRecord. 177 virtual void removeTimeRecord(int32_t layerId, uint64_t frameNumber) = 0; 178 179 virtual void setPowerMode( 180 hardware::graphics::composer::V2_4::IComposerClient::PowerMode powerMode) = 0; 181 // Source of truth is RefrehRateStats. 182 virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0; 183 virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0; 184 virtual void pushCompositionStrategyState(const ClientCompositionRecord&) = 0; 185 }; 186 187 namespace impl { 188 189 class TimeStats : public android::TimeStats { 190 using PowerMode = android::hardware::graphics::composer::V2_4::IComposerClient::PowerMode; 191 192 struct FrameTime { 193 uint64_t frameNumber = 0; 194 nsecs_t postTime = 0; 195 nsecs_t latchTime = 0; 196 nsecs_t acquireTime = 0; 197 nsecs_t desiredTime = 0; 198 nsecs_t presentTime = 0; 199 }; 200 201 struct TimeRecord { 202 bool ready = false; 203 FrameTime frameTime; 204 std::shared_ptr<FenceTime> acquireFence; 205 std::shared_ptr<FenceTime> presentFence; 206 }; 207 208 struct LayerRecord { 209 uid_t uid; 210 std::string layerName; 211 GameMode gameMode = GameMode::Unsupported; 212 // This is the index in timeRecords, at which the timestamps for that 213 // specific frame are still not fully received. This is not waiting for 214 // fences to signal, but rather waiting to receive those fences/timestamps. 215 int32_t waitData = -1; 216 uint32_t droppedFrames = 0; 217 uint32_t lateAcquireFrames = 0; 218 uint32_t badDesiredPresentFrames = 0; 219 TimeRecord prevTimeRecord; 220 std::deque<TimeRecord> timeRecords; 221 }; 222 223 struct PowerTime { 224 PowerMode powerMode = PowerMode::OFF; 225 nsecs_t prevTime = 0; 226 }; 227 228 struct RenderEngineDuration { 229 nsecs_t startTime; 230 std::variant<nsecs_t, std::shared_ptr<FenceTime>> endTime; 231 }; 232 233 struct GlobalRecord { 234 nsecs_t prevPresentTime = 0; 235 std::deque<std::shared_ptr<FenceTime>> presentFences; 236 std::deque<RenderEngineDuration> renderEngineDurations; 237 }; 238 239 public: 240 TimeStats(); 241 // For testing only for injecting custom dependencies. 242 TimeStats(std::optional<size_t> maxPulledLayers, 243 std::optional<size_t> maxPulledHistogramBuckets); 244 245 bool onPullAtom(const int atomId, std::string* pulledData) override; 246 void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override; 247 bool isEnabled() override; 248 std::string miniDump() override; 249 250 void incrementTotalFrames() override; 251 void incrementMissedFrames() override; 252 void incrementRefreshRateSwitches() override; 253 void recordDisplayEventConnectionCount(int32_t count) override; 254 255 void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override; 256 void recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) override; 257 void recordRenderEngineDuration(nsecs_t startTime, 258 const std::shared_ptr<FenceTime>& readyFence) override; 259 260 void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, uid_t uid, 261 nsecs_t postTime, GameMode) override; 262 void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) override; 263 void incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) override; 264 void incrementBadDesiredPresent(int32_t layerId) override; 265 void setDesiredTime(int32_t layerId, uint64_t frameNumber, nsecs_t desiredTime) override; 266 void setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) override; 267 void setAcquireFence(int32_t layerId, uint64_t frameNumber, 268 const std::shared_ptr<FenceTime>& acquireFence) override; 269 void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, 270 Fps displayRefreshRate, std::optional<Fps> renderRate, SetFrameRateVote, 271 GameMode) override; 272 void setPresentFence(int32_t layerId, uint64_t frameNumber, 273 const std::shared_ptr<FenceTime>& presentFence, Fps displayRefreshRate, 274 std::optional<Fps> renderRate, SetFrameRateVote, GameMode) override; 275 276 void incrementJankyFrames(const JankyFramesInfo& info) override; 277 // Clean up the layer record 278 void onDestroy(int32_t layerId) override; 279 // If SF skips or rejects a buffer, remove the corresponding TimeRecord. 280 void removeTimeRecord(int32_t layerId, uint64_t frameNumber) override; 281 282 void setPowerMode( 283 hardware::graphics::composer::V2_4::IComposerClient::PowerMode powerMode) override; 284 // Source of truth is RefrehRateStats. 285 void recordRefreshRate(uint32_t fps, nsecs_t duration) override; 286 void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override; 287 288 void pushCompositionStrategyState(const ClientCompositionRecord&) override; 289 290 static const size_t MAX_NUM_TIME_RECORDS = 64; 291 292 private: 293 bool populateGlobalAtom(std::string* pulledData); 294 bool populateLayerAtom(std::string* pulledData); 295 bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord); 296 void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, 297 std::optional<Fps> renderRate, SetFrameRateVote, 298 GameMode); 299 void flushPowerTimeLocked(); 300 void flushAvailableGlobalRecordsToStatsLocked(); 301 bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName, GameMode); 302 303 void enable(); 304 void disable(); 305 void clearAll(); 306 void clearGlobalLocked(); 307 void clearLayersLocked(); 308 void dump(bool asProto, std::optional<uint32_t> maxLayers, std::string& result); 309 310 std::atomic<bool> mEnabled = false; 311 std::mutex mMutex; 312 TimeStatsHelper::TimeStatsGlobal mTimeStats; 313 // Hashmap for LayerRecord with layerId as the hash key 314 std::unordered_map<int32_t, LayerRecord> mTimeStatsTracker; 315 PowerTime mPowerTime; 316 GlobalRecord mGlobalRecord; 317 318 static const size_t MAX_NUM_LAYER_RECORDS = 200; 319 320 static const size_t REFRESH_RATE_BUCKET_WIDTH = 30; 321 static const size_t RENDER_RATE_BUCKET_WIDTH = REFRESH_RATE_BUCKET_WIDTH; 322 static const size_t MAX_NUM_LAYER_STATS = 200; 323 static const size_t MAX_NUM_PULLED_LAYERS = MAX_NUM_LAYER_STATS; 324 size_t mMaxPulledLayers = MAX_NUM_PULLED_LAYERS; 325 size_t mMaxPulledHistogramBuckets = 6; 326 }; 327 328 } // namespace impl 329 330 } // namespace android 331