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