• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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