Loading services/surfaceflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -143,6 +143,7 @@ filegroup { "Scheduler/LayerHistory.cpp", "Scheduler/MessageQueue.cpp", "Scheduler/Scheduler.cpp", "Scheduler/SchedulerUtils.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", "SurfaceInterceptor.cpp", Loading services/surfaceflinger/Scheduler/LayerHistory.cpp +5 −2 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ #include <utils/Timers.h> #include <utils/Trace.h> #include "SchedulerUtils.h" namespace android { LayerHistory::LayerHistory() {} Loading @@ -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(); Loading @@ -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 services/surfaceflinger/Scheduler/LayerHistory.h +4 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ #include <utils/Timers.h> #include "SchedulerUtils.h" namespace android { /* Loading Loading @@ -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 services/surfaceflinger/Scheduler/Scheduler.cpp +24 −36 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "Scheduler.h" #include <algorithm> #include <cinttypes> #include <cstdint> #include <memory> Loading @@ -38,6 +39,7 @@ #include "EventControlThread.h" #include "EventThread.h" #include "InjectVSyncSource.h" #include "SchedulerUtils.h" namespace android { Loading Loading @@ -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) { Loading @@ -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) { Loading @@ -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) { Loading @@ -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 services/surfaceflinger/Scheduler/Scheduler.h +2 −7 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "EventThread.h" #include "InjectVSyncSource.h" #include "LayerHistory.h" #include "SchedulerUtils.h" namespace android { Loading Loading @@ -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, Loading @@ -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); Loading Loading @@ -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 Loading
services/surfaceflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -143,6 +143,7 @@ filegroup { "Scheduler/LayerHistory.cpp", "Scheduler/MessageQueue.cpp", "Scheduler/Scheduler.cpp", "Scheduler/SchedulerUtils.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", "SurfaceInterceptor.cpp", Loading
services/surfaceflinger/Scheduler/LayerHistory.cpp +5 −2 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ #include <utils/Timers.h> #include <utils/Trace.h> #include "SchedulerUtils.h" namespace android { LayerHistory::LayerHistory() {} Loading @@ -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(); Loading @@ -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
services/surfaceflinger/Scheduler/LayerHistory.h +4 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ #include <utils/Timers.h> #include "SchedulerUtils.h" namespace android { /* Loading Loading @@ -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
services/surfaceflinger/Scheduler/Scheduler.cpp +24 −36 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "Scheduler.h" #include <algorithm> #include <cinttypes> #include <cstdint> #include <memory> Loading @@ -38,6 +39,7 @@ #include "EventControlThread.h" #include "EventThread.h" #include "InjectVSyncSource.h" #include "SchedulerUtils.h" namespace android { Loading Loading @@ -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) { Loading @@ -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) { Loading @@ -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) { Loading @@ -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
services/surfaceflinger/Scheduler/Scheduler.h +2 −7 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include "EventThread.h" #include "InjectVSyncSource.h" #include "LayerHistory.h" #include "SchedulerUtils.h" namespace android { Loading Loading @@ -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, Loading @@ -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); Loading Loading @@ -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