1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <err.h>
18 #include <stdint.h>
19 #include <string.h>
20
21 #include <benchmark/benchmark.h>
22 #include <util.h>
23
BM_string_memcmp(benchmark::State & state)24 static void BM_string_memcmp(benchmark::State& state) {
25 const size_t nbytes = state.range(0);
26 const size_t src_alignment = state.range(1);
27 const size_t dst_alignment = state.range(2);
28
29 std::vector<char> src;
30 std::vector<char> dst;
31 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
32 char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'x');
33
34 while (state.KeepRunning()) {
35 benchmark::DoNotOptimize(memcmp(dst_aligned, src_aligned, nbytes));
36 }
37
38 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
39 }
40 BIONIC_BENCHMARK_WITH_ARG(BM_string_memcmp, "AT_ALIGNED_TWOBUF");
41
BM_string_memcpy(benchmark::State & state)42 static void BM_string_memcpy(benchmark::State& state) {
43 const size_t nbytes = state.range(0);
44 const size_t src_alignment = state.range(1);
45 const size_t dst_alignment = state.range(2);
46
47 std::vector<char> src;
48 std::vector<char> dst;
49 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
50 char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes);
51
52 while (state.KeepRunning()) {
53 memcpy(dst_aligned, src_aligned, nbytes);
54 }
55
56 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
57 }
58 BIONIC_BENCHMARK_WITH_ARG(BM_string_memcpy, "AT_ALIGNED_TWOBUF");
59
BM_string_memmove_non_overlapping(benchmark::State & state)60 static void BM_string_memmove_non_overlapping(benchmark::State& state) {
61 const size_t nbytes = state.range(0);
62 const size_t src_alignment = state.range(1);
63 const size_t dst_alignment = state.range(2);
64
65 std::vector<char> src;
66 std::vector<char> dst;
67 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
68 char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'y');
69
70 while (state.KeepRunning()) {
71 memmove(dst_aligned, src_aligned, nbytes);
72 }
73
74 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
75 }
76 BIONIC_BENCHMARK_WITH_ARG(BM_string_memmove_non_overlapping, "AT_ALIGNED_TWOBUF");
77
BM_string_memmove_overlap_dst_before_src(benchmark::State & state)78 static void BM_string_memmove_overlap_dst_before_src(benchmark::State& state) {
79 const size_t nbytes = state.range(0);
80 const size_t alignment = state.range(1);
81
82 std::vector<char> buf(3 * alignment + nbytes + 1, 'x');
83 char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
84
85 while (state.KeepRunning()) {
86 memmove(buf_aligned, buf_aligned + 1, nbytes); // Worst-case overlap.
87 }
88
89 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
90 }
91 BIONIC_BENCHMARK_WITH_ARG(BM_string_memmove_overlap_dst_before_src, "AT_ALIGNED_ONEBUF");
92
BM_string_memmove_overlap_src_before_dst(benchmark::State & state)93 static void BM_string_memmove_overlap_src_before_dst(benchmark::State& state) {
94 const size_t nbytes = state.range(0);
95 const size_t alignment = state.range(1);
96
97 std::vector<char> buf;
98 char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
99
100 while (state.KeepRunning()) {
101 memmove(buf_aligned + 1, buf_aligned, nbytes); // Worst-case overlap.
102 }
103
104 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
105 }
106 BIONIC_BENCHMARK_WITH_ARG(BM_string_memmove_overlap_src_before_dst, "AT_ALIGNED_ONEBUF");
107
BM_string_memset(benchmark::State & state)108 static void BM_string_memset(benchmark::State& state) {
109 const size_t nbytes = state.range(0);
110 const size_t alignment = state.range(1);
111
112 std::vector<char> buf;
113 char* buf_aligned = GetAlignedPtr(&buf, alignment, nbytes + 1);
114
115 while (state.KeepRunning()) {
116 memset(buf_aligned, 0, nbytes);
117 }
118
119 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
120 }
121 BIONIC_BENCHMARK_WITH_ARG(BM_string_memset, "AT_ALIGNED_ONEBUF");
122
BM_string_strlen(benchmark::State & state)123 static void BM_string_strlen(benchmark::State& state) {
124 const size_t nbytes = state.range(0);
125 const size_t alignment = state.range(1);
126
127 std::vector<char> buf;
128 char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
129 buf_aligned[nbytes - 1] = '\0';
130
131 while (state.KeepRunning()) {
132 benchmark::DoNotOptimize(strlen(buf_aligned));
133 }
134
135 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
136 }
137 BIONIC_BENCHMARK_WITH_ARG(BM_string_strlen, "AT_ALIGNED_ONEBUF");
138
BM_string_strcat_copy_only(benchmark::State & state)139 static void BM_string_strcat_copy_only(benchmark::State& state) {
140 const size_t nbytes = state.range(0);
141 const size_t src_alignment = state.range(1);
142 const size_t dst_alignment = state.range(2);
143
144 std::vector<char> src;
145 std::vector<char> dst;
146 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
147 char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes + 2);
148 src_aligned[nbytes - 1] = '\0';
149 dst_aligned[0] = 'y';
150 dst_aligned[1] = 'y';
151 dst_aligned[2] = '\0';
152
153 while (state.KeepRunning()) {
154 strcat(dst_aligned, src_aligned);
155 dst_aligned[2] = '\0';
156 }
157
158 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
159 }
160 BIONIC_BENCHMARK_WITH_ARG(BM_string_strcat_copy_only, "AT_ALIGNED_TWOBUF");
161
BM_string_strcat_seek_only(benchmark::State & state)162 static void BM_string_strcat_seek_only(benchmark::State& state) {
163 const size_t nbytes = state.range(0);
164 const size_t src_alignment = state.range(1);
165 const size_t dst_alignment = state.range(2);
166
167 std::vector<char> src;
168 std::vector<char> dst;
169 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, 3, 'x');
170 char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes + 2, 'y');
171 src_aligned[2] = '\0';
172 dst_aligned[nbytes - 1] = '\0';
173
174 while (state.KeepRunning()) {
175 strcat(dst_aligned, src_aligned);
176 dst_aligned[nbytes - 1] = '\0';
177 }
178
179 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
180 }
181 BIONIC_BENCHMARK_WITH_ARG(BM_string_strcat_seek_only, "AT_ALIGNED_TWOBUF");
182
BM_string_strcat_half_copy_half_seek(benchmark::State & state)183 static void BM_string_strcat_half_copy_half_seek(benchmark::State& state) {
184 const size_t nbytes = state.range(0);
185 const size_t src_alignment = state.range(1);
186 const size_t dst_alignment = state.range(2);
187
188 // Skip sizes that don't make sense.
189 if ((nbytes / 2) == 0) {
190 return;
191 }
192
193 std::vector<char> src;
194 std::vector<char> dst;
195 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes / 2, 'x');
196 char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'y');
197 src_aligned[nbytes / 2 - 1] = '\0';
198 dst_aligned[nbytes / 2 - 1] = '\0';
199
200 while (state.KeepRunning()) {
201 strcat(dst_aligned, src_aligned);
202 dst_aligned[nbytes / 2 - 1] = '\0';
203 }
204
205 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
206 }
207 BIONIC_BENCHMARK_WITH_ARG(BM_string_strcat_half_copy_half_seek, "AT_ALIGNED_TWOBUF");
208
BM_string_strcpy(benchmark::State & state)209 static void BM_string_strcpy(benchmark::State& state) {
210 const size_t nbytes = state.range(0);
211 const size_t src_alignment = state.range(1);
212 const size_t dst_alignment = state.range(2);
213
214 std::vector<char> src;
215 std::vector<char> dst;
216 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
217 char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes);
218 src_aligned[nbytes - 1] = '\0';
219
220 while (state.KeepRunning()) {
221 strcpy(dst_aligned, src_aligned);
222 }
223
224 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
225 }
226 BIONIC_BENCHMARK_WITH_ARG(BM_string_strcpy, "AT_ALIGNED_TWOBUF");
227
BM_string_strcmp(benchmark::State & state)228 static void BM_string_strcmp(benchmark::State& state) {
229 const size_t nbytes = state.range(0);
230 const size_t s1_alignment = state.range(1);
231 const size_t s2_alignment = state.range(2);
232
233 std::vector<char> s1;
234 std::vector<char> s2;
235 char* s1_aligned = GetAlignedPtrFilled(&s1, s1_alignment, nbytes, 'x');
236 char* s2_aligned = GetAlignedPtrFilled(&s2, s2_alignment, nbytes, 'x');
237 s1_aligned[nbytes - 1] = '\0';
238 s2_aligned[nbytes - 1] = '\0';
239
240 while (state.KeepRunning()) {
241 benchmark::DoNotOptimize(strcmp(s1_aligned, s2_aligned));
242 }
243
244 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
245 }
246 BIONIC_BENCHMARK_WITH_ARG(BM_string_strcmp, "AT_ALIGNED_TWOBUF");
247
BM_string_strncmp(benchmark::State & state)248 static void BM_string_strncmp(benchmark::State& state) {
249 const size_t nbytes = state.range(0);
250 const size_t s1_alignment = state.range(1);
251 const size_t s2_alignment = state.range(2);
252
253 std::vector<char> s1;
254 std::vector<char> s2;
255 char* s1_aligned = GetAlignedPtrFilled(&s1, s1_alignment, nbytes, 'x');
256 char* s2_aligned = GetAlignedPtrFilled(&s2, s2_alignment, nbytes, 'x');
257
258 for (auto _ : state) {
259 benchmark::DoNotOptimize(strncmp(s1_aligned, s2_aligned, nbytes));
260 }
261
262 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
263 }
264 BIONIC_BENCHMARK_WITH_ARG(BM_string_strncmp, "AT_ALIGNED_TWOBUF");
265
BM_string_strstr(benchmark::State & state)266 static void BM_string_strstr(benchmark::State& state) {
267 const size_t nbytes = state.range(0);
268 const size_t haystack_alignment = state.range(1);
269 const size_t needle_alignment = state.range(2);
270
271 std::vector<char> haystack;
272 std::vector<char> needle;
273 char* haystack_aligned = GetAlignedPtrFilled(&haystack, haystack_alignment, nbytes, 'x');
274 char* needle_aligned = GetAlignedPtrFilled(&needle, needle_alignment,
275 std::min(nbytes, static_cast<size_t>(5)), 'x');
276
277 if (nbytes / 4 > 2) {
278 for (size_t i = 0; nbytes / 4 >= 2 && i < nbytes / 4 - 2; i++) {
279 haystack_aligned[4 * i + 3] = 'y';
280 }
281 }
282 haystack_aligned[nbytes - 1] = '\0';
283 needle_aligned[needle.size() - 1] = '\0';
284
285 while (state.KeepRunning()) {
286 if (strstr(haystack_aligned, needle_aligned) == nullptr) {
287 errx(1, "ERROR: strstr failed to find valid substring.");
288 }
289 }
290
291 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
292 }
293 BIONIC_BENCHMARK_WITH_ARG(BM_string_strstr, "AT_ALIGNED_TWOBUF");
294
BM_string_strchr(benchmark::State & state)295 static void BM_string_strchr(benchmark::State& state) {
296 const size_t nbytes = state.range(0);
297 const size_t haystack_alignment = state.range(1);
298
299 std::vector<char> haystack;
300 char* haystack_aligned = GetAlignedPtrFilled(&haystack, haystack_alignment, nbytes, 'x');
301 haystack_aligned[nbytes-1] = '\0';
302
303 while (state.KeepRunning()) {
304 if (strchr(haystack_aligned, 'y') != nullptr) {
305 errx(1, "ERROR: strchr found a chr where it should have failed.");
306 }
307 }
308
309 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
310 }
311 BIONIC_BENCHMARK_WITH_ARG(BM_string_strchr, "AT_ALIGNED_ONEBUF");
312