Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compressor filter: add benchmark #10464

Merged
merged 32 commits into from
Apr 24, 2020
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
618fc6d
compressor filter: add benchmark
Mar 20, 2020
25524ce
Fix format
Mar 20, 2020
8b88265
Replace boiler plate with macro
Mar 20, 2020
a2f322b
Test a broader combination of params
Mar 21, 2020
4e38c4b
Trailing semi colon
Mar 21, 2020
36e8542
Fixes
Mar 22, 2020
c5dfbb0
Test different chunk sizes (8k, 1k)
Mar 23, 2020
826284b
Add test for 4k
Mar 23, 2020
db99a49
Reuse MockStreamDecoderFilterCallbacks
Mar 23, 2020
1c642a5
Update benchmark output comment
Mar 23, 2020
6461dfa
Move 8k chunks test to the top
Mar 23, 2020
93a5664
Update comment with 8k result
Mar 23, 2020
2562886
Move test buffers creation out of hot path
Mar 23, 2020
7b3a2c7
Merge remote-tracking branch 'upstream/master' into compressor-add-be…
Mar 24, 2020
0c974f2
Merge remote-tracking branch 'upstream/master' into compressor-add-be…
Apr 1, 2020
13fcda1
Properly move chunks
Apr 2, 2020
a4c43fd
Fixes
Apr 2, 2020
b459ca5
Format
Apr 2, 2020
5de4a96
Merge remote-tracking branch 'upstream/master' into compressor-add-be…
Apr 2, 2020
d9c397e
clang-tidy
Apr 2, 2020
707bdde
Merge remote-tracking branch 'upstream/master' into compressor-add-be…
Apr 5, 2020
bf7c4bb
Merge remote-tracking branch 'upstream/master' into compressor-add-be…
Apr 7, 2020
63c1bd2
Merge remote-tracking branch 'upstream/master' into compressor-add-be…
Apr 7, 2020
63f77b7
Add test for 16kb sized chunk
Apr 7, 2020
23ec050
Use manual timings to skip random data generation
Apr 8, 2020
eae6281
Merge remote-tracking branch 'upstream/master' into compressor-add-be…
Apr 8, 2020
0c9cd0d
Save resuls, useful for debugging
Apr 8, 2020
ddb4536
Merge remote-tracking branch 'upstream/master' into compressor-add-be…
Apr 13, 2020
2ec1e3b
Merge remote-tracking branch 'upstream/master' into compressor-add-be…
Apr 14, 2020
7b5a38a
Use the same input for all tests
Apr 14, 2020
031b1fd
Merge remote-tracking branch 'upstream/master' into compressor-add-be…
Apr 15, 2020
4b71256
Fix format
Apr 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions test/extensions/filters/http/common/compressor/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ licenses(["notice"]) # Apache 2
load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_test",
"envoy_cc_test_binary",
"envoy_package",
)

Expand All @@ -21,3 +22,23 @@ envoy_cc_test(
"@envoy_api//envoy/extensions/filters/http/compressor/v3:pkg_cc_proto",
],
)

envoy_cc_test_binary(
name = "compressor_filter_speed_test",
srcs = ["compressor_filter_speed_test.cc"],
external_deps = [
"benchmark",
"googletest",
],
deps = [
"//source/common/compressor:compressor_lib",
"//source/common/protobuf:utility_lib",
"//source/extensions/filters/http/common/compressor:compressor_lib",
"//test/mocks/http:http_mocks",
"//test/mocks/protobuf:protobuf_mocks",
"//test/mocks/runtime:runtime_mocks",
"//test/test_common:printers_lib",
"//test/test_common:utility_lib",
"@envoy_api//envoy/extensions/filters/http/compressor/v3:pkg_cc_proto",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
#include "envoy/extensions/filters/http/compressor/v3/compressor.pb.h"

#include "common/compressor/zlib_compressor_impl.h"

#include "extensions/filters/http/common/compressor/compressor.h"

#include "test/mocks/http/mocks.h"
#include "test/mocks/runtime/mocks.h"
#include "test/mocks/stats/mocks.h"

#include "benchmark/benchmark.h"
#include "gmock/gmock.h"

using testing::Return;

namespace Envoy {
namespace Extensions {
namespace HttpFilters {
namespace Common {
namespace Compressors {

class MockCompressorFilterConfig : public CompressorFilterConfig {
public:
MockCompressorFilterConfig(
const envoy::extensions::filters::http::compressor::v3::Compressor& compressor,
const std::string& stats_prefix, Stats::Scope& scope, Runtime::Loader& runtime,
const std::string& compressor_name,
Envoy::Compressor::ZlibCompressorImpl::CompressionLevel level,
Envoy::Compressor::ZlibCompressorImpl::CompressionStrategy strategy, int64_t window_bits,
uint64_t memory_level)
: CompressorFilterConfig(compressor, stats_prefix + compressor_name + ".", scope, runtime,
compressor_name),
level_(level), strategy_(strategy), window_bits_(window_bits), memory_level_(memory_level) {
}

std::unique_ptr<Compressor::Compressor> makeCompressor() override {
auto compressor = std::make_unique<Compressor::ZlibCompressorImpl>();
compressor->init(level_, strategy_, window_bits_, memory_level_);
return compressor;
}

const Envoy::Compressor::ZlibCompressorImpl::CompressionLevel level_;
const Envoy::Compressor::ZlibCompressorImpl::CompressionStrategy strategy_;
const int64_t window_bits_;
const uint64_t memory_level_;
};

using CompressionParams =
std::tuple<Envoy::Compressor::ZlibCompressorImpl::CompressionLevel,
Envoy::Compressor::ZlibCompressorImpl::CompressionStrategy, int64_t, uint64_t>;

static std::vector<Buffer::OwnedImpl> generateChunks(const uint64_t chunk_count,
const uint64_t chunk_size) {
std::vector<Buffer::OwnedImpl> vec;
vec.reserve(chunk_count);

Buffer::OwnedImpl data;
TestUtility::feedBufferWithRandomCharacters(data, chunk_size);

for (uint64_t i = 0; i < chunk_count; ++i) {
Buffer::OwnedImpl chunk;
chunk.add(data);
vec.push_back(std::move(chunk));
}

return vec;
}

static void compressWith(std::vector<Buffer::OwnedImpl> chunks, CompressionParams params,
rgs1 marked this conversation as resolved.
Show resolved Hide resolved
NiceMock<Http::MockStreamDecoderFilterCallbacks>& decoder_callbacks) {
Stats::IsolatedStoreImpl stats;
testing::NiceMock<Runtime::MockLoader> runtime;
envoy::extensions::filters::http::compressor::v3::Compressor compressor;

const auto level = std::get<0>(params);
const auto strategy = std::get<1>(params);
const auto window_bits = std::get<2>(params);
const auto memory_level = std::get<3>(params);
CompressorFilterConfigSharedPtr config = std::make_shared<MockCompressorFilterConfig>(
compressor, "test.", stats, runtime, "gzip", level, strategy, window_bits, memory_level);

ON_CALL(runtime.snapshot_, featureEnabled("test.filter_enabled", 100))
.WillByDefault(Return(true));

auto filter = std::make_unique<CompressorFilter>(config);
filter->setDecoderFilterCallbacks(decoder_callbacks);

Http::TestRequestHeaderMapImpl headers = {{":method", "get"}, {"accept-encoding", "gzip"}};
filter->decodeHeaders(headers, false);

Http::TestResponseHeaderMapImpl response_headers = {
{":method", "get"},
{"content-length", "122880"},
{"content-type", "application/json;charset=utf-8"}};
filter->encodeHeaders(response_headers, false);

uint64_t idx = 0;
uint64_t total_uncompressed_bytes = 0;
uint64_t total_compressed_bytes = 0;
for (auto& data : chunks) {
total_uncompressed_bytes += data.length();

if (idx == (chunks.size() - 1)) {
filter->encodeData(data, true);
} else {
filter->encodeData(data, false);
}

total_compressed_bytes += data.length();
++idx;
}

EXPECT_EQ(total_uncompressed_bytes, stats.counter("test.gzip.total_uncompressed_bytes").value());
EXPECT_EQ(total_compressed_bytes, stats.counter("test.gzip.total_compressed_bytes").value());
EXPECT_EQ(1U, stats.counter("test.gzip.compressed").value());
}

// SPELLCHECKER(off)
/*
Running ./bazel-bin/test/extensions/filters/http/common/compressor/compressor_filter_speed_test
Run on (8 X 2300 MHz CPU s)
CPU Caches:
L1 Data 32K (x4)
L1 Instruction 32K (x4)
L2 Unified 262K (x4)
L3 Unified 6291K (x1)
Load Average: 1.82, 1.72, 1.74
***WARNING*** Library was built as DEBUG. Timings may be affected.
------------------------------------------------------------
Benchmark Time CPU Iterations
------------------------------------------------------------
....

CompressChunks8192/2 2971499 ns 2967258 ns 248
CompressChunks8192/2 3015538 ns 3008694 ns 248
CompressChunks8192/2 2919954 ns 2907698 ns 248
CompressChunks8192/2 2838894 ns 2831851 ns 248
CompressChunks8192/2 2867619 ns 2865883 ns 248
CompressChunks8192/2_mean 2922701 ns 2916277 ns 5
CompressChunks8192/2_median 2919954 ns 2907698 ns 5
CompressChunks8192/2_stddev 72569 ns 72251 ns 5
....
*/
// SPELLCHECKER(on)

static std::vector<CompressionParams> compression_params = {
// Speed + Standard + Small Window + Low mem level
{Envoy::Compressor::ZlibCompressorImpl::CompressionLevel::Speed,
Envoy::Compressor::ZlibCompressorImpl::CompressionStrategy::Standard, 9, 1},

// Speed + Standard + Med window + Med mem level
{Envoy::Compressor::ZlibCompressorImpl::CompressionLevel::Speed,
Envoy::Compressor::ZlibCompressorImpl::CompressionStrategy::Standard, 12, 5},

// Speed + Standard + Big window + High mem level
{Envoy::Compressor::ZlibCompressorImpl::CompressionLevel::Speed,
Envoy::Compressor::ZlibCompressorImpl::CompressionStrategy::Standard, 15, 9},

// Standard + Standard + Small window + Low mem level
{Envoy::Compressor::ZlibCompressorImpl::CompressionLevel::Standard,
Envoy::Compressor::ZlibCompressorImpl::CompressionStrategy::Standard, 9, 1},

// Standard + Standard + Med window + Med mem level
{Envoy::Compressor::ZlibCompressorImpl::CompressionLevel::Standard,
Envoy::Compressor::ZlibCompressorImpl::CompressionStrategy::Standard, 12, 5},

// Standard + Standard + High window + High mem level
{Envoy::Compressor::ZlibCompressorImpl::CompressionLevel::Standard,
Envoy::Compressor::ZlibCompressorImpl::CompressionStrategy::Standard, 15, 9},

// Best + Standard + Small window + Low mem level
{Envoy::Compressor::ZlibCompressorImpl::CompressionLevel::Best,
Envoy::Compressor::ZlibCompressorImpl::CompressionStrategy::Standard, 9, 1},

// Best + Standard + Med window + Med mem level
{Envoy::Compressor::ZlibCompressorImpl::CompressionLevel::Best,
Envoy::Compressor::ZlibCompressorImpl::CompressionStrategy::Standard, 12, 5},

// Best + Standard + High window + High mem level
{Envoy::Compressor::ZlibCompressorImpl::CompressionLevel::Best,
Envoy::Compressor::ZlibCompressorImpl::CompressionStrategy::Standard, 15, 9}};

static void CompressChunks8192(benchmark::State& state) {
NiceMock<Http::MockStreamDecoderFilterCallbacks> decoder_callbacks;
const auto idx = state.range(0);
const auto& params = compression_params[idx];

for (auto _ : state) {
std::vector<Buffer::OwnedImpl> chunks = generateChunks(15, 8192);
compressWith(std::move(chunks), params, decoder_callbacks);
}
}
BENCHMARK(CompressChunks8192)->DenseRange(0, 8, 1);

static void CompressChunks4096(benchmark::State& state) {
NiceMock<Http::MockStreamDecoderFilterCallbacks> decoder_callbacks;
const auto idx = state.range(0);
const auto& params = compression_params[idx];

for (auto _ : state) {
std::vector<Buffer::OwnedImpl> chunks = generateChunks(30, 4096);
compressWith(std::move(chunks), params, decoder_callbacks);
}
}
BENCHMARK(CompressChunks4096)->DenseRange(0, 8, 1);

static void CompressChunks1024(benchmark::State& state) {
NiceMock<Http::MockStreamDecoderFilterCallbacks> decoder_callbacks;
const auto idx = state.range(0);
const auto& params = compression_params[idx];

for (auto _ : state) {
std::vector<Buffer::OwnedImpl> chunks = generateChunks(120, 1024);
compressWith(std::move(chunks), params, decoder_callbacks);
}
}
BENCHMARK(CompressChunks1024)->DenseRange(0, 8, 1);

static void CompressFull(benchmark::State& state) {
NiceMock<Http::MockStreamDecoderFilterCallbacks> decoder_callbacks;
const auto idx = state.range(0);
const auto& params = compression_params[idx];

for (auto _ : state) {
std::vector<Buffer::OwnedImpl> chunks = generateChunks(1, 122880);
compressWith(std::move(chunks), params, decoder_callbacks);
}
}
BENCHMARK(CompressFull)->DenseRange(0, 8, 1);

} // namespace Compressors
} // namespace Common
} // namespace HttpFilters
} // namespace Extensions
} // namespace Envoy

BENCHMARK_MAIN();