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