Loading services/surfaceflinger/BufferQueueLayer.cpp +4 −3 Original line number Diff line number Diff line Loading @@ -352,9 +352,10 @@ void BufferQueueLayer::setHwcLayerBuffer(DisplayId displayId) { void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope // Report the timestamp to the Scheduler. // Report the requested present time to the Scheduler. if (mFlinger->mUseScheduler) { mFlinger->mScheduler->addNewFrameTimestamp(item.mTimestamp, item.mIsAutoTimestamp); mFlinger->mScheduler->addFramePresentTimeForLayer(item.mTimestamp, item.mIsAutoTimestamp, mName.c_str()); } Mutex::Autolock lock(mQueueItemLock); Loading services/surfaceflinger/Scheduler/LayerHistory.cpp +5 −1 Original line number Diff line number Diff line Loading @@ -39,11 +39,15 @@ void LayerHistory::insert(const std::string layerName, nsecs_t presentTime) { void LayerHistory::incrementCounter() { mCounter++; mCounter = mCounter % ARRAY_SIZE; // Clear all the previous data from the history. This is a ring buffer, so we are // reusing memory. mElements[mCounter].clear(); } const std::unordered_map<std::string, nsecs_t>& LayerHistory::get(size_t index) const { return mElements.at(index); // 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); } } // namespace android No newline at end of file services/surfaceflinger/Scheduler/LayerHistory.h +6 −3 Original line number Diff line number Diff line Loading @@ -42,14 +42,17 @@ public: ~LayerHistory(); // Method for inserting layers and their requested present time into the ring buffer. // The elements are going to be inserted into an unordered_map at the position of // mCounter. // The elements are going to be inserted into an unordered_map at the position 'now'. void insert(const std::string layerName, nsecs_t presentTime); // Method for incrementing the current slot in the ring buffer. It also clears the // unordered_map, if it was created previously. void incrementCounter(); // Returns unordered_map at the given at index. // Returns unordered_map at the given at index. The index is decremented from 'now'. For // example, 0 is now, 1 is previous frame. 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; } private: size_t mCounter = 0; Loading services/surfaceflinger/Scheduler/Scheduler.cpp +84 −17 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ #include <gui/ISurfaceComposer.h> #include <ui/DisplayStatInfo.h> #include <utils/Timers.h> #include <utils/Trace.h> #include "DispSync.h" Loading Loading @@ -205,15 +206,95 @@ void Scheduler::makeHWSyncAvailable(bool makeAvailable) { mHWVsyncAvailable = makeAvailable; } void Scheduler::addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp) { void Scheduler::addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp, const std::string layerName) { // This is V1 logic. It calculates the average FPS based on the timestamp frequency // regardless of which layer the timestamp came from. // For now, the averages and FPS are recorded in the systrace. determineTimestampAverage(isAutoTimestamp, framePresentTime); // This is V2 logic. It calculates the average and median timestamp difference based on the // individual layer history. The results are recorded in the systrace. determineLayerTimestampStats(layerName, framePresentTime); } 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) { // Only update DispSync if it hasn't been updated yet. mPrimaryDispSync->setRefreshSkipCount(skipCount); mSkipCount = skipCount; } } void Scheduler::determineLayerTimestampStats(const std::string layerName, const nsecs_t framePresentTime) { mLayerHistory.insert(layerName, framePresentTime); std::vector<int64_t> differencesMs; // Traverse through the layer history, and determine the differences in present times. nsecs_t newestPresentTime = framePresentTime; for (int i = 1; i < mLayerHistory.getSize(); i++) { std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i); for (auto layer : layers) { if (layer.first != 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); } 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); // 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) { const auto tagMedian = "TimestampMedian_" + layerName; ATRACE_INT(tagMedian.c_str(), calculateMedian(&differencesMs)); } } int64_t Scheduler::calculateMedian(std::vector<int64_t>* v) { if (!v || v->size() == 0) { return 0; } 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) { ATRACE_INT("AutoTimestamp", isAutoTimestamp); // Video does not have timestamp automatically set, so we discard timestamps that are // coming in from other sources for now. if (isAutoTimestamp) { return; } int64_t differenceMs = (newFrameTimestamp - mPreviousFrameTimestamp) / 1000000; mPreviousFrameTimestamp = newFrameTimestamp; int64_t differenceMs = (framePresentTime - mPreviousFrameTimestamp) / 1000000; mPreviousFrameTimestamp = framePresentTime; if (differenceMs < 10 || differenceMs > 100) { // Dismiss noise. Loading @@ -240,18 +321,4 @@ void Scheduler::addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAut updateFrameSkipping(0); } 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) { // Only update DispSync if it hasn't been updated yet. mPrimaryDispSync->setRefreshSkipCount(skipCount); mSkipCount = skipCount; } } } // namespace android services/surfaceflinger/Scheduler/Scheduler.h +19 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include "EventControlThread.h" #include "EventThread.h" #include "InjectVSyncSource.h" #include "LayerHistory.h" namespace android { Loading Loading @@ -103,9 +104,15 @@ public: void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime); void setIgnorePresentFences(bool ignore); void makeHWSyncAvailable(bool makeAvailable); void addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp); // Adds the present time for given layer to the history of present times. void addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp, const std::string layerName); // Increments counter in the layer history to indicate that SF has started a new frame. 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 @@ -114,6 +121,15 @@ protected: private: nsecs_t calculateAverage() const; void updateFrameSkipping(const int64_t skipCount); // 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); // TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it // should make request to Scheduler to compute next refresh. Loading Loading @@ -150,6 +166,8 @@ private: static constexpr size_t ARRAY_SIZE = 30; std::array<int64_t, ARRAY_SIZE> mTimeDifferences; size_t mCounter = 0; LayerHistory mLayerHistory; }; } // namespace android Loading
services/surfaceflinger/BufferQueueLayer.cpp +4 −3 Original line number Diff line number Diff line Loading @@ -352,9 +352,10 @@ void BufferQueueLayer::setHwcLayerBuffer(DisplayId displayId) { void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope // Report the timestamp to the Scheduler. // Report the requested present time to the Scheduler. if (mFlinger->mUseScheduler) { mFlinger->mScheduler->addNewFrameTimestamp(item.mTimestamp, item.mIsAutoTimestamp); mFlinger->mScheduler->addFramePresentTimeForLayer(item.mTimestamp, item.mIsAutoTimestamp, mName.c_str()); } Mutex::Autolock lock(mQueueItemLock); Loading
services/surfaceflinger/Scheduler/LayerHistory.cpp +5 −1 Original line number Diff line number Diff line Loading @@ -39,11 +39,15 @@ void LayerHistory::insert(const std::string layerName, nsecs_t presentTime) { void LayerHistory::incrementCounter() { mCounter++; mCounter = mCounter % ARRAY_SIZE; // Clear all the previous data from the history. This is a ring buffer, so we are // reusing memory. mElements[mCounter].clear(); } const std::unordered_map<std::string, nsecs_t>& LayerHistory::get(size_t index) const { return mElements.at(index); // 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); } } // namespace android No newline at end of file
services/surfaceflinger/Scheduler/LayerHistory.h +6 −3 Original line number Diff line number Diff line Loading @@ -42,14 +42,17 @@ public: ~LayerHistory(); // Method for inserting layers and their requested present time into the ring buffer. // The elements are going to be inserted into an unordered_map at the position of // mCounter. // The elements are going to be inserted into an unordered_map at the position 'now'. void insert(const std::string layerName, nsecs_t presentTime); // Method for incrementing the current slot in the ring buffer. It also clears the // unordered_map, if it was created previously. void incrementCounter(); // Returns unordered_map at the given at index. // Returns unordered_map at the given at index. The index is decremented from 'now'. For // example, 0 is now, 1 is previous frame. 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; } private: size_t mCounter = 0; Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +84 −17 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ #include <gui/ISurfaceComposer.h> #include <ui/DisplayStatInfo.h> #include <utils/Timers.h> #include <utils/Trace.h> #include "DispSync.h" Loading Loading @@ -205,15 +206,95 @@ void Scheduler::makeHWSyncAvailable(bool makeAvailable) { mHWVsyncAvailable = makeAvailable; } void Scheduler::addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp) { void Scheduler::addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp, const std::string layerName) { // This is V1 logic. It calculates the average FPS based on the timestamp frequency // regardless of which layer the timestamp came from. // For now, the averages and FPS are recorded in the systrace. determineTimestampAverage(isAutoTimestamp, framePresentTime); // This is V2 logic. It calculates the average and median timestamp difference based on the // individual layer history. The results are recorded in the systrace. determineLayerTimestampStats(layerName, framePresentTime); } 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) { // Only update DispSync if it hasn't been updated yet. mPrimaryDispSync->setRefreshSkipCount(skipCount); mSkipCount = skipCount; } } void Scheduler::determineLayerTimestampStats(const std::string layerName, const nsecs_t framePresentTime) { mLayerHistory.insert(layerName, framePresentTime); std::vector<int64_t> differencesMs; // Traverse through the layer history, and determine the differences in present times. nsecs_t newestPresentTime = framePresentTime; for (int i = 1; i < mLayerHistory.getSize(); i++) { std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i); for (auto layer : layers) { if (layer.first != 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); } 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); // 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) { const auto tagMedian = "TimestampMedian_" + layerName; ATRACE_INT(tagMedian.c_str(), calculateMedian(&differencesMs)); } } int64_t Scheduler::calculateMedian(std::vector<int64_t>* v) { if (!v || v->size() == 0) { return 0; } 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) { ATRACE_INT("AutoTimestamp", isAutoTimestamp); // Video does not have timestamp automatically set, so we discard timestamps that are // coming in from other sources for now. if (isAutoTimestamp) { return; } int64_t differenceMs = (newFrameTimestamp - mPreviousFrameTimestamp) / 1000000; mPreviousFrameTimestamp = newFrameTimestamp; int64_t differenceMs = (framePresentTime - mPreviousFrameTimestamp) / 1000000; mPreviousFrameTimestamp = framePresentTime; if (differenceMs < 10 || differenceMs > 100) { // Dismiss noise. Loading @@ -240,18 +321,4 @@ void Scheduler::addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAut updateFrameSkipping(0); } 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) { // Only update DispSync if it hasn't been updated yet. mPrimaryDispSync->setRefreshSkipCount(skipCount); mSkipCount = skipCount; } } } // namespace android
services/surfaceflinger/Scheduler/Scheduler.h +19 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include "EventControlThread.h" #include "EventThread.h" #include "InjectVSyncSource.h" #include "LayerHistory.h" namespace android { Loading Loading @@ -103,9 +104,15 @@ public: void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime); void setIgnorePresentFences(bool ignore); void makeHWSyncAvailable(bool makeAvailable); void addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp); // Adds the present time for given layer to the history of present times. void addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp, const std::string layerName); // Increments counter in the layer history to indicate that SF has started a new frame. 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 @@ -114,6 +121,15 @@ protected: private: nsecs_t calculateAverage() const; void updateFrameSkipping(const int64_t skipCount); // 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); // TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it // should make request to Scheduler to compute next refresh. Loading Loading @@ -150,6 +166,8 @@ private: static constexpr size_t ARRAY_SIZE = 30; std::array<int64_t, ARRAY_SIZE> mTimeDifferences; size_t mCounter = 0; LayerHistory mLayerHistory; }; } // namespace android