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