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 "util.h"
26 
MallocFree(benchmark::State & state)27 static void MallocFree(benchmark::State& state) {
28   const size_t nbytes = state.range(0);
29   int pagesize = getpagesize();
30 
31   for (auto _ : state) {
32     void* ptr;
33     benchmark::DoNotOptimize(ptr = malloc(nbytes));
34     MakeAllocationResident(ptr, nbytes, pagesize);
35     free(ptr);
36   }
37 
38   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
39 }
40 
BM_stdlib_malloc_free_default(benchmark::State & state)41 static void BM_stdlib_malloc_free_default(benchmark::State& state) {
42 #if defined(__BIONIC__)
43   // The default is expected to be a zero decay time.
44   mallopt(M_DECAY_TIME, 0);
45 #endif
46 
47   MallocFree(state);
48 }
49 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_free_default, "AT_COMMON_SIZES");
50 
51 #if defined(__BIONIC__)
BM_stdlib_malloc_free_decay1(benchmark::State & state)52 static void BM_stdlib_malloc_free_decay1(benchmark::State& state) {
53   mallopt(M_DECAY_TIME, 1);
54 
55   MallocFree(state);
56 
57   mallopt(M_DECAY_TIME, 0);
58 }
59 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_free_decay1, "AT_COMMON_SIZES");
60 #endif
61 
CallocFree(benchmark::State & state)62 static void CallocFree(benchmark::State& state) {
63   const size_t nbytes = state.range(0);
64   int pagesize = getpagesize();
65 
66   for (auto _ : state) {
67     void* ptr;
68     benchmark::DoNotOptimize(ptr = calloc(1, nbytes));
69     MakeAllocationResident(ptr, nbytes, pagesize);
70     free(ptr);
71   }
72 
73   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
74 }
75 
BM_stdlib_calloc_free_default(benchmark::State & state)76 static void BM_stdlib_calloc_free_default(benchmark::State& state) {
77 #if defined(__BIONIC__)
78   // The default is expected to be a zero decay time.
79   mallopt(M_DECAY_TIME, 0);
80 #endif
81 
82   CallocFree(state);
83 }
84 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_calloc_free_default, "AT_COMMON_SIZES");
85 
86 #if defined(__BIONIC__)
BM_stdlib_calloc_free_decay1(benchmark::State & state)87 static void BM_stdlib_calloc_free_decay1(benchmark::State& state) {
88   mallopt(M_DECAY_TIME, 1);
89 
90   CallocFree(state);
91 
92   mallopt(M_DECAY_TIME, 0);
93 }
94 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_calloc_free_decay1, "AT_COMMON_SIZES");
95 #endif
96 
MallocMultiple(benchmark::State & state,size_t nbytes,size_t numAllocs)97 static void MallocMultiple(benchmark::State& state, size_t nbytes, size_t numAllocs) {
98   int pagesize = getpagesize();
99   void* ptrs[numAllocs];
100   for (auto _ : state) {
101     for (size_t i = 0; i < numAllocs; i++) {
102       benchmark::DoNotOptimize(ptrs[i] = reinterpret_cast<uint8_t*>(malloc(nbytes)));
103       MakeAllocationResident(ptrs[i], nbytes, pagesize);
104     }
105     state.PauseTiming(); // Stop timers while freeing pointers.
106     for (size_t i = 0; i < numAllocs; i++) {
107       free(ptrs[i]);
108     }
109     state.ResumeTiming();
110   }
111 
112   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes) * numAllocs);
113 }
114 
BM_stdlib_malloc_forty_default(benchmark::State & state)115 void BM_stdlib_malloc_forty_default(benchmark::State& state) {
116 
117 #if defined(__BIONIC__)
118   // The default is expected to be a zero decay time.
119   mallopt(M_DECAY_TIME, 0);
120 #endif
121 
122   MallocMultiple(state, state.range(0), 40);
123 }
124 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_forty_default, "AT_COMMON_SIZES");
125 
126 #if defined(__BIONIC__)
BM_stdlib_malloc_forty_decay1(benchmark::State & state)127 void BM_stdlib_malloc_forty_decay1(benchmark::State& state) {
128   mallopt(M_DECAY_TIME, 1);
129 
130   MallocMultiple(state, state.range(0), 40);
131 
132   mallopt(M_DECAY_TIME, 0);
133 }
134 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_forty_decay1, "AT_COMMON_SIZES");
135 #endif
136 
BM_stdlib_malloc_multiple_8192_allocs_default(benchmark::State & state)137 void BM_stdlib_malloc_multiple_8192_allocs_default(benchmark::State& state) {
138 #if defined(__BIONIC__)
139   // The default is expected to be a zero decay time.
140   mallopt(M_DECAY_TIME, 0);
141 #endif
142 
143   MallocMultiple(state, 8192, state.range(0));
144 }
145 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_multiple_8192_allocs_default, "AT_SMALL_SIZES");
146 
147 #if defined(__BIONIC__)
BM_stdlib_malloc_multiple_8192_allocs_decay1(benchmark::State & state)148 void BM_stdlib_malloc_multiple_8192_allocs_decay1(benchmark::State& state) {
149   mallopt(M_DECAY_TIME, 1);
150 
151   MallocMultiple(state, 8192, state.range(0));
152 
153   mallopt(M_DECAY_TIME, 0);
154 }
155 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_malloc_multiple_8192_allocs_decay1, "AT_SMALL_SIZES");
156 #endif
157 
BM_stdlib_mbstowcs(benchmark::State & state)158 static void BM_stdlib_mbstowcs(benchmark::State& state) {
159   const size_t buf_alignment = state.range(0);
160   const size_t widebuf_alignment = state.range(1);
161 
162   std::vector<char> buf;
163   std::vector<wchar_t> widebuf;
164 
165   setlocale(LC_CTYPE, "C.UTF-8")
166   || setlocale(LC_CTYPE, "en_US.UTF-8")
167   || setlocale(LC_CTYPE, "en_GB.UTF-8")
168   || setlocale(LC_CTYPE, "en.UTF-8")
169   || setlocale(LC_CTYPE, "de_DE-8")
170   || setlocale(LC_CTYPE, "fr_FR-8");
171   if (strcmp(nl_langinfo(CODESET), "UTF-8")) {
172     errx(1, "ERROR: unable to set locale in BM_stdlib_mbstowcs");
173   }
174 
175   char* buf_aligned = GetAlignedPtr(&buf, buf_alignment, 500000);
176   wchar_t* widebuf_aligned = GetAlignedPtr(&widebuf, widebuf_alignment, 500000);
177   size_t i, j, k, l;
178   l = 0;
179   for (i=0xc3; i<0xe0; i++)
180     for (j=0x80; j<0xc0; j++)
181       buf[l++] = i, buf[l++] = j;
182   for (i=0xe1; i<0xed; i++)
183     for (j=0x80; j<0xc0; j++)
184       for (k=0x80; k<0xc0; k++)
185         buf[l++] = i, buf[l++] = j, buf[l++] = k;
186   for (i=0xf1; i<0xf4; i++)
187     for (j=0x80; j<0xc0; j++)
188       for (k=0x80; k<0xc0; k++)
189         buf[l++] = i, buf[l++] = j, buf[l++] = 0x80, buf[l++] = k;
190   buf[l++] = 0;
191 
192   volatile size_t c __attribute__((unused)) = 0;
193   for (auto _ : state) {
194     c = mbstowcs(widebuf_aligned, buf_aligned, 500000);
195   }
196 
197   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(500000));
198 }
199 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_mbstowcs, "0 0");
200 
BM_stdlib_mbrtowc(benchmark::State & state)201 static void BM_stdlib_mbrtowc(benchmark::State& state) {
202   const size_t buf_alignment = state.range(0);
203 
204   std::vector<char> buf;
205 
206   setlocale(LC_CTYPE, "C.UTF-8")
207   || setlocale(LC_CTYPE, "en_US.UTF-8")
208   || setlocale(LC_CTYPE, "en_GB.UTF-8")
209   || setlocale(LC_CTYPE, "en.UTF-8")
210   || setlocale(LC_CTYPE, "de_DE-8")
211   || setlocale(LC_CTYPE, "fr_FR-8");
212   if (strcmp(nl_langinfo(CODESET), "UTF-8")) {
213     errx(1, "ERROR: unable to set locale in BM_stdlib_mbrtowc");
214   }
215 
216   char* buf_aligned = GetAlignedPtr(&buf, buf_alignment, 500000);
217   size_t i, j, k, l;
218   l = 0;
219   for (i=0xc3; i<0xe0; i++)
220     for (j=0x80; j<0xc0; j++)
221       buf[l++] = i, buf[l++] = j;
222   for (i=0xe1; i<0xed; i++)
223     for (j=0x80; j<0xc0; j++)
224       for (k=0x80; k<0xc0; k++)
225         buf[l++] = i, buf[l++] = j, buf[l++] = k;
226   for (i=0xf1; i<0xf4; i++)
227     for (j=0x80; j<0xc0; j++)
228       for (k=0x80; k<0xc0; k++)
229         buf[l++] = i, buf[l++] = j, buf[l++] = 0x80, buf[l++] = k;
230   buf[l++] = 0;
231 
232   wchar_t wc = 0;
233   for (auto _ : state) {
234     for (j = 0; buf_aligned[j]; j+=mbrtowc(&wc, buf_aligned + j, 4, nullptr)) {
235     }
236   }
237 
238   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(500000));
239 }
240 BIONIC_BENCHMARK_WITH_ARG(BM_stdlib_mbrtowc, "0");
241 
242 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_atoi, atoi(" -123"));
243 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_atol, atol(" -123"));
244 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_strtol, strtol(" -123", nullptr, 0));
245 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_strtoll, strtoll(" -123", nullptr, 0));
246 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_strtoul, strtoul(" -123", nullptr, 0));
247 BIONIC_TRIVIAL_BENCHMARK(BM_stdlib_strtoull, strtoull(" -123", nullptr, 0));
248