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

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

Merge "SF: Adding statistical mode"

parents 75cc36e4 434c22db
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -143,6 +143,7 @@ filegroup {
        "Scheduler/LayerHistory.cpp",
        "Scheduler/MessageQueue.cpp",
        "Scheduler/Scheduler.cpp",
        "Scheduler/SchedulerUtils.cpp",
        "StartPropertySetThread.cpp",
        "SurfaceFlinger.cpp",
        "SurfaceInterceptor.cpp",
+5 −2
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@
#include <utils/Timers.h>
#include <utils/Trace.h>

#include "SchedulerUtils.h"

namespace android {

LayerHistory::LayerHistory() {}
@@ -38,7 +40,7 @@ void LayerHistory::insert(const std::string layerName, nsecs_t presentTime) {

void LayerHistory::incrementCounter() {
    mCounter++;
    mCounter = mCounter % ARRAY_SIZE;
    mCounter = mCounter % scheduler::ARRAY_SIZE;
    // Clear all the previous data from the history. This is a ring buffer, so we are
    // reusing memory.
    mElements[mCounter].clear();
@@ -47,7 +49,8 @@ void LayerHistory::incrementCounter() {
const std::unordered_map<std::string, nsecs_t>& LayerHistory::get(size_t index) const {
    // For the purposes of the layer history, the index = 0 always needs to start at the
    // current counter, and then decrement to access the layers in correct historical order.
    return mElements.at((ARRAY_SIZE + (mCounter - (index % ARRAY_SIZE))) % ARRAY_SIZE);
    return mElements.at((scheduler::ARRAY_SIZE + (mCounter - (index % scheduler::ARRAY_SIZE))) %
                        scheduler::ARRAY_SIZE);
}

} // namespace android
 No newline at end of file
+4 −3
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@

#include <utils/Timers.h>

#include "SchedulerUtils.h"

namespace android {

/*
@@ -52,12 +54,11 @@ public:
    const std::unordered_map<std::string, nsecs_t>& get(size_t index) const;
    // Returns the total size of the ring buffer. The value is always the same regardless
    // of how many slots we filled in.
    static constexpr size_t getSize() { return ARRAY_SIZE; }
    static constexpr size_t getSize() { return scheduler::ARRAY_SIZE; }

private:
    size_t mCounter = 0;
    static constexpr size_t ARRAY_SIZE = 30;
    std::array<std::unordered_map<std::string, nsecs_t>, ARRAY_SIZE> mElements;
    std::array<std::unordered_map<std::string, nsecs_t>, scheduler::ARRAY_SIZE> mElements;
};

} // namespace android
 No newline at end of file
+24 −36
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include "Scheduler.h"

#include <algorithm>
#include <cinttypes>
#include <cstdint>
#include <memory>
@@ -38,6 +39,7 @@
#include "EventControlThread.h"
#include "EventThread.h"
#include "InjectVSyncSource.h"
#include "SchedulerUtils.h"

namespace android {

@@ -222,11 +224,6 @@ void Scheduler::incrementFrameCounter() {
    mLayerHistory.incrementCounter();
}

nsecs_t Scheduler::calculateAverage() const {
    nsecs_t sum = std::accumulate(mTimeDifferences.begin(), mTimeDifferences.end(), 0);
    return (sum / ARRAY_SIZE);
}

void Scheduler::updateFrameSkipping(const int64_t skipCount) {
    ATRACE_INT("FrameSkipCount", skipCount);
    if (mSkipCount != skipCount) {
@@ -243,6 +240,7 @@ void Scheduler::determineLayerTimestampStats(const std::string layerName,

    // Traverse through the layer history, and determine the differences in present times.
    nsecs_t newestPresentTime = framePresentTime;
    std::string differencesText = "";
    for (int i = 1; i < mLayerHistory.getSize(); i++) {
        std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i);
        for (auto layer : layers) {
@@ -250,39 +248,31 @@ void Scheduler::determineLayerTimestampStats(const std::string layerName,
                continue;
            }
            int64_t differenceMs = (newestPresentTime - layer.second) / 1000000;
            ALOGD("%d Layer %s: %" PRId64, i, layerName.c_str(), differenceMs);
            // Dismiss noise.
            if (differenceMs > 10 && differenceMs < 60) {
                differencesMs.push_back(differenceMs);
            }
            IF_ALOGV() { differencesText += (std::to_string(differenceMs) + " "); }
            newestPresentTime = layer.second;
        }
    }
    // Average is a good indicator for when 24fps videos are playing, because the frames come in
    // 33, and 49 ms intervals with occasional 41ms.
    int64_t average =
            std::accumulate(differencesMs.begin(), differencesMs.end(), 0) / differencesMs.size();
    const auto tag = "TimestampAvg_" + layerName;
    ATRACE_INT(tag.c_str(), average);
    ALOGV("Layer %s timestamp intervals: %s", layerName.c_str(), differencesText.c_str());

    if (!differencesMs.empty()) {
        // Mean/Average is a good indicator for when 24fps videos are playing, because the frames
        // come in 33, and 49 ms intervals with occasional 41ms.
        const int64_t meanMs = scheduler::calculate_mean(differencesMs);
        const auto tagMean = "TimestampMean_" + layerName;
        ATRACE_INT(tagMean.c_str(), meanMs);

    // Mode and median are good indicators for 30 and 60 fps videos, because the majority of frames
    // come in 16, or 33 ms intervals.
    // TODO(b/113612090): Calculate mode. Median is good for now, since we want a given interval to
    // repeat at least ARRAY_SIZE/2 + 1 times.
    if (differencesMs.size() > 0) {
        // Mode and median are good indicators for 30 and 60 fps videos, because the majority of
        // frames come in 16, or 33 ms intervals.
        const auto tagMedian = "TimestampMedian_" + layerName;
        ATRACE_INT(tagMedian.c_str(), calculateMedian(&differencesMs));
    }
}
        ATRACE_INT(tagMedian.c_str(), scheduler::calculate_median(&differencesMs));

int64_t Scheduler::calculateMedian(std::vector<int64_t>* v) {
    if (!v || v->size() == 0) {
        return 0;
        const auto tagMode = "TimestampMode_" + layerName;
        ATRACE_INT(tagMode.c_str(), scheduler::calculate_mode(differencesMs));
    }

    size_t n = v->size() / 2;
    nth_element(v->begin(), v->begin() + n, v->end());
    return v->at(n);
}

void Scheduler::determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime) {
@@ -302,23 +292,21 @@ void Scheduler::determineTimestampAverage(bool isAutoTimestamp, const nsecs_t fr
    }
    ATRACE_INT("TimestampDiff", differenceMs);

    mTimeDifferences[mCounter % ARRAY_SIZE] = differenceMs;
    mTimeDifferences[mCounter % scheduler::ARRAY_SIZE] = differenceMs;
    mCounter++;
    nsecs_t average = calculateAverage();
    ATRACE_INT("TimestampAverage", average);
    int64_t mean = scheduler::calculate_mean(mTimeDifferences);
    ATRACE_INT("AutoTimestampMean", mean);

    // TODO(b/113612090): This are current numbers from trial and error while running videos
    // from YouTube at 24, 30, and 60 fps.
    if (average > 14 && average < 18) {
    if (mean > 14 && mean < 18) {
        ATRACE_INT("FPS", 60);
    } else if (average > 31 && average < 34) {
    } else if (mean > 31 && mean < 34) {
        ATRACE_INT("FPS", 30);
        updateFrameSkipping(1);
        return;
    } else if (average > 39 && average < 42) {
    } else if (mean > 39 && mean < 42) {
        ATRACE_INT("FPS", 24);
    }
    updateFrameSkipping(0);
}

} // namespace android
+2 −7
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include "EventThread.h"
#include "InjectVSyncSource.h"
#include "LayerHistory.h"
#include "SchedulerUtils.h"

namespace android {

@@ -111,8 +112,6 @@ public:
    void incrementFrameCounter();

protected:
    friend class SchedulerTest;

    virtual std::unique_ptr<EventThread> makeEventThread(
            const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
            impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
@@ -124,9 +123,6 @@ private:
    // Collects the statistical mean (average) and median between timestamp
    // intervals for each frame for each layer.
    void determineLayerTimestampStats(const std::string layerName, const nsecs_t framePresentTime);
    // Calculates the statistical median in the vector. Return 0 if the vector is empty. The
    // function modifies the vector contents.
    int64_t calculateMedian(std::vector<int64_t>* v);
    // Collects the average difference between timestamps for each frame regardless
    // of which layer the timestamp came from.
    void determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime);
@@ -163,8 +159,7 @@ private:
    // simulate 30Hz rendering, we skip every other frame, and this variable is set
    // to 1.
    int64_t mSkipCount = 0;
    static constexpr size_t ARRAY_SIZE = 30;
    std::array<int64_t, ARRAY_SIZE> mTimeDifferences;
    std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{};
    size_t mCounter = 0;

    LayerHistory mLayerHistory;
Loading