Add SystemBenchmarks.
This benchmarks `sw::LRUCache`, which currently resides in the `src/Device` folder (but will be moved to `src/System`) with 43489.
Bug: b/153338950
Change-Id: I169b6ecb4a35349726a01b1da52472eaef3dfd74
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/43492
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 53f7921..dba0006 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1209,18 +1209,44 @@
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/third_party/benchmark)
endif()
+ # Reactor benchmarks
set(REACTOR_BENCHMARK_LIST
${SOURCE_DIR}/Reactor/ReactorBenchmarks.cpp
)
add_executable(ReactorBenchmarks ${REACTOR_BENCHMARK_LIST})
target_link_libraries(ReactorBenchmarks benchmark::benchmark marl ${Reactor})
-
set_target_properties(ReactorBenchmarks PROPERTIES
COMPILE_OPTIONS "${SWIFTSHADER_COMPILE_OPTIONS};${WARNINGS_AS_ERRORS}"
LINK_FLAGS "${SWIFTSHADER_LINK_FLAGS}"
FOLDER "Benchmarks"
)
+
+ # System benchmarks
+ set(SYSTEM_BENCHMARKS_LIST
+ ${SOURCE_DIR}/System/Debug.cpp
+
+ ${TESTS_DIR}/SystemBenchmarks/main.cpp
+ ${TESTS_DIR}/SystemBenchmarks/LRUCacheBenchmarks.cpp
+ )
+
+ set(SYSTEM_BENCHMARKS_INCLUDE_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/
+ )
+
+ add_executable(system-benchmarks ${SYSTEM_BENCHMARKS_LIST})
+ target_link_libraries(system-benchmarks benchmark::benchmark)
+ set_target_properties(system-benchmarks PROPERTIES
+ INCLUDE_DIRECTORIES "${SYSTEM_BENCHMARKS_INCLUDE_DIR}"
+ COMPILE_OPTIONS "${SWIFTSHADER_COMPILE_OPTIONS};${WARNINGS_AS_ERRORS}"
+ LINK_FLAGS "${SWIFTSHADER_LINK_FLAGS}"
+ FOLDER "Benchmarks"
+ )
+
+ target_link_libraries(system-benchmarks gtest gmock)
+ if(NOT WIN32)
+ target_link_libraries(system-benchmarks pthread ${SWIFTSHADER_LIBS})
+ endif()
endif(SWIFTSHADER_BUILD_BENCHMARKS)
if(SWIFTSHADER_BUILD_TESTS AND SWIFTSHADER_BUILD_VULKAN)
diff --git a/tests/SystemBenchmarks/LRUCacheBenchmarks.cpp b/tests/SystemBenchmarks/LRUCacheBenchmarks.cpp
new file mode 100644
index 0000000..66638d5
--- /dev/null
+++ b/tests/SystemBenchmarks/LRUCacheBenchmarks.cpp
@@ -0,0 +1,210 @@
+// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
+//
+// 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 "Device/LRUCache.hpp"
+
+#include "benchmark/benchmark.h"
+
+#include <array>
+
+namespace {
+
+// https://en.wikipedia.org/wiki/Xorshift
+class FastRnd
+{
+public:
+ inline size_t operator()()
+ {
+ x ^= x << 13;
+ x ^= x >> 7;
+ x ^= x << 17;
+ return x;
+ }
+
+private:
+ size_t x = 3243298;
+};
+
+struct ComplexKey
+{
+ std::array<size_t, 8> words;
+};
+
+bool operator==(const ComplexKey &a, const ComplexKey &b)
+{
+ for(size_t w = 0; w < a.words.size(); w++)
+ {
+ if(a.words[w] != b.words[w]) { return false; }
+ }
+ return true;
+}
+
+struct ComplexKeyHash
+{
+ size_t operator()(const ComplexKey &key) const
+ {
+ size_t hash = 12227;
+ for(size_t w = 0; w < key.words.size(); w++)
+ {
+ hash = hash * 11801 + key.words[w];
+ }
+ return hash;
+ }
+};
+
+} // namespace
+
+class LRUCacheBenchmark : public benchmark::Fixture
+{
+public:
+ void SetUp(const ::benchmark::State &state)
+ {
+ size = state.range(0);
+ }
+
+ void TearDown(const ::benchmark::State &state) {}
+
+ size_t size;
+};
+
+BENCHMARK_DEFINE_F(LRUCacheBenchmark, AddInt)
+(benchmark::State &state)
+{
+ sw::LRUCache<size_t, size_t> cache(size);
+ FastRnd rnd;
+
+ int i = 0;
+ for(auto _ : state)
+ {
+ cache.add(rnd() % size, i);
+ i++;
+ }
+}
+BENCHMARK_REGISTER_F(LRUCacheBenchmark, AddInt)->RangeMultiplier(8)->Range(1, 0x100000)->ArgName("cache-size");
+
+BENCHMARK_DEFINE_F(LRUCacheBenchmark, GetIntCacheHit)
+(benchmark::State &state)
+{
+ sw::LRUCache<size_t, size_t> cache(size);
+ FastRnd rnd;
+
+ for(size_t i = 0; i < size; i++)
+ {
+ cache.add(i, i);
+ }
+
+ for(auto _ : state)
+ {
+ cache.query(rnd() % size);
+ }
+}
+BENCHMARK_REGISTER_F(LRUCacheBenchmark, GetIntCacheHit)->RangeMultiplier(8)->Range(1, 0x100000)->ArgName("cache-size");
+
+BENCHMARK_DEFINE_F(LRUCacheBenchmark, GetIntCacheMiss)
+(benchmark::State &state)
+{
+ sw::LRUCache<size_t, size_t> cache(size);
+ FastRnd rnd;
+ for(size_t i = 0; i < size; i++)
+ {
+ cache.add(size + i, i);
+ }
+
+ for(auto _ : state)
+ {
+ cache.query(rnd() % size);
+ }
+}
+BENCHMARK_REGISTER_F(LRUCacheBenchmark, GetIntCacheMiss)->RangeMultiplier(8)->Range(1, 0x100000)->ArgName("cache-size");
+
+BENCHMARK_DEFINE_F(LRUCacheBenchmark, AddRandomComplexKey)
+(benchmark::State &state)
+{
+ sw::LRUCache<ComplexKey, size_t> cache(size);
+ FastRnd rnd;
+
+ int i = 0;
+ for(auto _ : state)
+ {
+ ComplexKey key;
+ for(size_t w = 0; w < key.words.size(); w++)
+ {
+ key.words[w] = rnd() & 1;
+ }
+
+ cache.add(key, i);
+ i++;
+ }
+}
+BENCHMARK_REGISTER_F(LRUCacheBenchmark, AddRandomComplexKey)->RangeMultiplier(8)->Range(1, 0x100000)->ArgName("cache-size");
+
+BENCHMARK_DEFINE_F(LRUCacheBenchmark, GetComplexKeyCacheHit)
+(benchmark::State &state)
+{
+ sw::LRUCache<ComplexKey, size_t> cache(size);
+ FastRnd rnd;
+
+ for(size_t i = 0; i < size; i++)
+ {
+ ComplexKey key;
+ for(size_t w = 0; w < key.words.size(); w++)
+ {
+ key.words[w] = (1U << w);
+ }
+ cache.add(key, i);
+ }
+
+ for(auto _ : state)
+ {
+ auto i = rnd() & size;
+
+ ComplexKey key;
+ for(size_t w = 0; w < key.words.size(); w++)
+ {
+ key.words[w] = i & (1U << w);
+ }
+ cache.query(key);
+ }
+}
+BENCHMARK_REGISTER_F(LRUCacheBenchmark, GetComplexKeyCacheHit)->RangeMultiplier(8)->Range(1, 0x100000)->ArgName("cache-size");
+
+BENCHMARK_DEFINE_F(LRUCacheBenchmark, GetComplexKeyCacheMiss)
+(benchmark::State &state)
+{
+ sw::LRUCache<ComplexKey, size_t> cache(size);
+ FastRnd rnd;
+
+ for(size_t i = 0; i < size; i++)
+ {
+ ComplexKey key;
+ for(size_t w = 0; w < key.words.size(); w++)
+ {
+ key.words[w] = 8 + (1U << w);
+ }
+ cache.add(key, i);
+ }
+
+ for(auto _ : state)
+ {
+ auto i = rnd() & size;
+
+ ComplexKey key;
+ for(size_t w = 0; w < key.words.size(); w++)
+ {
+ key.words[w] = i & (1U << w);
+ }
+ cache.query(key);
+ }
+}
+BENCHMARK_REGISTER_F(LRUCacheBenchmark, GetComplexKeyCacheMiss)->RangeMultiplier(8)->Range(1, 0x100000)->ArgName("cache-size");
diff --git a/tests/SystemBenchmarks/main.cpp b/tests/SystemBenchmarks/main.cpp
new file mode 100644
index 0000000..9f307ab
--- /dev/null
+++ b/tests/SystemBenchmarks/main.cpp
@@ -0,0 +1,17 @@
+// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
+//
+// 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 "benchmark/benchmark.h"
+
+BENCHMARK_MAIN();
diff --git a/tests/SystemUnitTests/LRUCacheTests.cpp b/tests/SystemUnitTests/LRUCacheTests.cpp
new file mode 100644
index 0000000..c1dead5
--- /dev/null
+++ b/tests/SystemUnitTests/LRUCacheTests.cpp
@@ -0,0 +1,124 @@
+// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
+//
+// 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 "System/LRUCache.hpp"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <vector>
+
+using namespace sw;
+
+namespace {
+
+template<typename Cache>
+void checkRange(const Cache &cache, std::vector<std::pair<typename Cache::Key, typename Cache::Data>> list)
+{
+ size_t i = 0;
+ for(auto it : cache)
+ {
+ ASSERT_EQ(list[i].first, it.key());
+ ASSERT_EQ(list[i].second, it.data());
+ i++;
+ }
+ ASSERT_EQ(i, list.size());
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// LRUCache
+////////////////////////////////////////////////////////////////////////////////
+TEST(LRUCache, Empty)
+{
+ LRUCache<std::string, std::string> cache(8);
+ ASSERT_EQ(cache.get(""), "");
+ ASSERT_EQ(cache.get("123"), "");
+ for(auto ignored : cache)
+ {
+ (void)ignored;
+ FAIL() << "Should not loop on empty cache";
+ }
+}
+
+TEST(LRUCache, AddNoEviction)
+{
+ LRUCache<std::string, std::string> cache(4);
+
+ cache.add("1", "one");
+ cache.add("2", "two");
+ cache.add("3", "three");
+ cache.add("4", "four");
+
+ ASSERT_EQ(cache.get("1"), "one");
+ ASSERT_EQ(cache.get("2"), "two");
+ ASSERT_EQ(cache.get("3"), "three");
+ ASSERT_EQ(cache.get("4"), "four");
+
+ checkRange(cache, {
+ { "4", "four" },
+ { "3", "three" },
+ { "2", "two" },
+ { "1", "one" },
+ });
+}
+
+TEST(LRUCache, AddWithEviction)
+{
+ LRUCache<std::string, std::string> cache(4);
+
+ cache.add("1", "one");
+ cache.add("2", "two");
+ cache.add("3", "three");
+ cache.add("4", "four");
+ cache.add("5", "five");
+ cache.add("6", "six");
+
+ ASSERT_EQ(cache.get("1"), "");
+ ASSERT_EQ(cache.get("2"), "");
+ ASSERT_EQ(cache.get("3"), "three");
+ ASSERT_EQ(cache.get("4"), "four");
+ ASSERT_EQ(cache.get("5"), "five");
+ ASSERT_EQ(cache.get("6"), "six");
+
+ checkRange(cache, {
+ { "6", "six" },
+ { "5", "five" },
+ { "4", "four" },
+ { "3", "three" },
+ });
+}
+
+TEST(LRUCache, Reordering)
+{
+ LRUCache<std::string, std::string> cache(4);
+
+ // Fill
+ cache.add("1", "one");
+ cache.add("2", "two");
+ cache.add("3", "three");
+ cache.add("4", "four");
+
+ // Push 2 then 4 to most recent
+ cache.add("2", "two");
+ cache.add("4", "four");
+
+ checkRange(cache, {
+ { "4", "four" },
+ { "2", "two" },
+ { "3", "three" },
+ { "1", "one" },
+ });
+}
\ No newline at end of file