| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #pragma once |
| |
| #include <timestatsproto/TimeStatsProtoHeader.h> |
| #include <utils/Timers.h> |
| |
| #include <optional> |
| #include <string> |
| #include <unordered_map> |
| #include <vector> |
| |
| namespace android { |
| namespace surfaceflinger { |
| |
| class TimeStatsHelper { |
| public: |
| class Histogram { |
| public: |
| // Key is the delta time between timestamps |
| // Value is the number of appearances of that delta |
| std::unordered_map<int32_t, int32_t> hist; |
| |
| void insert(int32_t delta); |
| int64_t totalTime() const; |
| float averageTime() const; |
| std::string toString() const; |
| }; |
| |
| struct JankPayload { |
| // note that transactions are counted for these frames. |
| int32_t totalFrames = 0; |
| int32_t totalJankyFrames = 0; |
| int32_t totalSFLongCpu = 0; |
| int32_t totalSFLongGpu = 0; |
| int32_t totalSFUnattributed = 0; |
| int32_t totalAppUnattributed = 0; |
| int32_t totalSFScheduling = 0; |
| int32_t totalSFPredictionError = 0; |
| int32_t totalAppBufferStuffing = 0; |
| |
| std::string toString() const; |
| }; |
| |
| struct SetFrameRateVote { |
| float frameRate = 0; |
| |
| // Needs to be in sync with atoms.proto |
| enum class FrameRateCompatibility { |
| Undefined = 0, |
| Default = 1, |
| ExactOrMultiple = 2, |
| } frameRateCompatibility = FrameRateCompatibility::Undefined; |
| |
| // Needs to be in sync with atoms.proto |
| enum class Seamlessness { |
| Undefined = 0, |
| ShouldBeSeamless = 1, |
| NotRequired = 2, |
| } seamlessness = Seamlessness::Undefined; |
| |
| static std::string toString(FrameRateCompatibility); |
| static std::string toString(Seamlessness); |
| std::string toString() const; |
| }; |
| |
| /** |
| * GameMode of the layer. GameModes are set by SysUI through WMShell. |
| * Actual game mode definitions are managed by GameManager.java |
| * The values defined here should always be in sync with the ones in GameManager. |
| */ |
| enum GameMode { |
| GameModeUnsupported = 0, |
| GameModeStandard = 1, |
| GameModePerformance = 2, |
| GameModeBattery = 3, |
| }; |
| |
| class TimeStatsLayer { |
| public: |
| uid_t uid; |
| std::string layerName; |
| std::string packageName; |
| int32_t displayRefreshRateBucket = 0; |
| int32_t renderRateBucket = 0; |
| int32_t gameMode = 0; |
| int32_t totalFrames = 0; |
| int32_t droppedFrames = 0; |
| int32_t lateAcquireFrames = 0; |
| int32_t badDesiredPresentFrames = 0; |
| JankPayload jankPayload; |
| SetFrameRateVote setFrameRateVote; |
| std::unordered_map<std::string, Histogram> deltas; |
| |
| std::string toString() const; |
| std::string toString(int32_t gameMode) const; |
| SFTimeStatsLayerProto toProto() const; |
| }; |
| |
| // Lifted from SkiaGLRenderEngine's LinearEffect class. |
| // Which in turn was inspired by art/runtime/class_linker.cc |
| // Also this is what boost:hash_combine does so this is a pretty good hash. |
| static size_t HashCombine(size_t seed, size_t val) { |
| return seed ^ (val + 0x9e3779b9 + (seed << 6) + (seed >> 2)); |
| } |
| |
| struct TimelineStatsKey { |
| int32_t displayRefreshRateBucket = 0; |
| int32_t renderRateBucket = 0; |
| |
| struct Hasher { |
| size_t operator()(const TimelineStatsKey& key) const { |
| size_t result = std::hash<int32_t>{}(key.displayRefreshRateBucket); |
| return HashCombine(result, std::hash<int32_t>{}(key.renderRateBucket)); |
| } |
| }; |
| |
| bool operator==(const TimelineStatsKey& o) const { |
| return displayRefreshRateBucket == o.displayRefreshRateBucket && |
| renderRateBucket == o.renderRateBucket; |
| } |
| }; |
| |
| struct LayerStatsKey { |
| uid_t uid = 0; |
| std::string layerName; |
| int32_t gameMode = 0; |
| |
| struct Hasher { |
| size_t operator()(const LayerStatsKey& key) const { |
| size_t uidHash = std::hash<uid_t>{}(key.uid); |
| size_t layerNameHash = std::hash<std::string>{}(key.layerName); |
| size_t gameModeHash = std::hash<int32_t>{}(key.gameMode); |
| return HashCombine(uidHash, HashCombine(layerNameHash, gameModeHash)); |
| } |
| }; |
| |
| bool operator==(const LayerStatsKey& o) const { |
| return uid == o.uid && layerName == o.layerName && gameMode == o.gameMode; |
| } |
| }; |
| |
| struct TimelineStats { |
| TimelineStatsKey key; |
| JankPayload jankPayload; |
| Histogram displayDeadlineDeltas; |
| Histogram displayPresentDeltas; |
| std::unordered_map<LayerStatsKey, TimeStatsLayer, LayerStatsKey::Hasher> stats; |
| |
| void clearGlobals() { |
| jankPayload = {}; |
| displayDeadlineDeltas = {}; |
| displayPresentDeltas = {}; |
| } |
| }; |
| |
| class TimeStatsGlobal { |
| public: |
| // Note: these are all legacy statistics, we're keeping these around because a variety of |
| // systems and form-factors find these useful when comparing with older releases. However, |
| // the current recommendation is that the new timeline-based metrics are used, and the old |
| // ones are deprecated. |
| int64_t statsStartLegacy = 0; |
| int64_t statsEndLegacy = 0; |
| int32_t totalFramesLegacy = 0; |
| int32_t missedFramesLegacy = 0; |
| int32_t clientCompositionFramesLegacy = 0; |
| int32_t clientCompositionReusedFramesLegacy = 0; |
| int32_t refreshRateSwitchesLegacy = 0; |
| int32_t compositionStrategyChangesLegacy = 0; |
| int32_t displayEventConnectionsCountLegacy = 0; |
| int64_t displayOnTimeLegacy = 0; |
| Histogram presentToPresentLegacy; |
| Histogram frameDurationLegacy; |
| Histogram renderEngineTimingLegacy; |
| std::unordered_map<uint32_t, nsecs_t> refreshRateStatsLegacy; |
| |
| std::unordered_map<TimelineStatsKey, TimelineStats, TimelineStatsKey::Hasher> stats; |
| |
| std::string toString(std::optional<uint32_t> maxLayers) const; |
| SFTimeStatsGlobalProto toProto(std::optional<uint32_t> maxLayers) const; |
| |
| private: |
| std::vector<TimeStatsLayer const*> generateDumpStats( |
| std::optional<uint32_t> maxLayers) const; |
| }; |
| }; |
| |
| } // namespace surfaceflinger |
| } // namespace android |