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

utlity: Add benchmark for string-utility functions #2348

Merged
merged 18 commits into from
Jan 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
2804d6c
Add an HTML home page for the admin port, which makes it easier to surf
jmarantz Dec 21, 2017
8eb9e25
Add unit tests and get all tests working, correcting some path proble…
jmarantz Dec 22, 2017
29bc713
Make the admin HandlerCb pass through a headers reference so handlers…
jmarantz Dec 22, 2017
8fe318b
Merge remote-tracking branch 'refs/remotes/origin/master'
jmarantz Jan 3, 2018
5e5e8a4
Adds Google benchmark infrastructure, compiled externally via cmake.
jmarantz Jan 11, 2018
b79d16a
Shortens rightTrim function.
jmarantz Jan 11, 2018
70b105d
Removes string_review rightTrim impl in utility.cc, which should reve…
jmarantz Jan 11, 2018
be822f4
Remove absl includes now that I reverted the references to it.
jmarantz Jan 11, 2018
fcdfe13
Fix braces nit in boilerplate main code. Remove excess printing.
jmarantz Jan 11, 2018
daf4d41
Add external_deps support to envoy_cc_binary and remove the intermedi…
jmarantz Jan 11, 2018
9057266
Remove gtest dependency from benchmark.
jmarantz Jan 11, 2018
c94cf1d
Merge branch 'master' into add-benchmark-library
jmarantz Jan 17, 2018
dc1db43
Merge branch 'master' into add-benchmark-library
jmarantz Jan 17, 2018
5132ae7
Remove some detritus from earlier PRs and stats_speed_test, which is …
jmarantz Jan 17, 2018
bcf5812
Update the SHA to hopefully get CI to work.
jmarantz Jan 18, 2018
b22ea04
Add an alternative faster implementation for finding a value in a token.
jmarantz Jan 18, 2018
dda3cda
Add an alternative faster findToken operation.
jmarantz Jan 19, 2018
12b97c6
formatting fix-up.
jmarantz Jan 23, 2018
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
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
references:
envoy-build-image: &envoy-build-image
envoyproxy/envoy-build:52f6880ffbf761c9b809fc3ac208900956ff16b4
envoyproxy/envoy-build:61b38528d7e46ced9d749d278ba185332310ca95

version: 2
jobs:
Expand Down
14 changes: 14 additions & 0 deletions test/common/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ licenses(["notice"]) # Apache 2

load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_binary",
"envoy_cc_test",
"envoy_package",
)
Expand Down Expand Up @@ -78,3 +79,16 @@ envoy_cc_test(
srcs = ["shared_memory_hash_set_test.cc"],
deps = ["//source/common/common:shared_memory_hash_set_lib"],
)

envoy_cc_binary(
name = "utility_speed_test",
srcs = ["utility_speed_test.cc"],
external_deps = [
"abseil_strings",
"benchmark",
],
deps = [
"//source/common/common:assert_lib",
"//source/common/common:utility_lib",
],
)
157 changes: 157 additions & 0 deletions test/common/common/utility_speed_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Note: this should be run with --compilation_mode=opt, and would benefit from a
// quiescent system with disabled cstate power management.

#include "common/common/assert.h"
#include "common/common/utility.h"

#include "absl/strings/string_view.h"
#include "testing/base/public/benchmark.h"

static const char TextToTrim[] = "\t the quick brown fox jumps over the lazy dog\n\r\n";
static size_t TextToTrimLength = sizeof(TextToTrim) - 1;

static const char AlreadyTrimmed[] = "the quick brown fox jumps over the lazy dog";
static size_t AlreadyTrimmedLength = sizeof(AlreadyTrimmed) - 1;

static const char CacheControl[] = "private, max-age=300, no-transform";
static size_t CacheControlLength = sizeof(CacheControl) - 1;

// NOLINT(namespace-envoy)

static void BM_RTrimStringView(benchmark::State& state) {
int accum = 0;
for (auto _ : state) {
absl::string_view text(TextToTrim, TextToTrimLength);
text = Envoy::StringUtil::rtrim(text);
accum += TextToTrimLength - text.size();
}
benchmark::DoNotOptimize(accum);
}
BENCHMARK(BM_RTrimStringView);

static void BM_RTrimStringViewAlreadyTrimmed(benchmark::State& state) {
int accum = 0;
for (auto _ : state) {
absl::string_view text(AlreadyTrimmed, AlreadyTrimmedLength);
text = Envoy::StringUtil::rtrim(text);
accum += AlreadyTrimmedLength - text.size();
}
benchmark::DoNotOptimize(accum);
}
BENCHMARK(BM_RTrimStringViewAlreadyTrimmed);

static void BM_RTrimStringViewAlreadyTrimmedAndMakeString(benchmark::State& state) {
int accum = 0;
for (auto _ : state) {
absl::string_view text(AlreadyTrimmed, AlreadyTrimmedLength);
std::string string_copy = std::string(Envoy::StringUtil::rtrim(text));
accum += AlreadyTrimmedLength - string_copy.size();
}
benchmark::DoNotOptimize(accum);
}
BENCHMARK(BM_RTrimStringViewAlreadyTrimmedAndMakeString);

static void BM_FindToken(benchmark::State& state) {
const absl::string_view cache_control(CacheControl, CacheControlLength);
for (auto _ : state) {
RELEASE_ASSERT(Envoy::StringUtil::findToken(cache_control, ",", "no-transform"));
}
}
BENCHMARK(BM_FindToken);

static bool nextToken(absl::string_view& str, char delim, bool stripWhitespace,
absl::string_view* token) {
while (!str.empty()) {
absl::string_view::size_type pos = str.find(delim);
if (pos == absl::string_view::npos) {
*token = str.substr(0, str.size());
str.remove_prefix(str.size()); // clears str
} else {
*token = str.substr(0, pos);
str.remove_prefix(pos + 1); // move past token and delim
}
if (stripWhitespace) {
*token = Envoy::StringUtil::trim(*token);
}
if (!token->empty()) {
return true;
}
}
return false;
}

// Experimental alternative implementation of StringUtil::findToken which doesn't create
// a temp vector, but just iterates through the string_view, tokenizing, and matching against
// the token we want. It appears to be about 2.5x to 3x faster on this testcase.
static bool findTokenWithoutSplitting(absl::string_view str, char delim, absl::string_view token,
bool stripWhitespace) {
for (absl::string_view tok; nextToken(str, delim, stripWhitespace, &tok);) {
if (tok == token) {
return true;
}
}
return false;
}

static void BM_FindTokenWithoutSplitting(benchmark::State& state) {
const absl::string_view cache_control(CacheControl, CacheControlLength);
for (auto _ : state) {
RELEASE_ASSERT(findTokenWithoutSplitting(cache_control, ',', "no-transform", true));
}
}
BENCHMARK(BM_FindTokenWithoutSplitting);

static void BM_FindTokenValueNestedSplit(benchmark::State& state) {
const absl::string_view cache_control(CacheControl, CacheControlLength);
absl::string_view max_age;
for (auto _ : state) {
for (absl::string_view token : Envoy::StringUtil::splitToken(cache_control, ",")) {
auto name_value = Envoy::StringUtil::splitToken(token, "=");
if ((name_value.size() == 2) && (Envoy::StringUtil::trim(name_value[0]) == "max-age")) {
max_age = Envoy::StringUtil::trim(name_value[1]);
}
}
RELEASE_ASSERT(max_age == "300");
}
}
BENCHMARK(BM_FindTokenValueNestedSplit);

static void BM_FindTokenValueSearchForEqual(benchmark::State& state) {
for (auto _ : state) {
const absl::string_view cache_control(CacheControl, CacheControlLength);
absl::string_view max_age;
for (absl::string_view token : Envoy::StringUtil::splitToken(cache_control, ",")) {
absl::string_view::size_type equals = token.find('=');
if (equals != absl::string_view::npos &&
Envoy::StringUtil::trim(token.substr(0, equals)) == "max-age") {
max_age = Envoy::StringUtil::trim(token.substr(equals + 1));
}
}
RELEASE_ASSERT(max_age == "300");
}
}
BENCHMARK(BM_FindTokenValueSearchForEqual);

static void BM_FindTokenValueNoSplit(benchmark::State& state) {
for (auto _ : state) {
absl::string_view cache_control(CacheControl, CacheControlLength);
absl::string_view max_age;
for (absl::string_view token; nextToken(cache_control, ',', true, &token);) {
absl::string_view name;
if (nextToken(token, '=', true, &name) && (name == "max-age")) {
max_age = Envoy::StringUtil::trim(token);
}
}
RELEASE_ASSERT(max_age == "300");
}
}
BENCHMARK(BM_FindTokenValueNoSplit);

// Boilerplate main(), which discovers benchmarks in the same file and runs them.
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv)) {
return 1;
}
benchmark::RunSpecifiedBenchmarks();
}