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