Loading services/surfaceflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,7 @@ filegroup { "Scheduler/DispSyncSource.cpp", "Scheduler/EventControlThread.cpp", "Scheduler/EventThread.cpp", "Scheduler/LayerHistory.cpp", "Scheduler/MessageQueue.cpp", "Scheduler/Scheduler.cpp", "StartPropertySetThread.cpp", Loading services/surfaceflinger/Scheduler/LayerHistory.cpp 0 → 100644 +49 −0 Original line number Diff line number Diff line /* * Copyright 2018 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. */ #include "LayerHistory.h" #include <cinttypes> #include <cstdint> #include <numeric> #include <string> #include <unordered_map> #include <utils/Log.h> #include <utils/Timers.h> #include <utils/Trace.h> namespace android { LayerHistory::LayerHistory() {} LayerHistory::~LayerHistory() = default; void LayerHistory::insert(const std::string layerName, nsecs_t presentTime) { mElements[mCounter].insert(std::make_pair(layerName, presentTime)); } void LayerHistory::incrementCounter() { mCounter++; mCounter = mCounter % ARRAY_SIZE; mElements[mCounter].clear(); } const std::unordered_map<std::string, nsecs_t>& LayerHistory::get(size_t index) const { return mElements.at(index); } } // namespace android No newline at end of file services/surfaceflinger/Scheduler/LayerHistory.h 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * Copyright 2018 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 <array> #include <cinttypes> #include <cstdint> #include <numeric> #include <string> #include <unordered_map> #include <utils/Timers.h> namespace android { /* * This class represents a circular buffer in which we keep layer history for * the past ARRAY_SIZE frames. Each time, a signal for new frame comes, the counter * gets incremented and includes all the layers that are requested to draw in that * frame. * * Once the buffer reaches the end of the array, it starts overriding the elements * at the beginning of the array. */ class LayerHistory { public: LayerHistory(); ~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. 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. const std::unordered_map<std::string, nsecs_t>& get(size_t index) const; private: size_t mCounter = 0; static constexpr size_t ARRAY_SIZE = 30; std::array<std::unordered_map<std::string, nsecs_t>, ARRAY_SIZE> mElements; }; } // namespace android No newline at end of file services/surfaceflinger/tests/unittests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ cc_test { "DisplayTransactionTest.cpp", "EventControlThreadTest.cpp", "EventThreadTest.cpp", "LayerHistoryTest.cpp", "SchedulerTest.cpp", "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockDisplaySurface.cpp", Loading services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp 0 → 100644 +144 −0 Original line number Diff line number Diff line #undef LOG_TAG #define LOG_TAG "LayerHistoryUnittests" #include <gmock/gmock.h> #include <gtest/gtest.h> #include <log/log.h> #include <mutex> #include "Scheduler/LayerHistory.h" using testing::_; using testing::Return; namespace android { class LayerHistoryTest : public testing::Test { public: LayerHistoryTest(); ~LayerHistoryTest() override; protected: std::unique_ptr<LayerHistory> mLayerHistory; }; LayerHistoryTest::LayerHistoryTest() { mLayerHistory = std::make_unique<LayerHistory>(); } LayerHistoryTest::~LayerHistoryTest() {} namespace { TEST_F(LayerHistoryTest, simpleInsertAndGet) { mLayerHistory->insert("TestLayer", 0); const std::unordered_map<std::string, nsecs_t>& testMap = mLayerHistory->get(0); EXPECT_EQ(1, testMap.size()); auto element = testMap.find("TestLayer"); EXPECT_EQ("TestLayer", element->first); EXPECT_EQ(0, element->second); // Testing accessing object at an empty container will return an empty map. const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(1); EXPECT_EQ(0, emptyMap.size()); } TEST_F(LayerHistoryTest, multipleInserts) { mLayerHistory->insert("TestLayer0", 0); mLayerHistory->insert("TestLayer1", 1); mLayerHistory->insert("TestLayer2", 2); mLayerHistory->insert("TestLayer3", 3); const std::unordered_map<std::string, nsecs_t>& testMap = mLayerHistory->get(0); // Because the counter was not incremented, all elements were inserted into the first // container. EXPECT_EQ(4, testMap.size()); auto element = testMap.find("TestLayer0"); EXPECT_EQ("TestLayer0", element->first); EXPECT_EQ(0, element->second); element = testMap.find("TestLayer1"); EXPECT_EQ("TestLayer1", element->first); EXPECT_EQ(1, element->second); element = testMap.find("TestLayer2"); EXPECT_EQ("TestLayer2", element->first); EXPECT_EQ(2, element->second); element = testMap.find("TestLayer3"); EXPECT_EQ("TestLayer3", element->first); EXPECT_EQ(3, element->second); // Testing accessing object at an empty container will return an empty map. const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(1); EXPECT_EQ(0, emptyMap.size()); } TEST_F(LayerHistoryTest, incrementingCounter) { mLayerHistory->insert("TestLayer0", 0); mLayerHistory->incrementCounter(); mLayerHistory->insert("TestLayer1", 1); mLayerHistory->insert("TestLayer2", 2); mLayerHistory->incrementCounter(); mLayerHistory->insert("TestLayer3", 3); // Because the counter was incremented, the elements were inserted into different // containers. const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0); EXPECT_EQ(1, testMap1.size()); auto element = testMap1.find("TestLayer0"); EXPECT_EQ("TestLayer0", element->first); EXPECT_EQ(0, element->second); const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(1); EXPECT_EQ(2, testMap2.size()); element = testMap2.find("TestLayer1"); EXPECT_EQ("TestLayer1", element->first); EXPECT_EQ(1, element->second); element = testMap2.find("TestLayer2"); EXPECT_EQ("TestLayer2", element->first); EXPECT_EQ(2, element->second); const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(2); EXPECT_EQ(1, testMap3.size()); element = testMap3.find("TestLayer3"); EXPECT_EQ("TestLayer3", element->first); EXPECT_EQ(3, element->second); // Testing accessing object at an empty container will return an empty map. const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(3); EXPECT_EQ(0, emptyMap.size()); } TEST_F(LayerHistoryTest, clearTheMap) { mLayerHistory->insert("TestLayer0", 0); mLayerHistory->incrementCounter(); const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0); EXPECT_EQ(1, testMap1.size()); auto element = testMap1.find("TestLayer0"); EXPECT_EQ("TestLayer0", element->first); EXPECT_EQ(0, element->second); // The array currently contains 30 elements. for (int i = 1; i < 30; ++i) { mLayerHistory->insert("TestLayer0", i); mLayerHistory->incrementCounter(); } // Expect the map to be cleared. const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(0); EXPECT_EQ(0, testMap2.size()); mLayerHistory->insert("TestLayer30", 30); const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(0); element = testMap3.find("TestLayer30"); EXPECT_EQ("TestLayer30", element->first); EXPECT_EQ(30, element->second); // The original element in this location does not exist anymore. element = testMap3.find("TestLayer0"); EXPECT_EQ(testMap3.end(), element); } } // namespace } // namespace android No newline at end of file Loading
services/surfaceflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,7 @@ filegroup { "Scheduler/DispSyncSource.cpp", "Scheduler/EventControlThread.cpp", "Scheduler/EventThread.cpp", "Scheduler/LayerHistory.cpp", "Scheduler/MessageQueue.cpp", "Scheduler/Scheduler.cpp", "StartPropertySetThread.cpp", Loading
services/surfaceflinger/Scheduler/LayerHistory.cpp 0 → 100644 +49 −0 Original line number Diff line number Diff line /* * Copyright 2018 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. */ #include "LayerHistory.h" #include <cinttypes> #include <cstdint> #include <numeric> #include <string> #include <unordered_map> #include <utils/Log.h> #include <utils/Timers.h> #include <utils/Trace.h> namespace android { LayerHistory::LayerHistory() {} LayerHistory::~LayerHistory() = default; void LayerHistory::insert(const std::string layerName, nsecs_t presentTime) { mElements[mCounter].insert(std::make_pair(layerName, presentTime)); } void LayerHistory::incrementCounter() { mCounter++; mCounter = mCounter % ARRAY_SIZE; mElements[mCounter].clear(); } const std::unordered_map<std::string, nsecs_t>& LayerHistory::get(size_t index) const { return mElements.at(index); } } // namespace android No newline at end of file
services/surfaceflinger/Scheduler/LayerHistory.h 0 → 100644 +60 −0 Original line number Diff line number Diff line /* * Copyright 2018 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 <array> #include <cinttypes> #include <cstdint> #include <numeric> #include <string> #include <unordered_map> #include <utils/Timers.h> namespace android { /* * This class represents a circular buffer in which we keep layer history for * the past ARRAY_SIZE frames. Each time, a signal for new frame comes, the counter * gets incremented and includes all the layers that are requested to draw in that * frame. * * Once the buffer reaches the end of the array, it starts overriding the elements * at the beginning of the array. */ class LayerHistory { public: LayerHistory(); ~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. 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. const std::unordered_map<std::string, nsecs_t>& get(size_t index) const; private: size_t mCounter = 0; static constexpr size_t ARRAY_SIZE = 30; std::array<std::unordered_map<std::string, nsecs_t>, ARRAY_SIZE> mElements; }; } // namespace android No newline at end of file
services/surfaceflinger/tests/unittests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ cc_test { "DisplayTransactionTest.cpp", "EventControlThreadTest.cpp", "EventThreadTest.cpp", "LayerHistoryTest.cpp", "SchedulerTest.cpp", "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockDisplaySurface.cpp", Loading
services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp 0 → 100644 +144 −0 Original line number Diff line number Diff line #undef LOG_TAG #define LOG_TAG "LayerHistoryUnittests" #include <gmock/gmock.h> #include <gtest/gtest.h> #include <log/log.h> #include <mutex> #include "Scheduler/LayerHistory.h" using testing::_; using testing::Return; namespace android { class LayerHistoryTest : public testing::Test { public: LayerHistoryTest(); ~LayerHistoryTest() override; protected: std::unique_ptr<LayerHistory> mLayerHistory; }; LayerHistoryTest::LayerHistoryTest() { mLayerHistory = std::make_unique<LayerHistory>(); } LayerHistoryTest::~LayerHistoryTest() {} namespace { TEST_F(LayerHistoryTest, simpleInsertAndGet) { mLayerHistory->insert("TestLayer", 0); const std::unordered_map<std::string, nsecs_t>& testMap = mLayerHistory->get(0); EXPECT_EQ(1, testMap.size()); auto element = testMap.find("TestLayer"); EXPECT_EQ("TestLayer", element->first); EXPECT_EQ(0, element->second); // Testing accessing object at an empty container will return an empty map. const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(1); EXPECT_EQ(0, emptyMap.size()); } TEST_F(LayerHistoryTest, multipleInserts) { mLayerHistory->insert("TestLayer0", 0); mLayerHistory->insert("TestLayer1", 1); mLayerHistory->insert("TestLayer2", 2); mLayerHistory->insert("TestLayer3", 3); const std::unordered_map<std::string, nsecs_t>& testMap = mLayerHistory->get(0); // Because the counter was not incremented, all elements were inserted into the first // container. EXPECT_EQ(4, testMap.size()); auto element = testMap.find("TestLayer0"); EXPECT_EQ("TestLayer0", element->first); EXPECT_EQ(0, element->second); element = testMap.find("TestLayer1"); EXPECT_EQ("TestLayer1", element->first); EXPECT_EQ(1, element->second); element = testMap.find("TestLayer2"); EXPECT_EQ("TestLayer2", element->first); EXPECT_EQ(2, element->second); element = testMap.find("TestLayer3"); EXPECT_EQ("TestLayer3", element->first); EXPECT_EQ(3, element->second); // Testing accessing object at an empty container will return an empty map. const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(1); EXPECT_EQ(0, emptyMap.size()); } TEST_F(LayerHistoryTest, incrementingCounter) { mLayerHistory->insert("TestLayer0", 0); mLayerHistory->incrementCounter(); mLayerHistory->insert("TestLayer1", 1); mLayerHistory->insert("TestLayer2", 2); mLayerHistory->incrementCounter(); mLayerHistory->insert("TestLayer3", 3); // Because the counter was incremented, the elements were inserted into different // containers. const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0); EXPECT_EQ(1, testMap1.size()); auto element = testMap1.find("TestLayer0"); EXPECT_EQ("TestLayer0", element->first); EXPECT_EQ(0, element->second); const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(1); EXPECT_EQ(2, testMap2.size()); element = testMap2.find("TestLayer1"); EXPECT_EQ("TestLayer1", element->first); EXPECT_EQ(1, element->second); element = testMap2.find("TestLayer2"); EXPECT_EQ("TestLayer2", element->first); EXPECT_EQ(2, element->second); const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(2); EXPECT_EQ(1, testMap3.size()); element = testMap3.find("TestLayer3"); EXPECT_EQ("TestLayer3", element->first); EXPECT_EQ(3, element->second); // Testing accessing object at an empty container will return an empty map. const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(3); EXPECT_EQ(0, emptyMap.size()); } TEST_F(LayerHistoryTest, clearTheMap) { mLayerHistory->insert("TestLayer0", 0); mLayerHistory->incrementCounter(); const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0); EXPECT_EQ(1, testMap1.size()); auto element = testMap1.find("TestLayer0"); EXPECT_EQ("TestLayer0", element->first); EXPECT_EQ(0, element->second); // The array currently contains 30 elements. for (int i = 1; i < 30; ++i) { mLayerHistory->insert("TestLayer0", i); mLayerHistory->incrementCounter(); } // Expect the map to be cleared. const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(0); EXPECT_EQ(0, testMap2.size()); mLayerHistory->insert("TestLayer30", 30); const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(0); element = testMap3.find("TestLayer30"); EXPECT_EQ("TestLayer30", element->first); EXPECT_EQ(30, element->second); // The original element in this location does not exist anymore. element = testMap3.find("TestLayer0"); EXPECT_EQ(testMap3.end(), element); } } // namespace } // namespace android No newline at end of file