|  | /* | 
|  | * Copyright 2020 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. | 
|  | */ | 
|  |  | 
|  | #undef LOG_TAG | 
|  | #define LOG_TAG "LayerInfoTest" | 
|  |  | 
|  | #include <gtest/gtest.h> | 
|  |  | 
|  | #include "Fps.h" | 
|  | #include "Scheduler/LayerHistory.h" | 
|  | #include "Scheduler/LayerInfo.h" | 
|  |  | 
|  | namespace android::scheduler { | 
|  |  | 
|  | class LayerInfoTest : public testing::Test { | 
|  | protected: | 
|  | using FrameTimeData = LayerInfo::FrameTimeData; | 
|  |  | 
|  | void setFrameTimes(const std::deque<FrameTimeData>& frameTimes) { | 
|  | layerInfo.mFrameTimes = frameTimes; | 
|  | } | 
|  |  | 
|  | void setLastRefreshRate(Fps fps) { | 
|  | layerInfo.mLastRefreshRate.reported = fps; | 
|  | layerInfo.mLastRefreshRate.calculated = fps; | 
|  | } | 
|  |  | 
|  | auto calculateAverageFrameTime() { return layerInfo.calculateAverageFrameTime(); } | 
|  |  | 
|  | LayerInfo layerInfo{"TestLayerInfo", 0, LayerHistory::LayerVoteType::Heuristic}; | 
|  | }; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | TEST_F(LayerInfoTest, prefersPresentTime) { | 
|  | std::deque<FrameTimeData> frameTimes; | 
|  | constexpr auto kExpectedFps = Fps(50.0f); | 
|  | constexpr auto kPeriod = kExpectedFps.getPeriodNsecs(); | 
|  | constexpr int kNumFrames = 10; | 
|  | for (int i = 1; i <= kNumFrames; i++) { | 
|  | frameTimes.push_back(FrameTimeData{.presentTime = kPeriod * i, | 
|  | .queueTime = 0, | 
|  | .pendingModeChange = false}); | 
|  | } | 
|  | setFrameTimes(frameTimes); | 
|  | const auto averageFrameTime = calculateAverageFrameTime(); | 
|  | ASSERT_TRUE(averageFrameTime.has_value()); | 
|  | const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime); | 
|  | ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps)) | 
|  | << "Expected " << averageFps << " to be equal to " << kExpectedFps; | 
|  | } | 
|  |  | 
|  | TEST_F(LayerInfoTest, fallbacksToQueueTimeIfNoPresentTime) { | 
|  | std::deque<FrameTimeData> frameTimes; | 
|  | constexpr auto kExpectedFps = Fps(50.0f); | 
|  | constexpr auto kPeriod = kExpectedFps.getPeriodNsecs(); | 
|  | constexpr int kNumFrames = 10; | 
|  | for (int i = 1; i <= kNumFrames; i++) { | 
|  | frameTimes.push_back(FrameTimeData{.presentTime = 0, | 
|  | .queueTime = kPeriod * i, | 
|  | .pendingModeChange = false}); | 
|  | } | 
|  | setFrameTimes(frameTimes); | 
|  | setLastRefreshRate(Fps(20.0f)); // Set to some valid value | 
|  | const auto averageFrameTime = calculateAverageFrameTime(); | 
|  | ASSERT_TRUE(averageFrameTime.has_value()); | 
|  | const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime); | 
|  | ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps)) | 
|  | << "Expected " << averageFps << " to be equal to " << kExpectedFps; | 
|  | } | 
|  |  | 
|  | TEST_F(LayerInfoTest, returnsNulloptIfThereWasConfigChange) { | 
|  | std::deque<FrameTimeData> frameTimesWithoutConfigChange; | 
|  | const auto period = Fps(50.0f).getPeriodNsecs(); | 
|  | constexpr int kNumFrames = 10; | 
|  | for (int i = 1; i <= kNumFrames; i++) { | 
|  | frameTimesWithoutConfigChange.push_back(FrameTimeData{.presentTime = period * i, | 
|  | .queueTime = period * i, | 
|  | .pendingModeChange = false}); | 
|  | } | 
|  |  | 
|  | setFrameTimes(frameTimesWithoutConfigChange); | 
|  | ASSERT_TRUE(calculateAverageFrameTime().has_value()); | 
|  |  | 
|  | { | 
|  | // Config change in the first record | 
|  | auto frameTimes = frameTimesWithoutConfigChange; | 
|  | frameTimes[0].pendingModeChange = true; | 
|  | setFrameTimes(frameTimes); | 
|  | ASSERT_FALSE(calculateAverageFrameTime().has_value()); | 
|  | } | 
|  |  | 
|  | { | 
|  | // Config change in the last record | 
|  | auto frameTimes = frameTimesWithoutConfigChange; | 
|  | frameTimes[frameTimes.size() - 1].pendingModeChange = true; | 
|  | setFrameTimes(frameTimes); | 
|  | ASSERT_FALSE(calculateAverageFrameTime().has_value()); | 
|  | } | 
|  |  | 
|  | { | 
|  | // Config change in the middle | 
|  | auto frameTimes = frameTimesWithoutConfigChange; | 
|  | frameTimes[frameTimes.size() / 2].pendingModeChange = true; | 
|  | setFrameTimes(frameTimes); | 
|  | ASSERT_FALSE(calculateAverageFrameTime().has_value()); | 
|  | } | 
|  | } | 
|  |  | 
|  | // A frame can be recorded twice with very close presentation or queue times. | 
|  | // Make sure that this doesn't influence the calculated average FPS. | 
|  | TEST_F(LayerInfoTest, ignoresSmallPeriods) { | 
|  | std::deque<FrameTimeData> frameTimes; | 
|  | constexpr auto kExpectedFps = Fps(50.0f); | 
|  | constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs(); | 
|  | constexpr auto kSmallPeriod = Fps(250.0f).getPeriodNsecs(); | 
|  | constexpr int kNumIterations = 10; | 
|  | for (int i = 1; i <= kNumIterations; i++) { | 
|  | frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i, | 
|  | .queueTime = 0, | 
|  | .pendingModeChange = false}); | 
|  |  | 
|  | // A duplicate frame | 
|  | frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i + kSmallPeriod, | 
|  | .queueTime = 0, | 
|  | .pendingModeChange = false}); | 
|  | } | 
|  | setFrameTimes(frameTimes); | 
|  | const auto averageFrameTime = calculateAverageFrameTime(); | 
|  | ASSERT_TRUE(averageFrameTime.has_value()); | 
|  | const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime); | 
|  | ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps)) | 
|  | << "Expected " << averageFps << " to be equal to " << kExpectedFps; | 
|  | } | 
|  |  | 
|  | // There may be a big period of time between two frames. Make sure that | 
|  | // this doesn't influence the calculated average FPS. | 
|  | TEST_F(LayerInfoTest, ignoresLargePeriods) { | 
|  | std::deque<FrameTimeData> frameTimes; | 
|  | constexpr auto kExpectedFps = Fps(50.0f); | 
|  | constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs(); | 
|  | constexpr auto kLargePeriod = Fps(9.0f).getPeriodNsecs(); | 
|  |  | 
|  | auto record = [&](nsecs_t time) { | 
|  | frameTimes.push_back( | 
|  | FrameTimeData{.presentTime = time, .queueTime = 0, .pendingModeChange = false}); | 
|  | }; | 
|  |  | 
|  | auto time = kExpectedPeriod; // Start with non-zero time. | 
|  | record(time); | 
|  | time += kLargePeriod; | 
|  | record(time); | 
|  | constexpr int kNumIterations = 10; | 
|  | for (int i = 1; i <= kNumIterations; i++) { | 
|  | time += kExpectedPeriod; | 
|  | record(time); | 
|  | } | 
|  |  | 
|  | setFrameTimes(frameTimes); | 
|  | const auto averageFrameTime = calculateAverageFrameTime(); | 
|  | ASSERT_TRUE(averageFrameTime.has_value()); | 
|  | const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime); | 
|  | ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps)) | 
|  | << "Expected " << averageFps << " to be equal to " << kExpectedFps; | 
|  | } | 
|  |  | 
|  | } // namespace | 
|  | } // namespace android::scheduler |