• 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 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