• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 #pragma once
17 
18 #include <gui/LayerMetadata.h>
19 #include <timestatsproto/TimeStatsProtoHeader.h>
20 #include <utils/Timers.h>
21 
22 #include <optional>
23 #include <string>
24 #include <unordered_map>
25 #include <vector>
26 
27 namespace android {
28 namespace surfaceflinger {
29 
30 class TimeStatsHelper {
31 public:
32     class Histogram {
33     public:
34         // Key is the delta time between timestamps
35         // Value is the number of appearances of that delta
36         std::unordered_map<int32_t, int32_t> hist;
37 
38         void insert(int32_t delta);
39         int64_t totalTime() const;
40         float averageTime() const;
41         std::string toString() const;
42     };
43 
44     struct JankPayload {
45         // note that transactions are counted for these frames.
46         int32_t totalFrames = 0;
47         int32_t totalJankyFrames = 0;
48         int32_t totalSFLongCpu = 0;
49         int32_t totalSFLongGpu = 0;
50         int32_t totalSFUnattributed = 0;
51         int32_t totalAppUnattributed = 0;
52         int32_t totalSFScheduling = 0;
53         int32_t totalSFPredictionError = 0;
54         int32_t totalAppBufferStuffing = 0;
55 
56         std::string toString() const;
57     };
58 
59     struct SetFrameRateVote {
60         float frameRate = 0;
61 
62         // Needs to be in sync with atoms.proto
63         enum class FrameRateCompatibility {
64             Undefined = 0,
65             Default = 1,
66             ExactOrMultiple = 2,
67 
68             ftl_last = ExactOrMultiple
69         } frameRateCompatibility = FrameRateCompatibility::Undefined;
70 
71         // Needs to be in sync with atoms.proto
72         enum class Seamlessness {
73             Undefined = 0,
74             ShouldBeSeamless = 1,
75             NotRequired = 2,
76 
77             ftl_last = NotRequired
78         } seamlessness = Seamlessness::Undefined;
79 
80         std::string toString() const;
81     };
82 
83     class TimeStatsLayer {
84     public:
85         uid_t uid;
86         std::string layerName;
87         std::string packageName;
88         int32_t displayRefreshRateBucket = 0;
89         int32_t renderRateBucket = 0;
90         GameMode gameMode = GameMode::Unsupported;
91         int32_t totalFrames = 0;
92         int32_t droppedFrames = 0;
93         int32_t lateAcquireFrames = 0;
94         int32_t badDesiredPresentFrames = 0;
95         JankPayload jankPayload;
96         SetFrameRateVote setFrameRateVote;
97         std::unordered_map<std::string, Histogram> deltas;
98 
99         std::string toString() const;
100         SFTimeStatsLayerProto toProto() const;
101     };
102 
103     // Lifted from SkiaGLRenderEngine's LinearEffect class.
104     // Which in turn was inspired by art/runtime/class_linker.cc
105     // Also this is what boost:hash_combine does so this is a pretty good hash.
HashCombine(size_t seed,size_t val)106     static size_t HashCombine(size_t seed, size_t val) {
107         return seed ^ (val + 0x9e3779b9 + (seed << 6) + (seed >> 2));
108     }
109 
110     struct TimelineStatsKey {
111         int32_t displayRefreshRateBucket = 0;
112         int32_t renderRateBucket = 0;
113 
114         struct Hasher {
operatorTimelineStatsKey::Hasher115             size_t operator()(const TimelineStatsKey& key) const {
116                 size_t result = std::hash<int32_t>{}(key.displayRefreshRateBucket);
117                 return HashCombine(result, std::hash<int32_t>{}(key.renderRateBucket));
118             }
119         };
120 
121         bool operator==(const TimelineStatsKey& o) const {
122             return displayRefreshRateBucket == o.displayRefreshRateBucket &&
123                     renderRateBucket == o.renderRateBucket;
124         }
125     };
126 
127     struct LayerStatsKey {
128         uid_t uid = 0;
129         std::string layerName;
130         GameMode gameMode = GameMode::Unsupported;
131 
132         struct Hasher {
operatorLayerStatsKey::Hasher133             size_t operator()(const LayerStatsKey& key) const {
134                 size_t uidHash = std::hash<uid_t>{}(key.uid);
135                 size_t layerNameHash = std::hash<std::string>{}(key.layerName);
136                 using T = std::underlying_type_t<GameMode>;
137                 size_t gameModeHash = std::hash<T>{}(static_cast<T>(key.gameMode));
138                 return HashCombine(uidHash, HashCombine(layerNameHash, gameModeHash));
139             }
140         };
141 
142         bool operator==(const LayerStatsKey& o) const {
143             return uid == o.uid && layerName == o.layerName && gameMode == o.gameMode;
144         }
145     };
146 
147     struct TimelineStats {
148         TimelineStatsKey key;
149         JankPayload jankPayload;
150         Histogram displayDeadlineDeltas;
151         Histogram displayPresentDeltas;
152         std::unordered_map<LayerStatsKey, TimeStatsLayer, LayerStatsKey::Hasher> stats;
153 
clearGlobalsTimelineStats154         void clearGlobals() {
155             jankPayload = {};
156             displayDeadlineDeltas = {};
157             displayPresentDeltas = {};
158         }
159     };
160 
161     class TimeStatsGlobal {
162     public:
163         // Note: these are all legacy statistics, we're keeping these around because a variety of
164         // systems and form-factors find these useful when comparing with older releases. However,
165         // the current recommendation is that the new timeline-based metrics are used, and the old
166         // ones are deprecated.
167         int64_t statsStartLegacy = 0;
168         int64_t statsEndLegacy = 0;
169         int32_t totalFramesLegacy = 0;
170         int32_t missedFramesLegacy = 0;
171         int32_t clientCompositionFramesLegacy = 0;
172         int32_t clientCompositionReusedFramesLegacy = 0;
173         int32_t refreshRateSwitchesLegacy = 0;
174         int32_t compositionStrategyChangesLegacy = 0;
175         int32_t displayEventConnectionsCountLegacy = 0;
176         int64_t displayOnTimeLegacy = 0;
177         Histogram presentToPresentLegacy;
178         Histogram frameDurationLegacy;
179         Histogram renderEngineTimingLegacy;
180         std::unordered_map<uint32_t, nsecs_t> refreshRateStatsLegacy;
181         int32_t compositionStrategyPredictedLegacy = 0;
182         int32_t compositionStrategyPredictionSucceededLegacy = 0;
183 
184         std::unordered_map<TimelineStatsKey, TimelineStats, TimelineStatsKey::Hasher> stats;
185 
186         std::string toString(std::optional<uint32_t> maxLayers) const;
187         SFTimeStatsGlobalProto toProto(std::optional<uint32_t> maxLayers) const;
188 
189     private:
190         std::vector<TimeStatsLayer const*> generateDumpStats(
191                 std::optional<uint32_t> maxLayers) const;
192     };
193 };
194 
195 } // namespace surfaceflinger
196 } // namespace android
197