Skip to content
File

Blob: src/workerd/tests/bench-api-headers.c++

3.9 KB
1// Copyright (c) 2023 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#include <workerd/api/http.h>
6#include <workerd/tests/bench-tools.h>
7#include <workerd/tests/test-fixture.h>
8 
9// A benchmark for js Header class.
10 
11namespace workerd {
12namespace {
13 
14struct ApiHeaders: public benchmark::Fixture {
15 virtual ~ApiHeaders() noexcept(true) {}
16 
17 struct Header {
18 bool append;
19 kj::StringPtr name;
20 kj::StringPtr value;
21 };
22 
23 void SetUp(benchmark::State& state) noexcept(true) override {
24 fixture = kj::heap<TestFixture>();
25 
26 kj::HttpHeaderTable::Builder builder;
27 builder.add("Host");
28 builder.add("Accept");
29 builder.add("Content-Type");
30 builder.add("Last-Modified");
31 table = builder.build();
32 kjHeaders = kj::heap<kj::HttpHeaders>(*table);
33 auto in = kj::heapString(
34 "GET /favicon.ico HTTP/1.1\r\n"
35 "Host: 0.0.0.0=5000\r\n"
36 "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n"
37 "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
38 "Accept-Language: en-us,en;q=0.5\r\n"
39 "Accept-Encoding: gzip,deflate\r\n"
40 "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n"
41 "Keep-Alive: 300\r\n"
42 "Connection: keep-alive\r\n"
43 "\r\n");
44 KJ_EXPECT(kjHeaders->tryParseRequest(in.asArray()).is<kj::HttpHeaders::Request>());
45 original = kj::mv(in);
46 }
47 
48 void TearDown(benchmark::State& state) noexcept(true) override {
49 fixture = nullptr;
50 }
51 
52 kj::Maybe<kj::String> original;
53 kj::Own<TestFixture> fixture;
54 kj::Own<kj::HttpHeaderTable> table;
55 kj::Own<kj::HttpHeaders> kjHeaders;
56 Header kHeaders[13] = {Header{false, "Host"_kj, "example.com"_kj},
57 Header{false, "User-Agent"_kj,
58 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"_kj},
59 Header{false, "Accept"_kj,
60 "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"_kj},
61 Header{false, "Accept-Language"_kj, "en-US,en;q=0.9"_kj},
62 Header{false, "Accept-Encoding"_kj, "gzip, deflate, br"_kj},
63 Header{false, "Content-Type"_kj, "application/json; charset=utf-8"_kj},
64 Header{false, "Authorization"_kj,
65 "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0"_kj},
66 Header{false, "Cache-Control"_kj, "no-cache, no-store, must-revalidate"_kj},
67 Header{false, "Content-Length"_kj, "1234"_kj},
68 Header{false, "Referer"_kj, "https://www.example.com/page?query=value&other=param"_kj},
69 Header{false, "X-Forwarded-For"_kj, "203.0.113.1, 198.51.100.17"_kj},
70 Header{true, "Set-Cookie"_kj, "new_session=token123; Path=/; Secure; HttpOnly"_kj},
71 Header{true, "Set-Cookie"_kj, "new_session=token124; Path=/abc; Secure; HttpOnly"_kj}};
72};
73 
74// initialization performs a lot of copying, benchmark it
75BENCHMARK_F(ApiHeaders, constructor)(benchmark::State& state) {
76 fixture->runInIoContext([&](const TestFixture::Environment& env) {
77 auto& js = env.js;
78 for (auto _: state) {
79 for (size_t i = 0; i < 10000; ++i) {
80 benchmark::DoNotOptimize(
81 js.alloc<api::Headers>(js, *kjHeaders, api::Headers::Guard::REQUEST));
82 benchmark::DoNotOptimize(i);
83 }
84 }
85 });
86}
87 
88BENCHMARK_F(ApiHeaders, set_append)(benchmark::State& state) {
89 fixture->runInIoContext([&](const TestFixture::Environment& env) {
90 auto& js = env.js;
91 for (auto _: state) {
92 for (size_t i = 0; i < 1000; ++i) {
93 auto headers = js.alloc<api::Headers>();
94 // Set common headers with various representative lengths
95 for (auto& h: kHeaders) {
96 if (h.append) {
97 headers->append(env.js, kj::str(h.name), kj::str(h.value));
98 } else {
99 headers->set(env.js, kj::str(h.name), kj::str(h.value));
100 }
101 }
102 benchmark::DoNotOptimize(i);
103 }
104 }
105 });
106}
107} // namespace
108} // namespace workerd