blob: cd81e4da1eb9eb993052dcf07036de7241e558c2 [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()) {
85 if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) {
86 totalTime[config.name] = mConfigModesTotalTime.at(config.configId);
87 }
88 }
89 return totalTime;
90 }
91
92 // Traverses through the map of config modes and returns how long they've been running in easy
93 // to read format.
94 std::string doDump() {
95 std::ostringstream stream;
96 stream << "+ Refresh rate: running time in seconds\n";
97 for (auto stats : getTotalTimes()) {
98 stream << stats.first.c_str() << ": " << getDateFormatFromMs(stats.second) << "\n";
99 }
100 return stream.str();
101 }
102
103private:
104 void flushTime() {
105 // Normal power mode is counted under different config modes.
106 if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
107 flushTimeForMode(mCurrentConfigMode);
108 } else {
109 flushTimeForMode(SCREEN_OFF_CONFIG_ID);
110 }
111 }
112
113 // Calculates the time that passed in ms between the last time we recorded time and the time
114 // this method was called.
115 void flushTimeForMode(int mode) {
116 nsecs_t currentTime = systemTime();
117 int64_t timeElapsedMs = ns2ms(currentTime - mPreviousRecordedTime);
118 mPreviousRecordedTime = currentTime;
119
120 mConfigModesTotalTime[mode] += timeElapsedMs;
121 }
122
123 // Formats the time in milliseconds into easy to read format.
124 static std::string getDateFormatFromMs(int64_t timeMs) {
125 auto [days, dayRemainderMs] = std::div(timeMs, MS_PER_DAY);
126 auto [hours, hourRemainderMs] = std::div(dayRemainderMs, MS_PER_HOUR);
127 auto [mins, minsRemainderMs] = std::div(hourRemainderMs, MS_PER_MIN);
128 auto [sec, secRemainderMs] = std::div(minsRemainderMs, MS_PER_S);
129 return base::StringPrintf("%" PRId64 "d%02" PRId64 ":%02" PRId64 ":%02" PRId64
130 ".%03" PRId64,
131 days, hours, mins, sec, secRemainderMs);
132 }
133
134 // Keeps information about refresh rate configs that device has.
135 std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
136
137 int64_t mCurrentConfigMode = 0;
138 int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
139
140 std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime;
141
142 nsecs_t mPreviousRecordedTime;
143};
144
145} // namespace scheduler
146} // namespace android