mirror of https://github.com/grpc/grpc.git
Split the filter popularity counting into a separate module (#26884)
* split hpack encoder filter into a separate class * chores * fix * Automated change: Fix sanity tests * include guards * add suppressions * Update popularity_count_test.cc Co-authored-by: ctiller <ctiller@users.noreply.github.com>pull/26851/head^2
parent
3e122fd050
commit
58d3161aac
16 changed files with 250 additions and 44 deletions
@ -0,0 +1,62 @@ |
||||
// Copyright 2021 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_EXT_TRANSPORT_CHTTP2_TRANSPORT_POPULARITY_COUNT_H |
||||
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_POPULARITY_COUNT_H |
||||
|
||||
#include <grpc/impl/codegen/port_platform.h> |
||||
|
||||
#include "include/grpc/impl/codegen/port_platform.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
// filter tables for elems: this tables provides an approximate
|
||||
// popularity count for particular hashes, and are used to determine whether
|
||||
// a new literal should be added to the compression table or not.
|
||||
// They track a single integer that counts how often a particular value has
|
||||
// been seen. When that count reaches max (255), all values are halved. */
|
||||
template <uint8_t kElems> |
||||
class PopularityCount { |
||||
public: |
||||
PopularityCount() : sum_{0}, elems_{} {} |
||||
|
||||
// increment a filter count, halve all counts if one element reaches max
|
||||
// return true if this element seems to be popular, false otherwise
|
||||
bool AddElement(uint8_t idx) { |
||||
elems_[idx]++; |
||||
if (GPR_LIKELY(elems_[idx] < 255)) { |
||||
sum_++; |
||||
} else { |
||||
HalveFilter(); |
||||
} |
||||
return elems_[idx] >= 2 * sum_ / kElems; |
||||
} |
||||
|
||||
private: |
||||
// halve all counts because an element reached max
|
||||
void HalveFilter() { |
||||
sum_ = 0; |
||||
for (int i = 0; i < kElems; i++) { |
||||
elems_[i] /= 2; |
||||
sum_ += elems_[i]; |
||||
} |
||||
} |
||||
|
||||
uint32_t sum_; |
||||
uint8_t elems_[kElems]; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_POPULARITY_COUNT_H */ |
@ -0,0 +1,73 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2020 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 "include/grpc/impl/codegen/port_platform.h" |
||||
|
||||
#include <gtest/gtest.h> |
||||
#include <array> |
||||
#include "src/core/ext/transport/chttp2/transport/popularity_count.h" |
||||
|
||||
namespace grpc_core { |
||||
namespace testing { |
||||
|
||||
static constexpr uint8_t kTestSize = 4; |
||||
|
||||
struct Scenario { |
||||
std::array<uint8_t, kTestSize> initial_values; |
||||
uint8_t final_add; |
||||
bool expectation; |
||||
}; |
||||
|
||||
std::ostream& operator<<(std::ostream& out, Scenario s) { |
||||
out << "init:"; |
||||
for (size_t i = 0; i < kTestSize; i++) { |
||||
if (i != 0) { |
||||
out << ","; |
||||
} |
||||
out << static_cast<int>(s.initial_values[i]); |
||||
} |
||||
out << " final:" << static_cast<int>(s.final_add); |
||||
out << " expect:" << (s.expectation ? "true" : "false"); |
||||
return out; |
||||
} |
||||
|
||||
struct PopularityCountTest : public ::testing::TestWithParam<Scenario> {}; |
||||
|
||||
TEST_P(PopularityCountTest, Test) { |
||||
Scenario s = GetParam(); |
||||
PopularityCount<kTestSize> pop; |
||||
for (size_t i = 0; i < kTestSize; i++) { |
||||
for (size_t j = 0; j < s.initial_values[i]; j++) { |
||||
pop.AddElement(i); |
||||
} |
||||
} |
||||
EXPECT_EQ(pop.AddElement(s.final_add), s.expectation); |
||||
} |
||||
|
||||
INSTANTIATE_TEST_SUITE_P(InterestingTests, PopularityCountTest, |
||||
::testing::Values(Scenario{{0, 0, 0, 0}, 0, true}, |
||||
Scenario{{64, 0, 0, 0}, 0, true}, |
||||
Scenario{{64, 0, 0, 0}, 1, false})); |
||||
|
||||
} // namespace testing
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char** argv) { |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
return RUN_ALL_TESTS(); |
||||
} |
Loading…
Reference in new issue