[metadata] Reduce size by packing (#30474)

* [metadata] Reduce size by packing

* fix

* comment

* Automated change: Fix sanity tests

* Automated change: Fix sanity tests

* windows workaround?

* Revert "fix"

This reverts commit 925211164b.

* iterate encodables correctly

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/30787/head
Craig Tiller 2 years ago committed by GitHub
parent 9edded2cda
commit 18da150733
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      BUILD
  2. 35
      CMakeLists.txt
  3. 14
      build_autogenerated.yaml
  4. 4
      gRPC-C++.podspec
  5. 4
      gRPC-Core.podspec
  6. 2
      grpc.gemspec
  7. 2
      package.xml
  8. 40
      src/core/lib/gprpp/packed_table.h
  9. 98
      src/core/lib/gprpp/sorted_pack.h
  10. 10
      src/core/lib/gprpp/table.h
  11. 14
      src/core/lib/transport/metadata_batch.h
  12. 12
      test/core/gprpp/BUILD
  13. 70
      test/core/gprpp/sorted_pack_test.cc
  14. 2
      tools/doxygen/Doxyfile.c++.internal
  15. 2
      tools/doxygen/Doxyfile.core.internal
  16. 24
      tools/run_tests/generated/tests.json

21
BUILD

@ -1178,6 +1178,17 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "packed_table",
hdrs = ["src/core/lib/gprpp/packed_table.h"],
language = "c++",
deps = [
"gpr_public_hdrs",
"sorted_pack",
"table",
],
)
grpc_cc_library(
name = "bitset",
language = "c++",
@ -3141,6 +3152,7 @@ grpc_cc_library(
"latch",
"memory_quota",
"orphanable",
"packed_table",
"percent_encoding",
"poll",
"pollset_set",
@ -3699,6 +3711,15 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "sorted_pack",
hdrs = [
"src/core/lib/gprpp/sorted_pack.h",
],
language = "c++",
deps = ["gpr_platform"],
)
grpc_cc_library(
name = "idle_filter_state",
srcs = [

35
CMakeLists.txt generated

@ -1149,6 +1149,7 @@ if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx socket_utils_test)
endif()
add_dependencies(buildtests_cxx sorted_pack_test)
add_dependencies(buildtests_cxx spinlock_test)
add_dependencies(buildtests_cxx ssl_credentials_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@ -16904,6 +16905,40 @@ endif()
endif()
if(gRPC_BUILD_TESTS)
add_executable(sorted_pack_test
test/core/gprpp/sorted_pack_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(sorted_pack_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(sorted_pack_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(spinlock_test
test/core/gpr/spinlock_test.cc
third_party/googletest/googletest/src/gtest-all.cc

@ -792,9 +792,11 @@ libs:
- src/core/lib/gprpp/no_destruct.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/overload.h
- src/core/lib/gprpp/packed_table.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/single_set_ptr.h
- src/core/lib/gprpp/sorted_pack.h
- src/core/lib/gprpp/status_helper.h
- src/core/lib/gprpp/table.h
- src/core/lib/gprpp/time.h
@ -1997,9 +1999,11 @@ libs:
- src/core/lib/gprpp/no_destruct.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/overload.h
- src/core/lib/gprpp/packed_table.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/single_set_ptr.h
- src/core/lib/gprpp/sorted_pack.h
- src/core/lib/gprpp/status_helper.h
- src/core/lib/gprpp/table.h
- src/core/lib/gprpp/time.h
@ -9501,6 +9505,16 @@ targets:
- linux
- posix
- mac
- name: sorted_pack_test
gtest: true
build: test
language: c++
headers:
- src/core/lib/gprpp/sorted_pack.h
src:
- test/core/gprpp/sorted_pack_test.cc
deps: []
uses_polling: false
- name: spinlock_test
gtest: true
build: test

4
gRPC-C++.podspec generated

@ -731,9 +731,11 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/no_destruct.h',
'src/core/lib/gprpp/orphanable.h',
'src/core/lib/gprpp/overload.h',
'src/core/lib/gprpp/packed_table.h',
'src/core/lib/gprpp/ref_counted.h',
'src/core/lib/gprpp/ref_counted_ptr.h',
'src/core/lib/gprpp/single_set_ptr.h',
'src/core/lib/gprpp/sorted_pack.h',
'src/core/lib/gprpp/stat.h',
'src/core/lib/gprpp/status_helper.h',
'src/core/lib/gprpp/sync.h',
@ -1587,9 +1589,11 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/no_destruct.h',
'src/core/lib/gprpp/orphanable.h',
'src/core/lib/gprpp/overload.h',
'src/core/lib/gprpp/packed_table.h',
'src/core/lib/gprpp/ref_counted.h',
'src/core/lib/gprpp/ref_counted_ptr.h',
'src/core/lib/gprpp/single_set_ptr.h',
'src/core/lib/gprpp/sorted_pack.h',
'src/core/lib/gprpp/stat.h',
'src/core/lib/gprpp/status_helper.h',
'src/core/lib/gprpp/sync.h',

4
gRPC-Core.podspec generated

@ -1153,9 +1153,11 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/no_destruct.h',
'src/core/lib/gprpp/orphanable.h',
'src/core/lib/gprpp/overload.h',
'src/core/lib/gprpp/packed_table.h',
'src/core/lib/gprpp/ref_counted.h',
'src/core/lib/gprpp/ref_counted_ptr.h',
'src/core/lib/gprpp/single_set_ptr.h',
'src/core/lib/gprpp/sorted_pack.h',
'src/core/lib/gprpp/stat.h',
'src/core/lib/gprpp/stat_posix.cc',
'src/core/lib/gprpp/stat_windows.cc',
@ -2211,9 +2213,11 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/no_destruct.h',
'src/core/lib/gprpp/orphanable.h',
'src/core/lib/gprpp/overload.h',
'src/core/lib/gprpp/packed_table.h',
'src/core/lib/gprpp/ref_counted.h',
'src/core/lib/gprpp/ref_counted_ptr.h',
'src/core/lib/gprpp/single_set_ptr.h',
'src/core/lib/gprpp/sorted_pack.h',
'src/core/lib/gprpp/stat.h',
'src/core/lib/gprpp/status_helper.h',
'src/core/lib/gprpp/sync.h',

2
grpc.gemspec generated

@ -1066,9 +1066,11 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/gprpp/no_destruct.h )
s.files += %w( src/core/lib/gprpp/orphanable.h )
s.files += %w( src/core/lib/gprpp/overload.h )
s.files += %w( src/core/lib/gprpp/packed_table.h )
s.files += %w( src/core/lib/gprpp/ref_counted.h )
s.files += %w( src/core/lib/gprpp/ref_counted_ptr.h )
s.files += %w( src/core/lib/gprpp/single_set_ptr.h )
s.files += %w( src/core/lib/gprpp/sorted_pack.h )
s.files += %w( src/core/lib/gprpp/stat.h )
s.files += %w( src/core/lib/gprpp/stat_posix.cc )
s.files += %w( src/core/lib/gprpp/stat_windows.cc )

2
package.xml generated

@ -1048,9 +1048,11 @@
<file baseinstalldir="/" name="src/core/lib/gprpp/no_destruct.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/orphanable.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/overload.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/packed_table.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/ref_counted.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/ref_counted_ptr.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/single_set_ptr.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/sorted_pack.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/stat.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/stat_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/stat_windows.cc" role="src" />

@ -0,0 +1,40 @@
// Copyright 2022 gRPC 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 GRPC_CORE_LIB_GPRPP_PACKED_TABLE_H
#define GRPC_CORE_LIB_GPRPP_PACKED_TABLE_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/sorted_pack.h"
#include "src/core/lib/gprpp/table.h"
namespace grpc_core {
namespace packed_table_detail {
template <typename A, typename B>
struct Cmp {
static constexpr bool kValue = alignof(A) > alignof(B) ||
(alignof(A) == alignof(B) &&
sizeof(A) > sizeof(B));
};
}; // namespace packed_table_detail
template <typename... T>
using PackedTable =
typename WithSortedPack<Table, packed_table_detail::Cmp, T...>::Type;
} // namespace grpc_core
#endif // GRPC_CORE_LIB_GPRPP_PACKED_TABLE_H

@ -0,0 +1,98 @@
// Copyright 2022 gRPC 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 GRPC_CORE_LIB_GPRPP_SORTED_PACK_H
#define GRPC_CORE_LIB_GPRPP_SORTED_PACK_H
#include <grpc/support/port_platform.h>
#include <type_traits>
namespace grpc_core {
namespace sorted_pack_detail {
// A list of types
template <typename... A>
struct Typelist {
template <template <typename...> class T>
using Instantiate = T<A...>;
template <typename C>
using PushFront = Typelist<C, A...>;
};
// Find the smallest element of Args, and the rest of the elements
template <template <typename, typename> class Cmp, typename Args>
struct Smallest;
template <template <typename, typename> class Cmp, typename Arg,
typename... Args>
struct Smallest<Cmp, Typelist<Arg, Args...>> {
using SmallestRest = Smallest<Cmp, Typelist<Args...>>;
using PrevSmallest = typename SmallestRest::Result;
using PrevRest = typename SmallestRest::Rest;
static constexpr bool kCmpResult = Cmp<Arg, PrevSmallest>::kValue;
using Result = typename std::conditional<kCmpResult, Arg, PrevSmallest>::type;
using Prefix = typename std::conditional<kCmpResult, PrevSmallest, Arg>::type;
using Rest = typename PrevRest::template PushFront<Prefix>;
};
template <template <typename, typename> class Cmp, typename Arg>
struct Smallest<Cmp, Typelist<Arg>> {
using Result = Arg;
using Rest = Typelist<>;
};
// Sort a list of types into a typelist
template <template <typename, typename> class Cmp, typename Args>
struct Sorted;
template <template <typename, typename> class Cmp, typename... Args>
struct Sorted<Cmp, Typelist<Args...>> {
using SmallestResult = Smallest<Cmp, Typelist<Args...>>;
using SmallestType = typename SmallestResult::Result;
using RestOfTypes = typename SmallestResult::Rest;
using SortedRestOfTypes = typename Sorted<Cmp, RestOfTypes>::Result;
using Result = typename SortedRestOfTypes::template PushFront<SmallestType>;
};
template <template <typename, typename> class Cmp, typename Arg>
struct Sorted<Cmp, Typelist<Arg>> {
using Result = Typelist<Arg>;
};
template <template <typename, typename> class Cmp>
struct Sorted<Cmp, Typelist<>> {
using Result = Typelist<>;
};
} // namespace sorted_pack_detail
// Given a type T<A...>, and a type comparator Cmp<P,Q>, and some set of types
// Args...:
// Sort Args... using Cmp into SortedArgs..., then instantiate T<SortedArgs...>
// as Type.
// Cmp<P,Q> should have a single constant `kValue` that is true if P < Q.
template <template <typename...> class T,
template <typename, typename> class Cmp, typename... Args>
struct WithSortedPack {
using Type = typename sorted_pack_detail::Sorted<
Cmp,
sorted_pack_detail::Typelist<Args...>>::Result::template Instantiate<T>;
};
} // namespace grpc_core
#endif // GRPC_CORE_LIB_GPRPP_SORTED_PACK_H

@ -218,7 +218,7 @@ class Table {
// Check if this table has index I.
template <size_t I>
absl::enable_if_t < I<sizeof...(Ts), bool> has() const {
absl::enable_if_t<(I < sizeof...(Ts)), bool> has() const {
return present_bits_.is_set(I);
}
@ -317,6 +317,14 @@ class Table {
ForEachImpl(std::move(f), absl::make_index_sequence<sizeof...(Ts)>());
}
// Iterate through each set field in the table if it exists in Vs, in the
// order of Vs.
template <typename F, typename... Vs>
void ForEachIn(F f) const {
ForEachImpl(std::move(f),
absl::index_sequence<table_detail::IndexOf<Vs, Ts...>()...>());
}
// Count the number of set fields in the table
size_t count() const { return present_bits_.count(); }

@ -40,7 +40,7 @@
#include "src/core/lib/compression/compression_internal.h"
#include "src/core/lib/gprpp/chunked_vector.h"
#include "src/core/lib/gprpp/table.h"
#include "src/core/lib/gprpp/packed_table.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice.h"
@ -93,7 +93,7 @@ struct ContentTypeMetadata {
// gRPC says that content-type can be application/grpc[;something]
// Core has only ever verified the prefix.
// IF we want to start verifying more, we can expand this type.
enum ValueType {
enum ValueType : uint8_t {
kApplicationGrpc,
kEmpty,
kInvalid,
@ -112,7 +112,7 @@ struct ContentTypeMetadata {
// scheme metadata trait.
struct HttpSchemeMetadata {
static constexpr bool kRepeatable = false;
enum ValueType {
enum ValueType : uint8_t {
kHttp,
kHttps,
kInvalid,
@ -134,7 +134,7 @@ struct HttpSchemeMetadata {
// method metadata trait.
struct HttpMethodMetadata {
static constexpr bool kRepeatable = false;
enum ValueType {
enum ValueType : uint8_t {
kPost,
kGet,
kPut,
@ -1045,7 +1045,9 @@ class MetadataMap {
// void Encode(string_view key, Slice value);
template <typename Encoder>
void Encode(Encoder* encoder) const {
table_.ForEach(metadata_detail::EncodeWrapper<Encoder>{encoder});
table_.template ForEachIn<metadata_detail::EncodeWrapper<Encoder>,
Value<Traits>...>(
metadata_detail::EncodeWrapper<Encoder>{encoder});
for (const auto& unk : unknown_) {
encoder->Encode(unk.first, unk.second);
}
@ -1222,7 +1224,7 @@ class MetadataMap {
using Value = metadata_detail::Value<Which>;
// Table of known metadata types.
Table<Value<Traits>...> table_;
PackedTable<Value<Traits>...> table_;
metadata_detail::UnknownMap unknown_;
};

@ -355,6 +355,18 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "sorted_pack_test",
srcs = ["sorted_pack_test.cc"],
external_deps = ["gtest"],
language = "c++",
uses_event_engine = False,
uses_polling = False,
deps = [
"//:sorted_pack",
],
)
grpc_cc_test(
name = "unique_type_name_test",
srcs = ["unique_type_name_test.cc"],

@ -0,0 +1,70 @@
// Copyright 2022 gRPC 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 "src/core/lib/gprpp/sorted_pack.h"
#include <type_traits>
#include <vector>
#include <gtest/gtest.h>
using grpc_core::WithSortedPack;
template <int I>
struct Int {
int value() const { return I; }
};
template <typename A, typename B>
struct Cmp;
template <int A, int B>
struct Cmp<Int<A>, Int<B>> {
static constexpr bool kValue = A < B;
};
template <typename... Args>
struct VecMaker {
static std::vector<int> Make() { return {Args().value()...}; }
};
template <int... Args>
std::vector<int> TestVec() {
return WithSortedPack<VecMaker, Cmp, Int<Args>...>::Type::Make();
}
TEST(SortedPackTest, Empty) { EXPECT_EQ(TestVec<>(), std::vector<int>{}); }
TEST(SortedPackTest, LenOne) {
EXPECT_EQ((TestVec<1>()), (std::vector<int>{1}));
EXPECT_EQ((TestVec<2>()), (std::vector<int>{2}));
}
TEST(SortedPackTest, Len2) {
EXPECT_EQ((TestVec<1, 2>()), (std::vector<int>{1, 2}));
EXPECT_EQ((TestVec<2, 1>()), (std::vector<int>{1, 2}));
}
TEST(SortedPackTest, Len3) {
EXPECT_EQ((TestVec<1, 2, 3>()), (std::vector<int>{1, 2, 3}));
EXPECT_EQ((TestVec<1, 3, 2>()), (std::vector<int>{1, 2, 3}));
EXPECT_EQ((TestVec<2, 1, 3>()), (std::vector<int>{1, 2, 3}));
EXPECT_EQ((TestVec<2, 3, 1>()), (std::vector<int>{1, 2, 3}));
EXPECT_EQ((TestVec<3, 1, 2>()), (std::vector<int>{1, 2, 3}));
EXPECT_EQ((TestVec<3, 2, 1>()), (std::vector<int>{1, 2, 3}));
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -2049,9 +2049,11 @@ src/core/lib/gprpp/mpscq.h \
src/core/lib/gprpp/no_destruct.h \
src/core/lib/gprpp/orphanable.h \
src/core/lib/gprpp/overload.h \
src/core/lib/gprpp/packed_table.h \
src/core/lib/gprpp/ref_counted.h \
src/core/lib/gprpp/ref_counted_ptr.h \
src/core/lib/gprpp/single_set_ptr.h \
src/core/lib/gprpp/sorted_pack.h \
src/core/lib/gprpp/stat.h \
src/core/lib/gprpp/stat_posix.cc \
src/core/lib/gprpp/stat_windows.cc \

@ -1841,9 +1841,11 @@ src/core/lib/gprpp/mpscq.h \
src/core/lib/gprpp/no_destruct.h \
src/core/lib/gprpp/orphanable.h \
src/core/lib/gprpp/overload.h \
src/core/lib/gprpp/packed_table.h \
src/core/lib/gprpp/ref_counted.h \
src/core/lib/gprpp/ref_counted_ptr.h \
src/core/lib/gprpp/single_set_ptr.h \
src/core/lib/gprpp/sorted_pack.h \
src/core/lib/gprpp/stat.h \
src/core/lib/gprpp/stat_posix.cc \
src/core/lib/gprpp/stat_windows.cc \

@ -6123,6 +6123,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "sorted_pack_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save