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