aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/http/io
diff options
context:
space:
mode:
authorAlexSm <alex@ydb.tech>2024-01-09 18:56:40 +0100
committerGitHub <noreply@github.com>2024-01-09 18:56:40 +0100
commite95f266d2a3e48e62015220588a4fd73d5d5a5cb (patch)
treea8a784b6931fe52ad5f511cfef85af14e5f63991 /library/cpp/http/io
parent50a65e3b48a82d5b51f272664da389f2e0b0c99a (diff)
downloadydb-e95f266d2a3e48e62015220588a4fd73d5d5a5cb.tar.gz
Library import 6 (#888)
Diffstat (limited to 'library/cpp/http/io')
-rw-r--r--library/cpp/http/io/benchmark/main.cpp81
-rw-r--r--library/cpp/http/io/benchmark/ya.make11
-rw-r--r--library/cpp/http/io/headers.cpp14
-rw-r--r--library/cpp/http/io/ya.make6
4 files changed, 108 insertions, 4 deletions
diff --git a/library/cpp/http/io/benchmark/main.cpp b/library/cpp/http/io/benchmark/main.cpp
new file mode 100644
index 0000000000..2a3a07b3bb
--- /dev/null
+++ b/library/cpp/http/io/benchmark/main.cpp
@@ -0,0 +1,81 @@
+#include <library/cpp/http/io/headers.h>
+
+#include <benchmark/benchmark.h>
+
+#include <util/stream/str.h>
+
+void FindHeaderFirstMatch(benchmark::State& state) {
+ THttpHeaders headers;
+ headers.AddHeader("Host", "example.com");
+ Y_ENSURE(headers.FindHeader("Host"));
+ for (auto _ : state) {
+ auto header = headers.FindHeader("Host");
+ benchmark::DoNotOptimize(header);
+ }
+}
+
+void FindHeaderNoMatchSameSize(benchmark::State& state) {
+ THttpHeaders headers;
+ for (char c = 'a'; c <= 'z'; ++c) {
+ headers.AddHeader(TString::Join(c, "aaa"), "some value");
+ }
+ Y_ENSURE(!headers.FindHeader("Host"));
+ for (auto _ : state) {
+ auto header = headers.FindHeader("Host");
+ benchmark::DoNotOptimize(header);
+ }
+}
+
+void FindHeaderNoMatchDifferentSizesNoCommonPrefix(benchmark::State& state) {
+ THttpHeaders headers;
+ for (char c = 'a'; c <= 'z'; ++c) { // same number of headers as above
+ headers.AddHeader("aaaaa", "some value");
+ }
+ Y_ENSURE(!headers.FindHeader("Host"));
+ for (auto _ : state) {
+ auto header = headers.FindHeader("Host");
+ benchmark::DoNotOptimize(header);
+ }
+}
+
+void FindHeaderNoMatchDifferentSizesCommonPrefix(benchmark::State& state) {
+ THttpHeaders headers;
+ for (char c = 'a'; c <= 'z'; ++c) {
+ headers.AddHeader("Host2", "some value");
+ }
+ Y_ENSURE(!headers.FindHeader("Host"));
+ for (auto _ : state) {
+ auto header = headers.FindHeader("Host");
+ benchmark::DoNotOptimize(header);
+ }
+}
+
+void FindHeaderMoreRealisticUseCase(benchmark::State& state) {
+ TString requestHeaders(R"(Host: yandex.ru
+User-Agent: Mozilla/5.0 ...
+Accept: */*
+Accept-Language: en-US,en;q=0.5
+Accept-Encoding: gzip, deflate, br
+Content-Type: text/plain;charset=UTF-8
+Content-Length: 1234
+Origin: https://a.yandex-team.ru
+Connection: keep-alive
+Referer: https://a.yandex-team.ru/
+Sec-Fetch-Dest: empty
+Sec-Fetch-Mode: no-cors
+Sec-Fetch-Site: cross-site
+TE: trailers)");
+ TStringInput stream(requestHeaders);
+ THttpHeaders headers(&stream);
+ Y_ENSURE(headers.FindHeader("Content-Type"));
+ for (auto _ : state) {
+ auto header = headers.FindHeader("Content-Type");
+ benchmark::DoNotOptimize(header);
+ }
+}
+
+BENCHMARK(FindHeaderFirstMatch);
+BENCHMARK(FindHeaderNoMatchSameSize);
+BENCHMARK(FindHeaderNoMatchDifferentSizesNoCommonPrefix);
+BENCHMARK(FindHeaderNoMatchDifferentSizesCommonPrefix);
+BENCHMARK(FindHeaderMoreRealisticUseCase);
diff --git a/library/cpp/http/io/benchmark/ya.make b/library/cpp/http/io/benchmark/ya.make
new file mode 100644
index 0000000000..6e1d252df0
--- /dev/null
+++ b/library/cpp/http/io/benchmark/ya.make
@@ -0,0 +1,11 @@
+G_BENCHMARK()
+
+PEERDIR(
+ library/cpp/http/io
+)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/http/io/headers.cpp b/library/cpp/http/io/headers.cpp
index 4ec27a29e8..f2baf64021 100644
--- a/library/cpp/http/io/headers.cpp
+++ b/library/cpp/http/io/headers.cpp
@@ -12,6 +12,13 @@ static inline TStringBuf Trim(const char* b, const char* e) noexcept {
return StripString(TStringBuf(b, e));
}
+static inline bool HeaderNameEqual(TStringBuf headerName, TStringBuf expectedName) noexcept {
+ // Most headers names have distinct sizes.
+ // Size comparison adds small overhead if all headers have the same size (~4% or lower with size = 4),
+ // but significantly speeds up the case where sizes are different (~4.5x for expectedName.size() = 4 and headerName.size() = 5)
+ return headerName.size() == expectedName.size() && AsciiCompareIgnoreCase(headerName, expectedName) == 0;
+}
+
THttpInputHeader::THttpInputHeader(const TStringBuf header) {
size_t pos = header.find(':');
@@ -65,7 +72,7 @@ bool THttpHeaders::HasHeader(const TStringBuf header) const {
const THttpInputHeader* THttpHeaders::FindHeader(const TStringBuf header) const {
for (const auto& hdr : Headers_) {
- if (AsciiCompareIgnoreCase(hdr.Name(), header) == 0) {
+ if (HeaderNameEqual(hdr.Name(), header)) {
return &hdr;
}
}
@@ -74,7 +81,7 @@ const THttpInputHeader* THttpHeaders::FindHeader(const TStringBuf header) const
void THttpHeaders::RemoveHeader(const TStringBuf header) {
for (auto h = Headers_.begin(); h != Headers_.end(); ++h) {
- if (AsciiCompareIgnoreCase(h->Name(), header) == 0) {
+ if (HeaderNameEqual(h->Name(), header)) {
Headers_.erase(h);
return;
}
@@ -82,8 +89,9 @@ void THttpHeaders::RemoveHeader(const TStringBuf header) {
}
void THttpHeaders::AddOrReplaceHeader(const THttpInputHeader& header) {
+ TStringBuf name = header.Name();
for (auto& hdr : Headers_) {
- if (AsciiCompareIgnoreCase(hdr.Name(), header.Name()) == 0) {
+ if (HeaderNameEqual(hdr.Name(), name)) {
hdr = header;
return;
}
diff --git a/library/cpp/http/io/ya.make b/library/cpp/http/io/ya.make
index 0390aecf55..20e014d011 100644
--- a/library/cpp/http/io/ya.make
+++ b/library/cpp/http/io/ya.make
@@ -17,7 +17,11 @@ SRCS(
END()
RECURSE(
- fuzz
list_codings
+)
+
+RECURSE_FOR_TESTS(
+ benchmark
+ fuzz
ut
)