Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.h 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * Copyright 2019 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 <algorithm> #include <numeric> #include "Scheduler/SchedulerUtils.h" #include "android-base/stringprintf.h" namespace android { namespace scheduler { /** * This class is used to encapsulate configuration for refresh rates. It holds infomation * about available refresh rates on the device, and the mapping between the numbers and human * readable names. */ class RefreshRateConfigs { public: // Enum to indicate which vsync rate to run at. Power saving is intended to be the lowest // (eg. when the screen is in AOD mode or off), default is the old 60Hz, and performance // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs. enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE }; struct RefreshRate { // Type of the refresh rate. RefreshRateType type; // This config ID corresponds to the position of the config in the vector that is stored // on the device. int configId; // Human readable name of the refresh rate. std::string name; }; // TODO(b/122916473): Get this information from configs prepared by vendors, instead of // baking them in. explicit RefreshRateConfigs( const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) { // This is the rate that HWC encapsulates right now when the screen is off. RefreshRate rate; rate.type = RefreshRateType::POWER_SAVING; rate.configId = SCREEN_OFF_CONFIG_ID; rate.name = "ScreenOff"; mRefreshRates.push_back(rate); if (configs.size() < 1) { return; } std::vector<std::pair<int, nsecs_t>> configIdToVsyncPeriod; for (int i = 0; i < configs.size(); ++i) { configIdToVsyncPeriod.push_back(std::make_pair(i, configs.at(i)->getVsyncPeriod())); } std::sort(configIdToVsyncPeriod.begin(), configIdToVsyncPeriod.end(), [](const std::pair<int, nsecs_t>& a, const std::pair<int, nsecs_t>& b) { return a.second > b.second; }); nsecs_t vsyncPeriod = configIdToVsyncPeriod.at(0).second; if (vsyncPeriod != 0) { const float fps = std::chrono::nanoseconds(1).count() / vsyncPeriod; rate.type = RefreshRateType::DEFAULT; rate.configId = configIdToVsyncPeriod.at(0).first; rate.name = base::StringPrintf("%2.ffps", fps); mRefreshRates.push_back(rate); } if (configs.size() < 2) { return; } vsyncPeriod = configIdToVsyncPeriod.at(1).second; if (vsyncPeriod != 0) { const float fps = std::chrono::nanoseconds(1).count() / vsyncPeriod; rate.type = RefreshRateType::PERFORMANCE; rate.configId = configIdToVsyncPeriod.at(1).first; rate.name = base::StringPrintf("%2.ffps", fps); mRefreshRates.push_back(rate); } for (auto refreshRate : mRefreshRates) { ALOGV("type: %d, id: %d, name: %s", refreshRate.type, refreshRate.configId, refreshRate.name.c_str()); } } ~RefreshRateConfigs() = default; const std::vector<RefreshRate>& getRefreshRates() { return mRefreshRates; } private: std::vector<RefreshRate> mRefreshRates; }; } // namespace scheduler } // namespace android No newline at end of file services/surfaceflinger/Scheduler/RefreshRateStats.h 0 → 100644 +146 −0 Original line number Diff line number Diff line /* * Copyright 2019 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 <numeric> #include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/SchedulerUtils.h" #include "android-base/stringprintf.h" #include "utils/Timers.h" namespace android { namespace scheduler { /** * Class to encapsulate statistics about refresh rates that the display is using. When the power * mode is set to HWC_POWER_MODE_NORMAL, SF is switching between refresh rates that are stored in * the device's configs. Otherwise, we assume the HWC is running in power saving mode under the * hood (eg. the device is in DOZE, or screen off mode). */ class RefreshRateStats { static constexpr int64_t MS_PER_S = 1000; static constexpr int64_t MS_PER_MIN = 60 * MS_PER_S; static constexpr int64_t MS_PER_HOUR = 60 * MS_PER_MIN; static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR; public: explicit RefreshRateStats( const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) : mRefreshRateConfigs(std::make_unique<RefreshRateConfigs>(configs)), mPreviousRecordedTime(systemTime()) {} ~RefreshRateStats() = default; // Sets power mode. We only collect the information when the power mode is not // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based // on config mode. void setPowerMode(int mode) { if (mCurrentPowerMode == mode) { return; } // If power mode is normal, the time is going to be recorded under config modes. if (mode == HWC_POWER_MODE_NORMAL) { mCurrentPowerMode = mode; return; } flushTime(); mCurrentPowerMode = mode; } // Sets config mode. If the mode has changed, it records how much time was spent in the previous // mode. void setConfigMode(int mode) { if (mCurrentConfigMode == mode) { return; } flushTime(); mCurrentConfigMode = mode; } // Returns a map between human readable refresh rate and number of seconds the device spent in // that mode. std::unordered_map<std::string, int64_t> getTotalTimes() { // If the power mode is on, then we are probably switching between the config modes. If // it's not then the screen is probably off. Make sure to flush times before printing // them. flushTime(); std::unordered_map<std::string, int64_t> totalTime; for (auto config : mRefreshRateConfigs->getRefreshRates()) { if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) { totalTime[config.name] = mConfigModesTotalTime.at(config.configId); } } return totalTime; } // Traverses through the map of config modes and returns how long they've been running in easy // to read format. std::string doDump() { std::ostringstream stream; stream << "+ Refresh rate: running time in seconds\n"; for (auto stats : getTotalTimes()) { stream << stats.first.c_str() << ": " << getDateFormatFromMs(stats.second) << "\n"; } return stream.str(); } private: void flushTime() { // Normal power mode is counted under different config modes. if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) { flushTimeForMode(mCurrentConfigMode); } else { flushTimeForMode(SCREEN_OFF_CONFIG_ID); } } // Calculates the time that passed in ms between the last time we recorded time and the time // this method was called. void flushTimeForMode(int mode) { nsecs_t currentTime = systemTime(); int64_t timeElapsedMs = ns2ms(currentTime - mPreviousRecordedTime); mPreviousRecordedTime = currentTime; mConfigModesTotalTime[mode] += timeElapsedMs; } // Formats the time in milliseconds into easy to read format. static std::string getDateFormatFromMs(int64_t timeMs) { auto [days, dayRemainderMs] = std::div(timeMs, MS_PER_DAY); auto [hours, hourRemainderMs] = std::div(dayRemainderMs, MS_PER_HOUR); auto [mins, minsRemainderMs] = std::div(hourRemainderMs, MS_PER_MIN); auto [sec, secRemainderMs] = std::div(minsRemainderMs, MS_PER_S); return base::StringPrintf("%" PRId64 "d%02" PRId64 ":%02" PRId64 ":%02" PRId64 ".%03" PRId64, days, hours, mins, sec, secRemainderMs); } // Keeps information about refresh rate configs that device has. std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs; int64_t mCurrentConfigMode = 0; int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF; std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime; nsecs_t mPreviousRecordedTime; }; } // namespace scheduler } // namespace android No newline at end of file services/surfaceflinger/Scheduler/Scheduler.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -352,4 +352,10 @@ void Scheduler::expiredTimerCallback() { } } std::string Scheduler::doDump() { std::ostringstream stream; stream << "+ Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl; return stream.str(); } } // namespace android services/surfaceflinger/Scheduler/Scheduler.h +2 −0 Original line number Diff line number Diff line Loading @@ -118,6 +118,8 @@ public: void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback); // Callback that gets invoked once the idle timer is reset. void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback); // Returns relevant information about Scheduler for dumpsys purposes. std::string doDump(); protected: virtual std::unique_ptr<EventThread> makeEventThread( Loading services/surfaceflinger/Scheduler/SchedulerUtils.h +5 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,11 @@ namespace scheduler { // about layers. static constexpr size_t ARRAY_SIZE = 30; // This number is used to have a place holder for when the screen is not NORMAL/ON. Currently // the config is not visible to SF, and is completely maintained by HWC. However, we would // still like to keep track of time when the device is in this config. static constexpr int SCREEN_OFF_CONFIG_ID = -1; // Calculates the statistical mean (average) in the data structure (array, vector). The // function does not modify the contents of the array. template <typename T> Loading Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.h 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * Copyright 2019 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 <algorithm> #include <numeric> #include "Scheduler/SchedulerUtils.h" #include "android-base/stringprintf.h" namespace android { namespace scheduler { /** * This class is used to encapsulate configuration for refresh rates. It holds infomation * about available refresh rates on the device, and the mapping between the numbers and human * readable names. */ class RefreshRateConfigs { public: // Enum to indicate which vsync rate to run at. Power saving is intended to be the lowest // (eg. when the screen is in AOD mode or off), default is the old 60Hz, and performance // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs. enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE }; struct RefreshRate { // Type of the refresh rate. RefreshRateType type; // This config ID corresponds to the position of the config in the vector that is stored // on the device. int configId; // Human readable name of the refresh rate. std::string name; }; // TODO(b/122916473): Get this information from configs prepared by vendors, instead of // baking them in. explicit RefreshRateConfigs( const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) { // This is the rate that HWC encapsulates right now when the screen is off. RefreshRate rate; rate.type = RefreshRateType::POWER_SAVING; rate.configId = SCREEN_OFF_CONFIG_ID; rate.name = "ScreenOff"; mRefreshRates.push_back(rate); if (configs.size() < 1) { return; } std::vector<std::pair<int, nsecs_t>> configIdToVsyncPeriod; for (int i = 0; i < configs.size(); ++i) { configIdToVsyncPeriod.push_back(std::make_pair(i, configs.at(i)->getVsyncPeriod())); } std::sort(configIdToVsyncPeriod.begin(), configIdToVsyncPeriod.end(), [](const std::pair<int, nsecs_t>& a, const std::pair<int, nsecs_t>& b) { return a.second > b.second; }); nsecs_t vsyncPeriod = configIdToVsyncPeriod.at(0).second; if (vsyncPeriod != 0) { const float fps = std::chrono::nanoseconds(1).count() / vsyncPeriod; rate.type = RefreshRateType::DEFAULT; rate.configId = configIdToVsyncPeriod.at(0).first; rate.name = base::StringPrintf("%2.ffps", fps); mRefreshRates.push_back(rate); } if (configs.size() < 2) { return; } vsyncPeriod = configIdToVsyncPeriod.at(1).second; if (vsyncPeriod != 0) { const float fps = std::chrono::nanoseconds(1).count() / vsyncPeriod; rate.type = RefreshRateType::PERFORMANCE; rate.configId = configIdToVsyncPeriod.at(1).first; rate.name = base::StringPrintf("%2.ffps", fps); mRefreshRates.push_back(rate); } for (auto refreshRate : mRefreshRates) { ALOGV("type: %d, id: %d, name: %s", refreshRate.type, refreshRate.configId, refreshRate.name.c_str()); } } ~RefreshRateConfigs() = default; const std::vector<RefreshRate>& getRefreshRates() { return mRefreshRates; } private: std::vector<RefreshRate> mRefreshRates; }; } // namespace scheduler } // namespace android No newline at end of file
services/surfaceflinger/Scheduler/RefreshRateStats.h 0 → 100644 +146 −0 Original line number Diff line number Diff line /* * Copyright 2019 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 <numeric> #include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/SchedulerUtils.h" #include "android-base/stringprintf.h" #include "utils/Timers.h" namespace android { namespace scheduler { /** * Class to encapsulate statistics about refresh rates that the display is using. When the power * mode is set to HWC_POWER_MODE_NORMAL, SF is switching between refresh rates that are stored in * the device's configs. Otherwise, we assume the HWC is running in power saving mode under the * hood (eg. the device is in DOZE, or screen off mode). */ class RefreshRateStats { static constexpr int64_t MS_PER_S = 1000; static constexpr int64_t MS_PER_MIN = 60 * MS_PER_S; static constexpr int64_t MS_PER_HOUR = 60 * MS_PER_MIN; static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR; public: explicit RefreshRateStats( const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) : mRefreshRateConfigs(std::make_unique<RefreshRateConfigs>(configs)), mPreviousRecordedTime(systemTime()) {} ~RefreshRateStats() = default; // Sets power mode. We only collect the information when the power mode is not // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based // on config mode. void setPowerMode(int mode) { if (mCurrentPowerMode == mode) { return; } // If power mode is normal, the time is going to be recorded under config modes. if (mode == HWC_POWER_MODE_NORMAL) { mCurrentPowerMode = mode; return; } flushTime(); mCurrentPowerMode = mode; } // Sets config mode. If the mode has changed, it records how much time was spent in the previous // mode. void setConfigMode(int mode) { if (mCurrentConfigMode == mode) { return; } flushTime(); mCurrentConfigMode = mode; } // Returns a map between human readable refresh rate and number of seconds the device spent in // that mode. std::unordered_map<std::string, int64_t> getTotalTimes() { // If the power mode is on, then we are probably switching between the config modes. If // it's not then the screen is probably off. Make sure to flush times before printing // them. flushTime(); std::unordered_map<std::string, int64_t> totalTime; for (auto config : mRefreshRateConfigs->getRefreshRates()) { if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) { totalTime[config.name] = mConfigModesTotalTime.at(config.configId); } } return totalTime; } // Traverses through the map of config modes and returns how long they've been running in easy // to read format. std::string doDump() { std::ostringstream stream; stream << "+ Refresh rate: running time in seconds\n"; for (auto stats : getTotalTimes()) { stream << stats.first.c_str() << ": " << getDateFormatFromMs(stats.second) << "\n"; } return stream.str(); } private: void flushTime() { // Normal power mode is counted under different config modes. if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) { flushTimeForMode(mCurrentConfigMode); } else { flushTimeForMode(SCREEN_OFF_CONFIG_ID); } } // Calculates the time that passed in ms between the last time we recorded time and the time // this method was called. void flushTimeForMode(int mode) { nsecs_t currentTime = systemTime(); int64_t timeElapsedMs = ns2ms(currentTime - mPreviousRecordedTime); mPreviousRecordedTime = currentTime; mConfigModesTotalTime[mode] += timeElapsedMs; } // Formats the time in milliseconds into easy to read format. static std::string getDateFormatFromMs(int64_t timeMs) { auto [days, dayRemainderMs] = std::div(timeMs, MS_PER_DAY); auto [hours, hourRemainderMs] = std::div(dayRemainderMs, MS_PER_HOUR); auto [mins, minsRemainderMs] = std::div(hourRemainderMs, MS_PER_MIN); auto [sec, secRemainderMs] = std::div(minsRemainderMs, MS_PER_S); return base::StringPrintf("%" PRId64 "d%02" PRId64 ":%02" PRId64 ":%02" PRId64 ".%03" PRId64, days, hours, mins, sec, secRemainderMs); } // Keeps information about refresh rate configs that device has. std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs; int64_t mCurrentConfigMode = 0; int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF; std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime; nsecs_t mPreviousRecordedTime; }; } // namespace scheduler } // namespace android No newline at end of file
services/surfaceflinger/Scheduler/Scheduler.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -352,4 +352,10 @@ void Scheduler::expiredTimerCallback() { } } std::string Scheduler::doDump() { std::ostringstream stream; stream << "+ Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl; return stream.str(); } } // namespace android
services/surfaceflinger/Scheduler/Scheduler.h +2 −0 Original line number Diff line number Diff line Loading @@ -118,6 +118,8 @@ public: void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback); // Callback that gets invoked once the idle timer is reset. void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback); // Returns relevant information about Scheduler for dumpsys purposes. std::string doDump(); protected: virtual std::unique_ptr<EventThread> makeEventThread( Loading
services/surfaceflinger/Scheduler/SchedulerUtils.h +5 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,11 @@ namespace scheduler { // about layers. static constexpr size_t ARRAY_SIZE = 30; // This number is used to have a place holder for when the screen is not NORMAL/ON. Currently // the config is not visible to SF, and is completely maintained by HWC. However, we would // still like to keep track of time when the device is in this config. static constexpr int SCREEN_OFF_CONFIG_ID = -1; // Calculates the statistical mean (average) in the data structure (array, vector). The // function does not modify the contents of the array. template <typename T> Loading