Implements a cache key serializer and tests.
- Introduces necessary infra to support cache key serialization templating and extensibility. - Tests cover basic use cases of the infra. Bug: dawn:549 Change-Id: Idc0bbcb07a3037e9c59841bb3ad7d1040d7b401f Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/83121 Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Loko Kung <lokokung@google.com>
This commit is contained in:
parent
ba6d95af9b
commit
2391382b14
|
@ -202,6 +202,8 @@ source_set("sources") {
|
||||||
"BuddyMemoryAllocator.h",
|
"BuddyMemoryAllocator.h",
|
||||||
"Buffer.cpp",
|
"Buffer.cpp",
|
||||||
"Buffer.h",
|
"Buffer.h",
|
||||||
|
"CacheKey.cpp",
|
||||||
|
"CacheKey.h",
|
||||||
"CachedObject.cpp",
|
"CachedObject.cpp",
|
||||||
"CachedObject.h",
|
"CachedObject.h",
|
||||||
"CallbackTaskManager.cpp",
|
"CallbackTaskManager.cpp",
|
||||||
|
|
|
@ -52,6 +52,8 @@ target_sources(dawn_native PRIVATE
|
||||||
"Buffer.h"
|
"Buffer.h"
|
||||||
"CachedObject.cpp"
|
"CachedObject.cpp"
|
||||||
"CachedObject.h"
|
"CachedObject.h"
|
||||||
|
"CacheKey.cpp",
|
||||||
|
"CacheKey.h",
|
||||||
"CallbackTaskManager.cpp"
|
"CallbackTaskManager.cpp"
|
||||||
"CallbackTaskManager.h"
|
"CallbackTaskManager.h"
|
||||||
"CommandAllocator.cpp"
|
"CommandAllocator.cpp"
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright 2022 The Dawn Authors
|
||||||
|
//
|
||||||
|
// 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 "dawn/native/CacheKey.h"
|
||||||
|
|
||||||
|
namespace dawn::native {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<std::string>::Serialize(CacheKey* key, const std::string& t) {
|
||||||
|
std::string len = std::to_string(t.length());
|
||||||
|
key->insert(key->end(), len.begin(), len.end());
|
||||||
|
key->push_back('"');
|
||||||
|
key->insert(key->end(), t.begin(), t.end());
|
||||||
|
key->push_back('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<CacheKey>::Serialize(CacheKey* key, const CacheKey& t) {
|
||||||
|
key->insert(key->end(), t.begin(), t.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dawn::native
|
|
@ -0,0 +1,93 @@
|
||||||
|
// Copyright 2022 The Dawn Authors
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef DAWNNATIVE_CACHE_KEY_H_
|
||||||
|
#define DAWNNATIVE_CACHE_KEY_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "dawn/common/Compiler.h"
|
||||||
|
|
||||||
|
namespace dawn::native {
|
||||||
|
|
||||||
|
using CacheKey = std::vector<uint8_t>;
|
||||||
|
|
||||||
|
// Overridable serializer struct that should be implemented for cache key serializable
|
||||||
|
// types/classes.
|
||||||
|
template <typename T, typename SFINAE = void>
|
||||||
|
struct CacheKeySerializer {
|
||||||
|
static void Serialize(CacheKey* key, const T& t);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialized overload for integral types. Note that we are currently serializing as a string
|
||||||
|
// to avoid handling null termiantors.
|
||||||
|
template <typename Integer>
|
||||||
|
struct CacheKeySerializer<Integer, std::enable_if_t<std::is_integral_v<Integer>>> {
|
||||||
|
static void Serialize(CacheKey* key, const Integer i) {
|
||||||
|
std::string str = std::to_string(i);
|
||||||
|
key->insert(key->end(), str.begin(), str.end());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialized overload for floating point types. Note that we are currently serializing as a
|
||||||
|
// string to avoid handling null termiantors.
|
||||||
|
template <typename Float>
|
||||||
|
struct CacheKeySerializer<Float, std::enable_if_t<std::is_floating_point_v<Float>>> {
|
||||||
|
static void Serialize(CacheKey* key, const Float f) {
|
||||||
|
std::string str = std::to_string(f);
|
||||||
|
key->insert(key->end(), str.begin(), str.end());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialized overload for string literals. Note we drop the null-terminator.
|
||||||
|
template <size_t N>
|
||||||
|
struct CacheKeySerializer<char[N]> {
|
||||||
|
static void Serialize(CacheKey* key, const char (&t)[N]) {
|
||||||
|
std::string len = std::to_string(N - 1);
|
||||||
|
key->insert(key->end(), len.begin(), len.end());
|
||||||
|
key->push_back('"');
|
||||||
|
key->insert(key->end(), t, t + N - 1);
|
||||||
|
key->push_back('"');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper template function that defers to underlying static functions.
|
||||||
|
template <typename T>
|
||||||
|
void SerializeInto(CacheKey* key, const T& t) {
|
||||||
|
CacheKeySerializer<T>::Serialize(key, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given list of arguments of types with a free implementation of SerializeIntoImpl in the
|
||||||
|
// dawn::native namespace, serializes each argument and appends them to the CacheKey while
|
||||||
|
// prepending member ids before each argument.
|
||||||
|
template <typename... Ts>
|
||||||
|
CacheKey GetCacheKey(const Ts&... inputs) {
|
||||||
|
CacheKey key;
|
||||||
|
key.push_back('{');
|
||||||
|
int memberId = 0;
|
||||||
|
auto Serialize = [&](const auto& input) {
|
||||||
|
std::string memberIdStr = (memberId == 0 ? "" : ",") + std::to_string(memberId) + ":";
|
||||||
|
key.insert(key.end(), memberIdStr.begin(), memberIdStr.end());
|
||||||
|
SerializeInto(&key, input);
|
||||||
|
memberId++;
|
||||||
|
};
|
||||||
|
(Serialize(inputs), ...);
|
||||||
|
key.push_back('}');
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dawn::native
|
||||||
|
|
||||||
|
#endif // DAWNNATIVE_CACHE_KEY_H_
|
|
@ -238,6 +238,7 @@ dawn_test("dawn_unittests") {
|
||||||
"unittests/SystemUtilsTests.cpp",
|
"unittests/SystemUtilsTests.cpp",
|
||||||
"unittests/ToBackendTests.cpp",
|
"unittests/ToBackendTests.cpp",
|
||||||
"unittests/TypedIntegerTests.cpp",
|
"unittests/TypedIntegerTests.cpp",
|
||||||
|
"unittests/native/CacheKeyTests.cpp",
|
||||||
"unittests/native/CommandBufferEncodingTests.cpp",
|
"unittests/native/CommandBufferEncodingTests.cpp",
|
||||||
"unittests/native/CreatePipelineAsyncTaskTests.cpp",
|
"unittests/native/CreatePipelineAsyncTaskTests.cpp",
|
||||||
"unittests/native/DestroyObjectTests.cpp",
|
"unittests/native/DestroyObjectTests.cpp",
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
// Copyright 2022 The Dawn Authors
|
||||||
|
//
|
||||||
|
// 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 <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "dawn/native/CacheKey.h"
|
||||||
|
|
||||||
|
namespace dawn::native {
|
||||||
|
|
||||||
|
// Testing classes/structs with serializing implemented for testing.
|
||||||
|
struct A {};
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<A>::Serialize(CacheKey* key, const A& t) {
|
||||||
|
std::string str = "structA";
|
||||||
|
key->insert(key->end(), str.begin(), str.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {};
|
||||||
|
template <>
|
||||||
|
void CacheKeySerializer<B>::Serialize(CacheKey* key, const B& t) {
|
||||||
|
std::string str = "classB";
|
||||||
|
key->insert(key->end(), str.begin(), str.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Matcher to compare CacheKey to a string for easier testing.
|
||||||
|
MATCHER_P(CacheKeyEq,
|
||||||
|
key,
|
||||||
|
"cache key " + std::string(negation ? "not" : "") + "equal to " + key) {
|
||||||
|
return std::string(arg.begin(), arg.end()) == key;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CacheKeyTest, IntegralTypes) {
|
||||||
|
EXPECT_THAT(GetCacheKey((int)-1), CacheKeyEq("{0:-1}"));
|
||||||
|
EXPECT_THAT(GetCacheKey((uint8_t)2), CacheKeyEq("{0:2}"));
|
||||||
|
EXPECT_THAT(GetCacheKey((uint16_t)4), CacheKeyEq("{0:4}"));
|
||||||
|
EXPECT_THAT(GetCacheKey((uint32_t)8), CacheKeyEq("{0:8}"));
|
||||||
|
EXPECT_THAT(GetCacheKey((uint64_t)16), CacheKeyEq("{0:16}"));
|
||||||
|
|
||||||
|
EXPECT_THAT(GetCacheKey((int)-1, (uint8_t)2, (uint16_t)4, (uint32_t)8, (uint64_t)16),
|
||||||
|
CacheKeyEq("{0:-1,1:2,2:4,3:8,4:16}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CacheKeyTest, FloatingTypes) {
|
||||||
|
EXPECT_THAT(GetCacheKey((float)0.5), CacheKeyEq("{0:0.500000}"));
|
||||||
|
EXPECT_THAT(GetCacheKey((double)32.0), CacheKeyEq("{0:32.000000}"));
|
||||||
|
|
||||||
|
EXPECT_THAT(GetCacheKey((float)0.5, (double)32.0),
|
||||||
|
CacheKeyEq("{0:0.500000,1:32.000000}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CacheKeyTest, Strings) {
|
||||||
|
std::string str0 = "string0";
|
||||||
|
std::string str1 = "string1";
|
||||||
|
|
||||||
|
EXPECT_THAT(GetCacheKey("string0"), CacheKeyEq(R"({0:7"string0"})"));
|
||||||
|
EXPECT_THAT(GetCacheKey(str0), CacheKeyEq(R"({0:7"string0"})"));
|
||||||
|
EXPECT_THAT(GetCacheKey("string0", str1), CacheKeyEq(R"({0:7"string0",1:7"string1"})"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CacheKeyTest, NestedCacheKey) {
|
||||||
|
EXPECT_THAT(GetCacheKey(GetCacheKey((int)-1)), CacheKeyEq("{0:{0:-1}}"));
|
||||||
|
EXPECT_THAT(GetCacheKey(GetCacheKey("string")), CacheKeyEq(R"({0:{0:6"string"}})"));
|
||||||
|
EXPECT_THAT(GetCacheKey(GetCacheKey(A{})), CacheKeyEq("{0:{0:structA}}"));
|
||||||
|
EXPECT_THAT(GetCacheKey(GetCacheKey(B())), CacheKeyEq("{0:{0:classB}}"));
|
||||||
|
|
||||||
|
EXPECT_THAT(GetCacheKey(GetCacheKey((int)-1), GetCacheKey("string"), GetCacheKey(A{}),
|
||||||
|
GetCacheKey(B())),
|
||||||
|
CacheKeyEq(R"({0:{0:-1},1:{0:6"string"},2:{0:structA},3:{0:classB}})"));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
} // namespace dawn::native
|
Loading…
Reference in New Issue