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