1 /*
2  * Copyright (C) 2017 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 <langinfo.h>
19 #include <locale.h>
20 #include <malloc.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 
24 #include <benchmark/benchmark.h>
25 #include "ScopedDecayTimeRestorer.h"
26 #include "util.h"
27 
MallocFree(benchmark::State & state)28 static void MallocFree(benchmark::State& state) {
29   const size_t nbytes = state.range(0);
30   int pagesize = getpagesize();
31 
32   for (auto _ : state) {
33     void* ptr;
34     benchmark::DoNotOptimize(ptr = malloc(nbytes));
35     MakeAllocationResident(ptr, nbytes, pagesize);
36     free(ptr);
37   }
38 
39   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
40 }
41 
BM_stdlib_malloc_free_default(benchmark::State & state)42 static void BM_stdlib_malloc_free_default(benchmark::State& state) {
43 #if defined(__BIONIC__)
44   ScopedDecayTimeRestorer restorer;
45 
46   // The default is expected to be a zero decay time.
47   mallopt(M_DECAY_TIME, 0);
48 #endif
49 
50   MallocFree(state);
51 }
52 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_free_default, "AT_COMMON_SIZES");
53 
54 #if defined(__BIONIC__)
BM_stdlib_malloc_free_decay1(benchmark::State & state)55 static void BM_stdlib_malloc_free_decay1(benchmark::State& state) {
56   ScopedDecayTimeRestorer restorer;
57 
58   mallopt(M_DECAY_TIME, 1);
59 
60   MallocFree(state);
61 }
62 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_free_decay1, "AT_COMMON_SIZES");
63 #endif
64 
CallocFree(benchmark::State & state)65 static void CallocFree(benchmark::State& state) {
66   const size_t nbytes = state.range(0);
67   int pagesize = getpagesize();
68 
69   for (auto _ : state) {
70     void* ptr;
71     benchmark::DoNotOptimize(ptr = calloc(1, nbytes));
72     MakeAllocationResident(ptr, nbytes, pagesize);
73     free(ptr);
74   }
75 
76   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
77 }
78 
BM_stdlib_calloc_free_default(benchmark::State & state)79 static void BM_stdlib_calloc_free_default(benchmark::State& state) {
80 #if defined(__BIONIC__)
81   ScopedDecayTimeRestorer restorer;
82 
83   // The default is expected to be a zero decay time.
84   mallopt(M_DECAY_TIME, 0);
85 #endif
86 
87   CallocFree(state);
88 }
89 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_calloc_free_default, "AT_COMMON_SIZES");
90 
91 #if defined(__BIONIC__)
BM_stdlib_calloc_free_decay1(benchmark::State & state)92 static void BM_stdlib_calloc_free_decay1(benchmark::State& state) {
93   mallopt(M_DECAY_TIME, 1);
94 
95   CallocFree(state);
96 
97   mallopt(M_DECAY_TIME, 0);
98 }
99 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_calloc_free_decay1, "AT_COMMON_SIZES");
100 #endif
101 
MallocMultiple(benchmark::State & state,size_t nbytes,size_t numAllocs)102 static void MallocMultiple(benchmark::State& state, size_t nbytes, size_t numAllocs) {
103   int pagesize = getpagesize();
104   void* ptrs[numAllocs];
105   for (auto _ : state) {
106     for (size_t i = 0; i < numAllocs; i++) {
107       benchmark::DoNotOptimize(ptrs[i] = reinterpret_cast<uint8_t*>(malloc(nbytes)));
108       MakeAllocationResident(ptrs[i], nbytes, pagesize);
109     }
110     state.PauseTiming(); // Stop timers while freeing pointers.
111     for (size_t i = 0; i < numAllocs; i++) {
112       free(ptrs[i]);
113     }
114     state.ResumeTiming();
115   }
116 
117   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes) * numAllocs);
118 }
119 
BM_stdlib_malloc_forty_default(benchmark::State & state)120 void BM_stdlib_malloc_forty_default(benchmark::State& state) {
121 #if defined(__BIONIC__)
122   ScopedDecayTimeRestorer restorer;
123 
124   // The default is expected to be a zero decay time.
125   mallopt(M_DECAY_TIME, 0);
126 #endif
127 
128   MallocMultiple(state, state.range(0), 40);
129 }
130 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_forty_default, "AT_COMMON_SIZES");
131 
132 #if defined(__BIONIC__)
BM_stdlib_malloc_forty_decay1(benchmark::State & state)133 void BM_stdlib_malloc_forty_decay1(benchmark::State& state) {
134   ScopedDecayTimeRestorer restorer;
135 
136   mallopt(M_DECAY_TIME, 1);
137 
138   MallocMultiple(state, state.range(0), 40);
139 }
140 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_forty_decay1, "AT_COMMON_SIZES");
141 #endif
142 
BM_stdlib_malloc_multiple_8192_allocs_default(benchmark::State & state)143 void BM_stdlib_malloc_multiple_8192_allocs_default(benchmark::State& state) {
144 #if defined(__BIONIC__)
145   ScopedDecayTimeRestorer restorer;
146 
147   // The default is expected to be a zero decay time.
148   mallopt(M_DECAY_TIME, 0);
149 #endif
150 
151   MallocMultiple(state, 8192, state.range(0));
152 }
153 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_multiple_8192_allocs_default, "AT_SMALL_SIZES");
154 
155 #if defined(__BIONIC__)
BM_stdlib_malloc_multiple_8192_allocs_decay1(benchmark::State & state)156 void BM_stdlib_malloc_multiple_8192_allocs_decay1(benchmark::State& state) {
157   ScopedDecayTimeRestorer restorer;
158 
159   mallopt(M_DECAY_TIME, 1);
160 
161   MallocMultiple(state, 8192, state.range(0));
162 }
163 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_multiple_8192_allocs_decay1, "AT_SMALL_SIZES");
164 #endif
165 
BM_stdlib_mbstowcs_ascii(benchmark::State & state)166 static void BM_stdlib_mbstowcs_ascii(benchmark::State& state) {
167   // It doesn't really matter what ASCII character we pick.
168   // The flow through the fast path is the same regardless.
169   const size_t count = 500000;
170   std::vector<char> mbs(count, 'e');
171   std::vector<wchar_t> wcs(count);
172 
173   for (auto _ : state) {
174     benchmark::DoNotOptimize(mbstowcs(&wcs[0], &mbs[0], wcs.size()));
175   }
176 
177   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(wcs.size()));
178 }
179 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_mbstowcs_ascii, "");
180 
BM_stdlib_mbstowcs_wide(benchmark::State & state)181 static void BM_stdlib_mbstowcs_wide(benchmark::State& state) {
182   // It doesn't matter much what wide character we pick.
183   // A three-byte character seems pretty representative, and all three byte
184   // characters are the same from the code's perspective.
185   const size_t count = 500000;
186   std::string mbs;
187   for (size_t i = 0; i < count; i++) {
188     mbs += "\xe5\xb1\xb1";
189   }
190   std::vector<wchar_t> wcs(count);
191 
192   for (auto _ : state) {
193     benchmark::DoNotOptimize(mbstowcs(&wcs[0], &mbs[0], wcs.size()));
194   }
195 
196   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(wcs.size()));
197 }
198 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_mbstowcs_wide, "");
199 
BM_stdlib_mbrtowc_1(benchmark::State & state)200 static void BM_stdlib_mbrtowc_1(benchmark::State& state) {
201   wchar_t wc;
202   for (auto _ : state) {
203     benchmark::DoNotOptimize(mbrtowc(&wc, "e", 1, nullptr));
204   }
205 }
206 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_mbrtowc_1, "");
207 
BM_stdlib_mbrtowc_2(benchmark::State & state)208 static void BM_stdlib_mbrtowc_2(benchmark::State& state) {
209   wchar_t wc;
210   for (auto _ : state) {
211     benchmark::DoNotOptimize(mbrtowc(&wc, "\xc3\x9f", 3, nullptr));
212   }
213 }
214 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_mbrtowc_2, "");
215 
BM_stdlib_mbrtowc_3(benchmark::State & state)216 static void BM_stdlib_mbrtowc_3(benchmark::State& state) {
217   wchar_t wc;
218   for (auto _ : state) {
219     benchmark::DoNotOptimize(mbrtowc(&wc, "\xe5\xb1\xb1", 3, nullptr));
220   }
221 }
222 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_mbrtowc_3, "");
223 
BM_stdlib_mbrtowc_4(benchmark::State & state)224 static void BM_stdlib_mbrtowc_4(benchmark::State& state) {
225   wchar_t wc;
226   for (auto _ : state) {
227     benchmark::DoNotOptimize(mbrtowc(&wc, "\xf0\xa4\xad\xa2", 4, nullptr));
228   }
229 }
230 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_mbrtowc_4, "");
231 
232 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_atoi, atoi(" -123"));
233 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_atol, atol(" -123"));
234 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_strtol, strtol(" -123", nullptr, 0));
235 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_strtoll, strtoll(" -123", nullptr, 0));
236 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_strtoul, strtoul(" -123", nullptr, 0));
237 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_strtoull, strtoull(" -123", nullptr, 0));
238 
239 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_strtol_hex, strtol("0xdeadbeef", nullptr, 0));
240 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_strtoul_hex, strtoul("0xdeadbeef", nullptr, 0));
241