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 volatile int c __attribute__((unused)) = 0;
35 while (state.KeepRunning()) {
36 c += memcmp(dst_aligned, src_aligned, nbytes);
37 }
38
39 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
40 }
41 BIONIC_BENCHMARK_WITH_ARG(BM_string_memcmp, "AT_ALIGNED_TWOBUF");
42
BM_string_memcpy(benchmark::State & state)43 static void BM_string_memcpy(benchmark::State& state) {
44 const size_t nbytes = state.range(0);
45 const size_t src_alignment = state.range(1);
46 const size_t dst_alignment = state.range(2);
47
48 std::vector<char> src;
49 std::vector<char> dst;
50 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
51 char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes);
52
53 while (state.KeepRunning()) {
54 memcpy(dst_aligned, src_aligned, nbytes);
55 }
56
57 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
58 }
59 BIONIC_BENCHMARK_WITH_ARG(BM_string_memcpy, "AT_ALIGNED_TWOBUF");
60
BM_string_memmove_non_overlapping(benchmark::State & state)61 static void BM_string_memmove_non_overlapping(benchmark::State& state) {
62 const size_t nbytes = state.range(0);
63 const size_t src_alignment = state.range(1);
64 const size_t dst_alignment = state.range(2);
65
66 std::vector<char> src;
67 std::vector<char> dst;
68 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
69 char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'y');
70
71 while (state.KeepRunning()) {
72 memmove(dst_aligned, src_aligned, nbytes);
73 }
74
75 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
76 }
77 BIONIC_BENCHMARK_WITH_ARG(BM_string_memmove_non_overlapping, "AT_ALIGNED_TWOBUF");
78
BM_string_memmove_overlap_dst_before_src(benchmark::State & state)79 static void BM_string_memmove_overlap_dst_before_src(benchmark::State& state) {
80 const size_t nbytes = state.range(0);
81 const size_t alignment = state.range(1);
82
83 std::vector<char> buf(3 * alignment + nbytes + 1, 'x');
84 char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
85
86 while (state.KeepRunning()) {
87 memmove(buf_aligned, buf_aligned + 1, nbytes); // Worst-case overlap.
88 }
89
90 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
91 }
92 BIONIC_BENCHMARK_WITH_ARG(BM_string_memmove_overlap_dst_before_src, "AT_ALIGNED_ONEBUF");
93
BM_string_memmove_overlap_src_before_dst(benchmark::State & state)94 static void BM_string_memmove_overlap_src_before_dst(benchmark::State& state) {
95 const size_t nbytes = state.range(0);
96 const size_t alignment = state.range(1);
97
98 std::vector<char> buf;
99 char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
100
101 while (state.KeepRunning()) {
102 memmove(buf_aligned + 1, buf_aligned, nbytes); // Worst-case overlap.
103 }
104
105 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
106 }
107 BIONIC_BENCHMARK_WITH_ARG(BM_string_memmove_overlap_src_before_dst, "AT_ALIGNED_ONEBUF");
108
BM_string_memset(benchmark::State & state)109 static void BM_string_memset(benchmark::State& state) {
110 const size_t nbytes = state.range(0);
111 const size_t alignment = state.range(1);
112
113 std::vector<char> buf;
114 char* buf_aligned = GetAlignedPtr(&buf, alignment, nbytes + 1);
115
116 while (state.KeepRunning()) {
117 memset(buf_aligned, 0, nbytes);
118 }
119
120 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
121 }
122 BIONIC_BENCHMARK_WITH_ARG(BM_string_memset, "AT_ALIGNED_ONEBUF");
123
BM_string_strlen(benchmark::State & state)124 static void BM_string_strlen(benchmark::State& state) {
125 const size_t nbytes = state.range(0);
126 const size_t alignment = state.range(1);
127
128 std::vector<char> buf;
129 char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
130 buf_aligned[nbytes - 1] = '\0';
131
132 volatile int c __attribute__((unused)) = 0;
133 while (state.KeepRunning()) {
134 c += strlen(buf_aligned);
135 }
136
137 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
138 }
139 BIONIC_BENCHMARK_WITH_ARG(BM_string_strlen, "AT_ALIGNED_ONEBUF");
140
BM_string_strcat_copy_only(benchmark::State & state)141 static void BM_string_strcat_copy_only(benchmark::State& state) {
142 const size_t nbytes = state.range(0);
143 const size_t src_alignment = state.range(1);
144 const size_t dst_alignment = state.range(2);
145
146 std::vector<char> src;
147 std::vector<char> dst;
148 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
149 char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes + 2);
150 src_aligned[nbytes - 1] = '\0';
151 dst_aligned[0] = 'y';
152 dst_aligned[1] = 'y';
153 dst_aligned[2] = '\0';
154
155 while (state.KeepRunning()) {
156 strcat(dst_aligned, src_aligned);
157 dst_aligned[2] = '\0';
158 }
159
160 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
161 }
162 BIONIC_BENCHMARK_WITH_ARG(BM_string_strcat_copy_only, "AT_ALIGNED_TWOBUF");
163
BM_string_strcat_seek_only(benchmark::State & state)164 static void BM_string_strcat_seek_only(benchmark::State& state) {
165 const size_t nbytes = state.range(0);
166 const size_t src_alignment = state.range(1);
167 const size_t dst_alignment = state.range(2);
168
169 std::vector<char> src;
170 std::vector<char> dst;
171 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, 3, 'x');
172 char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes + 2, 'y');
173 src_aligned[2] = '\0';
174 dst_aligned[nbytes - 1] = '\0';
175
176 while (state.KeepRunning()) {
177 strcat(dst_aligned, src_aligned);
178 dst_aligned[nbytes - 1] = '\0';
179 }
180
181 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
182 }
183 BIONIC_BENCHMARK_WITH_ARG(BM_string_strcat_seek_only, "AT_ALIGNED_TWOBUF");
184
BM_string_strcat_half_copy_half_seek(benchmark::State & state)185 static void BM_string_strcat_half_copy_half_seek(benchmark::State& state) {
186 const size_t nbytes = state.range(0);
187 const size_t src_alignment = state.range(1);
188 const size_t dst_alignment = state.range(2);
189
190 // Skip sizes that don't make sense.
191 if ((nbytes / 2) == 0) {
192 return;
193 }
194
195 std::vector<char> src;
196 std::vector<char> dst;
197 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes / 2, 'x');
198 char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'y');
199 src_aligned[nbytes / 2 - 1] = '\0';
200 dst_aligned[nbytes / 2 - 1] = '\0';
201
202 while (state.KeepRunning()) {
203 strcat(dst_aligned, src_aligned);
204 dst_aligned[nbytes / 2 - 1] = '\0';
205 }
206
207 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
208 }
209 BIONIC_BENCHMARK_WITH_ARG(BM_string_strcat_half_copy_half_seek, "AT_ALIGNED_TWOBUF");
210
BM_string_strcpy(benchmark::State & state)211 static void BM_string_strcpy(benchmark::State& state) {
212 const size_t nbytes = state.range(0);
213 const size_t src_alignment = state.range(1);
214 const size_t dst_alignment = state.range(2);
215
216 std::vector<char> src;
217 std::vector<char> dst;
218 char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
219 char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes);
220 src_aligned[nbytes - 1] = '\0';
221
222 while (state.KeepRunning()) {
223 strcpy(dst_aligned, src_aligned);
224 }
225
226 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
227 }
228 BIONIC_BENCHMARK_WITH_ARG(BM_string_strcpy, "AT_ALIGNED_TWOBUF");
229
BM_string_strcmp(benchmark::State & state)230 static void BM_string_strcmp(benchmark::State& state) {
231 const size_t nbytes = state.range(0);
232 const size_t s1_alignment = state.range(1);
233 const size_t s2_alignment = state.range(2);
234
235 std::vector<char> s1;
236 std::vector<char> s2;
237 char* s1_aligned = GetAlignedPtrFilled(&s1, s1_alignment, nbytes, 'x');
238 char* s2_aligned = GetAlignedPtrFilled(&s2, s2_alignment, nbytes, 'x');
239 s1_aligned[nbytes - 1] = '\0';
240 s2_aligned[nbytes - 1] = '\0';
241
242 volatile int c __attribute__((unused));
243 while (state.KeepRunning()) {
244 c = strcmp(s1_aligned, s2_aligned);
245 }
246
247 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
248 }
249 BIONIC_BENCHMARK_WITH_ARG(BM_string_strcmp, "AT_ALIGNED_TWOBUF");
250
BM_string_strncmp(benchmark::State & state)251 static void BM_string_strncmp(benchmark::State& state) {
252 const size_t nbytes = state.range(0);
253 const size_t s1_alignment = state.range(1);
254 const size_t s2_alignment = state.range(2);
255
256 std::vector<char> s1;
257 std::vector<char> s2;
258 char* s1_aligned = GetAlignedPtrFilled(&s1, s1_alignment, nbytes, 'x');
259 char* s2_aligned = GetAlignedPtrFilled(&s2, s2_alignment, nbytes, 'x');
260
261 volatile int c __attribute__((unused));
262 for (auto _ : state) {
263 c = strncmp(s1_aligned, s2_aligned, nbytes);
264 }
265
266 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
267 }
268 BIONIC_BENCHMARK_WITH_ARG(BM_string_strncmp, "AT_ALIGNED_TWOBUF");
269
BM_string_strstr(benchmark::State & state)270 static void BM_string_strstr(benchmark::State& state) {
271 const size_t nbytes = state.range(0);
272 const size_t haystack_alignment = state.range(1);
273 const size_t needle_alignment = state.range(2);
274
275 std::vector<char> haystack;
276 std::vector<char> needle;
277 char* haystack_aligned = GetAlignedPtrFilled(&haystack, haystack_alignment, nbytes, 'x');
278 char* needle_aligned = GetAlignedPtrFilled(&needle, needle_alignment,
279 std::min(nbytes, static_cast<size_t>(5)), 'x');
280
281 if (nbytes / 4 > 2) {
282 for (size_t i = 0; nbytes / 4 >= 2 && i < nbytes / 4 - 2; i++) {
283 haystack_aligned[4 * i + 3] = 'y';
284 }
285 }
286 haystack_aligned[nbytes - 1] = '\0';
287 needle_aligned[needle.size() - 1] = '\0';
288
289 while (state.KeepRunning()) {
290 if (strstr(haystack_aligned, needle_aligned) == nullptr) {
291 errx(1, "ERROR: strstr failed to find valid substring.");
292 }
293 }
294
295 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
296 }
297 BIONIC_BENCHMARK_WITH_ARG(BM_string_strstr, "AT_ALIGNED_TWOBUF");
298
BM_string_strchr(benchmark::State & state)299 static void BM_string_strchr(benchmark::State& state) {
300 const size_t nbytes = state.range(0);
301 const size_t haystack_alignment = state.range(1);
302
303 std::vector<char> haystack;
304 char* haystack_aligned = GetAlignedPtrFilled(&haystack, haystack_alignment, nbytes, 'x');
305 haystack_aligned[nbytes-1] = '\0';
306
307 while (state.KeepRunning()) {
308 if (strchr(haystack_aligned, 'y') != nullptr) {
309 errx(1, "ERROR: strchr found a chr where it should have failed.");
310 }
311 }
312
313 state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
314 }
315 BIONIC_BENCHMARK_WITH_ARG(BM_string_strchr, "AT_ALIGNED_ONEBUF");
316