blob: dcb2988e0704f3af3572ba91ab0436b1596066d9 [file] [log] [blame]
Ana Krulecb43429d2019-01-09 14:28:51 -08001/*
2 * Copyright 2019 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 <numeric>
20
21#include "Scheduler/RefreshRateConfigs.h"
22#include "Scheduler/SchedulerUtils.h"
Alec Mourifb571ea2019-01-24 18:42:10 -080023#include "TimeStats/TimeStats.h"
Ana Krulecb43429d2019-01-09 14:28:51 -080024
25#include "android-base/stringprintf.h"
26#include "utils/Timers.h"
27
28namespace android {
29namespace scheduler {
30
31/**
32 * Class to encapsulate statistics about refresh rates that the display is using. When the power
33 * mode is set to HWC_POWER_MODE_NORMAL, SF is switching between refresh rates that are stored in
34 * the device's configs. Otherwise, we assume the HWC is running in power saving mode under the
35 * hood (eg. the device is in DOZE, or screen off mode).
36 */
37class RefreshRateStats {
38 static constexpr int64_t MS_PER_S = 1000;
39 static constexpr int64_t MS_PER_MIN = 60 * MS_PER_S;
40 static constexpr int64_t MS_PER_HOUR = 60 * MS_PER_MIN;
41 static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
42
43public:
44 explicit RefreshRateStats(
Alec Mourifb571ea2019-01-24 18:42:10 -080045 const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
46 const std::shared_ptr<TimeStats>& timeStats)
Ana Krulecb43429d2019-01-09 14:28:51 -080047 : mRefreshRateConfigs(std::make_unique<RefreshRateConfigs>(configs)),
Alec Mourifb571ea2019-01-24 18:42:10 -080048 mTimeStats(timeStats),
Ana Krulecb43429d2019-01-09 14:28:51 -080049 mPreviousRecordedTime(systemTime()) {}
50 ~RefreshRateStats() = default;
51
52 // Sets power mode. We only collect the information when the power mode is not
53 // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based
54 // on config mode.
55 void setPowerMode(int mode) {
56 if (mCurrentPowerMode == mode) {
57 return;
58 }
59 // If power mode is normal, the time is going to be recorded under config modes.
60 if (mode == HWC_POWER_MODE_NORMAL) {
61 mCurrentPowerMode = mode;
62 return;
63 }
64 flushTime();
65 mCurrentPowerMode = mode;
66 }
67
68 // Sets config mode. If the mode has changed, it records how much time was spent in the previous
69 // mode.
70 void setConfigMode(int mode) {
71 if (mCurrentConfigMode == mode) {
72 return;
73 }
74 flushTime();
75 mCurrentConfigMode = mode;
76 }
77
78 // Returns a map between human readable refresh rate and number of seconds the device spent in
79 // that mode.
80 std::unordered_map<std::string, int64_t> getTotalTimes() {
81 // If the power mode is on, then we are probably switching between the config modes. If
82 // it's not then the screen is probably off. Make sure to flush times before printing
83 // them.
84 flushTime();
85
86 std::unordered_map<std::string, int64_t> totalTime;
87 for (auto config : mRefreshRateConfigs->getRefreshRates()) {
Ana Krulec4593b692019-01-11 22:07:25 -080088 int64_t totalTimeForConfig = 0;
Ana Krulecb43429d2019-01-09 14:28:51 -080089 if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) {
Ana Krulec4593b692019-01-11 22:07:25 -080090 totalTimeForConfig = mConfigModesTotalTime.at(config.configId);
Ana Krulecb43429d2019-01-09 14:28:51 -080091 }
Ana Krulec4593b692019-01-11 22:07:25 -080092 totalTime[config.name] = totalTimeForConfig;
Ana Krulecb43429d2019-01-09 14:28:51 -080093 }
94 return totalTime;
95 }
96
97 // Traverses through the map of config modes and returns how long they've been running in easy
98 // to read format.
99 std::string doDump() {
100 std::ostringstream stream;
101 stream << "+ Refresh rate: running time in seconds\n";
102 for (auto stats : getTotalTimes()) {
103 stream << stats.first.c_str() << ": " << getDateFormatFromMs(stats.second) << "\n";
104 }
105 return stream.str();
106 }
107
108private:
109 void flushTime() {
110 // Normal power mode is counted under different config modes.
111 if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
112 flushTimeForMode(mCurrentConfigMode);
113 } else {
114 flushTimeForMode(SCREEN_OFF_CONFIG_ID);
115 }
116 }
117
118 // Calculates the time that passed in ms between the last time we recorded time and the time
119 // this method was called.
120 void flushTimeForMode(int mode) {
121 nsecs_t currentTime = systemTime();
Alec Mourifb571ea2019-01-24 18:42:10 -0800122 nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
123 int64_t timeElapsedMs = ns2ms(timeElapsed);
Ana Krulecb43429d2019-01-09 14:28:51 -0800124 mPreviousRecordedTime = currentTime;
125
126 mConfigModesTotalTime[mode] += timeElapsedMs;
Alec Mourifb571ea2019-01-24 18:42:10 -0800127 for (const auto& config : mRefreshRateConfigs->getRefreshRates()) {
128 if (config.configId == mode) {
129 mTimeStats->recordRefreshRate(config.fps, timeElapsed);
130 }
131 }
Ana Krulecb43429d2019-01-09 14:28:51 -0800132 }
133
134 // Formats the time in milliseconds into easy to read format.
135 static std::string getDateFormatFromMs(int64_t timeMs) {
136 auto [days, dayRemainderMs] = std::div(timeMs, MS_PER_DAY);
137 auto [hours, hourRemainderMs] = std::div(dayRemainderMs, MS_PER_HOUR);
138 auto [mins, minsRemainderMs] = std::div(hourRemainderMs, MS_PER_MIN);
139 auto [sec, secRemainderMs] = std::div(minsRemainderMs, MS_PER_S);
140 return base::StringPrintf("%" PRId64 "d%02" PRId64 ":%02" PRId64 ":%02" PRId64
141 ".%03" PRId64,
142 days, hours, mins, sec, secRemainderMs);
143 }
144
145 // Keeps information about refresh rate configs that device has.
146 std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
147
Alec Mourifb571ea2019-01-24 18:42:10 -0800148 // Aggregate refresh rate statistics for telemetry.
149 std::shared_ptr<TimeStats> mTimeStats;
150
Ana Krulecb43429d2019-01-09 14:28:51 -0800151 int64_t mCurrentConfigMode = 0;
152 int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
153
154 std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime;
155
156 nsecs_t mPreviousRecordedTime;
157};
158
159} // namespace scheduler
Alec Mourifb571ea2019-01-24 18:42:10 -0800160} // namespace android