Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c224077d authored by Ana Krulec's avatar Ana Krulec Committed by Android (Google) Code Review
Browse files

Merge "SF: Adding Scheduler information into dumpsys"

parents db8e15a3 b43429d9
Loading
Loading
Loading
Loading
+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
+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
+6 −0
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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(
+5 −0
Original line number Diff line number Diff line
@@ -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