Skip to content
File

Blob: src/workerd/tests/bench-jsstring.c++

12.1 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/jsg/jsg.h>
6#include <workerd/jsg/setup.h>
7#include <workerd/tests/bench-tools.h>
8#include <workerd/tests/test-fixture.h>
9 
10// Benchmark for JsString.utf8Length() method across different string types:
11// latin1/utf16, flat/non-flat, and various sizes.
12 
13namespace workerd {
14namespace {
15 
16template <size_t N>
17jsg::JsString createLatin1String(jsg::Lock& js) {
18 kj::FixedArray<char, N> vec;
19 vec.fill('a');
20 if (N > 1) {
21 vec[N / 2] = static_cast<char>(0xC0);
22 }
23 return js.str(vec.asPtr());
24}
25 
26template <size_t N>
27jsg::JsString createUtf16String(jsg::Lock& js) {
28 kj::FixedArray<uint16_t, N> vec;
29 vec.fill(0x1F600 & 0xFFFF);
30 return js.str(vec.asPtr());
31}
32 
33template <size_t N>
34jsg::JsString createInvalidUtf16String(jsg::Lock& js) {
35 kj::FixedArray<uint16_t, N> vec;
36 vec.fill(0x1F600 & 0xFFFF);
37 if (N > 1) {
38 vec[N / 2] = 0xD800;
39 }
40 return js.str(vec.asPtr());
41}
42 
43// Benchmarks utf8Length on 32-char latin1 flat strings
44static void JsString_Utf8Length_Latin1_Flat_32(benchmark::State& state) {
45 TestFixture fixture;
46 fixture.runInIoContext([&](const TestFixture::Environment& env) {
47 auto& js = env.js;
48 auto str = createLatin1String<32>(js);
49 
50 for (auto _: state) {
51 KJ_ASSERT(str.isFlat());
52 benchmark::DoNotOptimize(str.utf8Length(js));
53 }
54 });
55}
56 
57// Benchmarks utf8Length on 256-char latin1 flat strings
58static void JsString_Utf8Length_Latin1_Flat_256(benchmark::State& state) {
59 TestFixture fixture;
60 fixture.runInIoContext([&](const TestFixture::Environment& env) {
61 auto& js = env.js;
62 auto str = createLatin1String<256>(js);
63 
64 for (auto _: state) {
65 KJ_ASSERT(str.isFlat());
66 benchmark::DoNotOptimize(str.utf8Length(js));
67 }
68 });
69}
70 
71// Benchmarks utf8Length on 1024-char latin1 flat strings
72static void JsString_Utf8Length_Latin1_Flat_1024(benchmark::State& state) {
73 TestFixture fixture;
74 fixture.runInIoContext([&](const TestFixture::Environment& env) {
75 auto& js = env.js;
76 auto str = createLatin1String<1024>(js);
77 
78 for (auto _: state) {
79 KJ_ASSERT(str.isFlat());
80 benchmark::DoNotOptimize(str.utf8Length(js));
81 }
82 });
83}
84 
85// Benchmarks utf8Length on 8192-char latin1 flat strings
86static void JsString_Utf8Length_Latin1_Flat_8192(benchmark::State& state) {
87 TestFixture fixture;
88 fixture.runInIoContext([&](const TestFixture::Environment& env) {
89 auto& js = env.js;
90 auto str = createLatin1String<8192>(js);
91 
92 for (auto _: state) {
93 KJ_ASSERT(str.isFlat());
94 benchmark::DoNotOptimize(str.utf8Length(js));
95 }
96 });
97}
98 
99// Benchmarks utf8Length on 256-char utf16 flat strings
100static void JsString_Utf8Length_Utf16_Flat_256(benchmark::State& state) {
101 TestFixture fixture;
102 fixture.runInIoContext([&](const TestFixture::Environment& env) {
103 auto& js = env.js;
104 auto str = createUtf16String<256>(js);
105 
106 for (auto _: state) {
107 KJ_ASSERT(str.isFlat());
108 benchmark::DoNotOptimize(str.utf8Length(js));
109 }
110 });
111}
112 
113// Benchmarks utf8Length on 1024-char utf16 flat strings
114static void JsString_Utf8Length_Utf16_Flat_1024(benchmark::State& state) {
115 TestFixture fixture;
116 fixture.runInIoContext([&](const TestFixture::Environment& env) {
117 auto& js = env.js;
118 auto str = createUtf16String<1024>(js);
119 
120 for (auto _: state) {
121 KJ_ASSERT(str.isFlat());
122 benchmark::DoNotOptimize(str.utf8Length(js));
123 }
124 });
125}
126 
127// Benchmarks utf8Length on 8192-char utf16 flat strings
128static void JsString_Utf8Length_Utf16_Flat_8192(benchmark::State& state) {
129 TestFixture fixture;
130 fixture.runInIoContext([&](const TestFixture::Environment& env) {
131 auto& js = env.js;
132 auto str = createUtf16String<8192>(js);
133 
134 for (auto _: state) {
135 KJ_ASSERT(str.isFlat());
136 benchmark::DoNotOptimize(str.utf8Length(js));
137 }
138 });
139}
140 
141// Benchmarks utf8Length on 256-char utf16 flat strings with invalid UTF-16
142static void JsString_Utf8Length_Utf16_Invalid_Flat_256(benchmark::State& state) {
143 TestFixture fixture;
144 fixture.runInIoContext([&](const TestFixture::Environment& env) {
145 auto& js = env.js;
146 auto str = createInvalidUtf16String<256>(js);
147 
148 for (auto _: state) {
149 KJ_ASSERT(str.isFlat());
150 benchmark::DoNotOptimize(str.utf8Length(js));
151 }
152 });
153}
154 
155// Benchmarks utf8Length on 1024-char utf16 flat strings with invalid UTF-16
156static void JsString_Utf8Length_Utf16_Invalid_Flat_1024(benchmark::State& state) {
157 TestFixture fixture;
158 fixture.runInIoContext([&](const TestFixture::Environment& env) {
159 auto& js = env.js;
160 auto str = createInvalidUtf16String<1024>(js);
161 
162 for (auto _: state) {
163 KJ_ASSERT(str.isFlat());
164 benchmark::DoNotOptimize(str.utf8Length(js));
165 }
166 });
167}
168 
169// Benchmarks utf8Length on 8192-char utf16 flat strings with invalid UTF-16
170static void JsString_Utf8Length_Utf16_Invalid_Flat_8192(benchmark::State& state) {
171 TestFixture fixture;
172 fixture.runInIoContext([&](const TestFixture::Environment& env) {
173 auto& js = env.js;
174 auto str = createInvalidUtf16String<8192>(js);
175 
176 for (auto _: state) {
177 KJ_ASSERT(str.isFlat());
178 benchmark::DoNotOptimize(str.utf8Length(js));
179 }
180 });
181}
182 
183// Benchmarks utf8Length on 256-char non-flat latin1 strings (deep tree, 8 pieces)
184static void JsString_Utf8Length_Latin1_NonFlat_256(benchmark::State& state) {
185 TestFixture fixture;
186 fixture.runInIoContext([&](const TestFixture::Environment& env) {
187 auto& js = env.js;
188 auto piece = createLatin1String<32>(js);
189 
190 for (auto _: state) {
191 // Build deep tree by concatenating 8 pieces (depth ~7-8)
192 auto result = piece;
193 for (int i = 1; i < 8; i++) {
194 result = jsg::JsString::concat(js, result, piece);
195 }
196 KJ_ASSERT(!result.isFlat());
197 benchmark::DoNotOptimize(result.utf8Length(js));
198 }
199 });
200}
201 
202// Benchmarks utf8Length on 1024-char non-flat latin1 strings (deep tree, 16 pieces)
203static void JsString_Utf8Length_Latin1_NonFlat_1024(benchmark::State& state) {
204 TestFixture fixture;
205 fixture.runInIoContext([&](const TestFixture::Environment& env) {
206 auto& js = env.js;
207 auto piece = createLatin1String<64>(js);
208 
209 for (auto _: state) {
210 // Build deep tree by concatenating 16 pieces (depth ~15-16)
211 auto result = piece;
212 for (int i = 1; i < 16; i++) {
213 result = jsg::JsString::concat(js, result, piece);
214 }
215 KJ_ASSERT(!result.isFlat());
216 benchmark::DoNotOptimize(result.utf8Length(js));
217 }
218 });
219}
220 
221// Benchmarks utf8Length on 8192-char non-flat latin1 strings (deep tree, 32 pieces)
222static void JsString_Utf8Length_Latin1_NonFlat_8192(benchmark::State& state) {
223 TestFixture fixture;
224 fixture.runInIoContext([&](const TestFixture::Environment& env) {
225 auto& js = env.js;
226 auto piece = createLatin1String<256>(js);
227 
228 for (auto _: state) {
229 // Build deep tree by concatenating 32 pieces (depth ~31-32)
230 auto result = piece;
231 for (int i = 1; i < 32; i++) {
232 result = jsg::JsString::concat(js, result, piece);
233 }
234 KJ_ASSERT(!result.isFlat());
235 benchmark::DoNotOptimize(result.utf8Length(js));
236 }
237 });
238}
239 
240// Benchmarks utf8Length on 256-char non-flat utf16 strings (deep tree, 8 pieces)
241static void JsString_Utf8Length_Utf16_NonFlat_256(benchmark::State& state) {
242 TestFixture fixture;
243 fixture.runInIoContext([&](const TestFixture::Environment& env) {
244 auto& js = env.js;
245 auto piece = createUtf16String<32>(js);
246 
247 for (auto _: state) {
248 // Build deep tree by concatenating 8 pieces (depth ~7-8)
249 auto result = piece;
250 for (int i = 1; i < 8; i++) {
251 result = jsg::JsString::concat(js, result, piece);
252 }
253 KJ_ASSERT(!result.isFlat());
254 benchmark::DoNotOptimize(result.utf8Length(js));
255 }
256 });
257}
258 
259// Benchmarks utf8Length on 1024-char non-flat utf16 strings (deep tree, 16 pieces)
260static void JsString_Utf8Length_Utf16_NonFlat_1024(benchmark::State& state) {
261 TestFixture fixture;
262 fixture.runInIoContext([&](const TestFixture::Environment& env) {
263 auto& js = env.js;
264 auto piece = createUtf16String<64>(js);
265 
266 for (auto _: state) {
267 // Build deep tree by concatenating 16 pieces (depth ~15-16)
268 auto result = piece;
269 for (int i = 1; i < 16; i++) {
270 result = jsg::JsString::concat(js, result, piece);
271 }
272 KJ_ASSERT(!result.isFlat());
273 benchmark::DoNotOptimize(result.utf8Length(js));
274 }
275 });
276}
277 
278// Benchmarks utf8Length on 8192-char non-flat utf16 strings (deep tree, 32 pieces)
279static void JsString_Utf8Length_Utf16_NonFlat_8192(benchmark::State& state) {
280 TestFixture fixture;
281 fixture.runInIoContext([&](const TestFixture::Environment& env) {
282 auto& js = env.js;
283 auto piece = createUtf16String<256>(js);
284 
285 for (auto _: state) {
286 // Build deep tree by concatenating 32 pieces (depth ~31-32)
287 auto result = piece;
288 for (int i = 1; i < 32; i++) {
289 result = jsg::JsString::concat(js, result, piece);
290 }
291 KJ_ASSERT(!result.isFlat());
292 benchmark::DoNotOptimize(result.utf8Length(js));
293 }
294 });
295}
296 
297// Benchmarks utf8Length on 256-char non-flat utf16 strings with invalid UTF-16 (deep tree, 8 pieces)
298static void JsString_Utf8Length_Utf16_Invalid_NonFlat_256(benchmark::State& state) {
299 TestFixture fixture;
300 fixture.runInIoContext([&](const TestFixture::Environment& env) {
301 auto& js = env.js;
302 auto piece = createInvalidUtf16String<32>(js);
303 
304 for (auto _: state) {
305 // Build deep tree by concatenating 8 pieces (depth ~7-8)
306 auto result = piece;
307 for (int i = 1; i < 8; i++) {
308 result = jsg::JsString::concat(js, result, piece);
309 }
310 KJ_ASSERT(!result.isFlat());
311 benchmark::DoNotOptimize(result.utf8Length(js));
312 }
313 });
314}
315 
316// Benchmarks utf8Length on 1024-char non-flat utf16 strings with invalid UTF-16 (deep tree, 16 pieces)
317static void JsString_Utf8Length_Utf16_Invalid_NonFlat_1024(benchmark::State& state) {
318 TestFixture fixture;
319 fixture.runInIoContext([&](const TestFixture::Environment& env) {
320 auto& js = env.js;
321 auto piece = createInvalidUtf16String<64>(js);
322 
323 for (auto _: state) {
324 // Build deep tree by concatenating 16 pieces (depth ~15-16)
325 auto result = piece;
326 for (int i = 1; i < 16; i++) {
327 result = jsg::JsString::concat(js, result, piece);
328 }
329 KJ_ASSERT(!result.isFlat());
330 benchmark::DoNotOptimize(result.utf8Length(js));
331 }
332 });
333}
334 
335// Benchmarks utf8Length on 8192-char non-flat utf16 strings with invalid UTF-16 (deep tree, 32 pieces)
336static void JsString_Utf8Length_Utf16_Invalid_NonFlat_8192(benchmark::State& state) {
337 TestFixture fixture;
338 fixture.runInIoContext([&](const TestFixture::Environment& env) {
339 auto& js = env.js;
340 auto piece = createInvalidUtf16String<256>(js);
341 
342 for (auto _: state) {
343 // Build deep tree by concatenating 32 pieces (depth ~31-32)
344 auto result = piece;
345 for (int i = 1; i < 32; i++) {
346 result = jsg::JsString::concat(js, result, piece);
347 }
348 KJ_ASSERT(!result.isFlat());
349 benchmark::DoNotOptimize(result.utf8Length(js));
350 }
351 });
352}
353 
354WD_BENCHMARK(JsString_Utf8Length_Latin1_Flat_32);
355WD_BENCHMARK(JsString_Utf8Length_Latin1_Flat_256);
356WD_BENCHMARK(JsString_Utf8Length_Latin1_Flat_1024);
357WD_BENCHMARK(JsString_Utf8Length_Latin1_Flat_8192);
358WD_BENCHMARK(JsString_Utf8Length_Utf16_Flat_256);
359WD_BENCHMARK(JsString_Utf8Length_Utf16_Flat_1024);
360WD_BENCHMARK(JsString_Utf8Length_Utf16_Flat_8192);
361WD_BENCHMARK(JsString_Utf8Length_Utf16_Invalid_Flat_256);
362WD_BENCHMARK(JsString_Utf8Length_Utf16_Invalid_Flat_1024);
363WD_BENCHMARK(JsString_Utf8Length_Utf16_Invalid_Flat_8192);
364WD_BENCHMARK(JsString_Utf8Length_Latin1_NonFlat_256);
365WD_BENCHMARK(JsString_Utf8Length_Latin1_NonFlat_1024);
366WD_BENCHMARK(JsString_Utf8Length_Latin1_NonFlat_8192);
367WD_BENCHMARK(JsString_Utf8Length_Utf16_NonFlat_256);
368WD_BENCHMARK(JsString_Utf8Length_Utf16_NonFlat_1024);
369WD_BENCHMARK(JsString_Utf8Length_Utf16_NonFlat_8192);
370WD_BENCHMARK(JsString_Utf8Length_Utf16_Invalid_NonFlat_256);
371WD_BENCHMARK(JsString_Utf8Length_Utf16_Invalid_NonFlat_1024);
372WD_BENCHMARK(JsString_Utf8Length_Utf16_Invalid_NonFlat_8192);
373 
374} // namespace
375} // namespace workerd