1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2023. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "sys/types.h"
17 #include "sys/stat.h"
18 #include "fcntl.h"
19 #include "sys/mman.h"
20 #include "unistd.h"
21 #include "cstdio"
22 #if defined __APPLE__
23 #include <malloc/malloc.h>
24 #else
25 #include "malloc.h"
26 #endif
27 #include "util.h"
28
29 using namespace std;
30
31 static const vector<int> mmapFlags = {
32 MAP_PRIVATE | MAP_ANONYMOUS,
33 #if not defined __APPLE__
34 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
35 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGE_2MB,
36 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGE_1GB,
37 MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE,
38 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE,
39 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGE_2MB | MAP_POPULATE,
40 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGE_1GB | MAP_POPULATE,
41 #endif
42 };
43
44 static const vector<int> msyncFlags = {
45 MS_ASYNC,
46 MS_SYNC,
47 MS_INVALIDATE,
48 };
49
50 static const vector<int> mmapLength {
51 8,
52 16,
53 64,
54 1 * K,
55 4 * K,
56 64 * K,
57 256 * K,
58 1 * M,
59 4 * M,
60 64 * M,
61 256 * M,
62 1 * G,
63 };
64
65 static const vector<int> mdviseType {
66 MADV_NORMAL,
67 MADV_RANDOM,
68 MADV_SEQUENTIAL,
69 MADV_WILLNEED,
70 MADV_DONTNEED,
71 MADV_FREE,
72 #if not defined __APPLE__
73 MADV_REMOVE,
74 MADV_HUGEPAGE,
75 MADV_SOFT_OFFLINE
76 #endif
77 };
78
79 static const vector<int> mprotectLength {
80 1,
81 2,
82 4,
83 32,
84 1 * K,
85 4 * K,
86 32 * K,
87 1 * M,
88 };
89
PrepareArgs(benchmark::internal::Benchmark * b)90 static void PrepareArgs(benchmark::internal::Benchmark* b)
91 {
92 for (auto l : mmapLength) {
93 for (auto f : mmapFlags) {
94 b->Args({l, f});
95 }
96 }
97 }
98
PrepareArgsInMdvise(benchmark::internal::Benchmark * b)99 static void PrepareArgsInMdvise(benchmark::internal::Benchmark* b)
100 {
101 for (auto l : mmapLength) {
102 for (auto t : mdviseType) {
103 b->Args({l, t});
104 }
105 }
106 }
107
PrepareArgsInMremap(benchmark::internal::Benchmark * b)108 static void PrepareArgsInMremap(benchmark::internal::Benchmark* b)
109 {
110 for (auto oldLength : mmapLength) {
111 for (auto newLength : mmapLength) {
112 b->Args({oldLength, newLength});
113 }
114 }
115 }
116
PrepareArgsInMsync(benchmark::internal::Benchmark * b)117 static void PrepareArgsInMsync(benchmark::internal::Benchmark* b)
118 {
119 for (auto l : mmapLength) {
120 for (auto f : msyncFlags) {
121 b->Args({l, f});
122 }
123 }
124 }
125
Bm_function_Mmap_anonymous(benchmark::State & state)126 static void Bm_function_Mmap_anonymous(benchmark::State &state)
127 {
128 size_t length = state.range(0);
129 int flags = state.range(1);
130 for (auto _ : state) {
131 char* mem = (char *)mmap(nullptr, length, PROT_READ | PROT_WRITE, flags, -1, 0);
132 if (mem != MAP_FAILED) {
133 benchmark::DoNotOptimize(mem);
134 state.PauseTiming();
135 munmap(mem, length);
136 state.ResumeTiming();
137 }
138 }
139 state.SetItemsProcessed(state.iterations());
140 }
141
Bm_function_Munmap_anonymous(benchmark::State & state)142 static void Bm_function_Munmap_anonymous(benchmark::State &state)
143 {
144 size_t length = state.range(0);
145 int flags = state.range(1);
146 for (auto _ : state) {
147 state.PauseTiming();
148 char* mem = (char *)mmap(nullptr, length, PROT_READ | PROT_WRITE, flags, -1, 0);
149 state.ResumeTiming();
150 if (mem != MAP_FAILED) {
151 benchmark::DoNotOptimize(mem);
152 munmap(mem, length);
153 }
154 }
155 state.SetItemsProcessed(state.iterations());
156 }
157
Bm_function_Mmap_fd(benchmark::State & state)158 static void Bm_function_Mmap_fd(benchmark::State &state)
159 {
160 int fd = open("/dev/zero", O_RDWR, OPEN_MODE);
161 if (fd == -1) {
162 perror("open /dev/zero failed.");
163 }
164 size_t length = state.range(0);
165 int flags = state.range(1);
166 for (auto _ : state) {
167 char* mem = (char *)mmap(nullptr, length, PROT_READ | PROT_WRITE, flags, fd, 0);
168 if (mem != MAP_FAILED) {
169 benchmark::DoNotOptimize(mem);
170 state.PauseTiming();
171 munmap(mem, length);
172 state.ResumeTiming();
173 }
174 }
175 close(fd);
176 state.SetItemsProcessed(state.iterations());
177 }
178
Bm_function_Munmap_fd(benchmark::State & state)179 static void Bm_function_Munmap_fd(benchmark::State &state)
180 {
181 int fd = open("/dev/zero", O_RDWR, OPEN_MODE);
182 if (fd == -1) {
183 perror("open /dev/zero failed.");
184 }
185 size_t length = state.range(0);
186 int flags = state.range(1);
187 for (auto _ : state) {
188 state.PauseTiming();
189 char* mem = (char *)mmap(nullptr, length, PROT_READ | PROT_WRITE, flags, fd, 0);
190 state.ResumeTiming();
191 if (mem != MAP_FAILED) {
192 benchmark::DoNotOptimize(mem);
193 munmap(mem, length);
194 }
195 }
196 close(fd);
197 state.SetItemsProcessed(state.iterations());
198 }
199
Bm_function_Madvise(benchmark::State & state)200 static void Bm_function_Madvise(benchmark::State &state)
201 {
202 size_t length = state.range(0);
203 int type = state.range(1);
204 int *addr = (int*)mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
205 for (auto _ : state) {
206 benchmark::DoNotOptimize(madvise(addr, length, type));
207 }
208 madvise(addr, length, MADV_NORMAL);
209 munmap(addr, length);
210 }
211
Bm_function_Mremap(benchmark::State & state)212 static void Bm_function_Mremap(benchmark::State &state)
213 {
214 size_t oldLength = state.range(0);
215 size_t newLength = state.range(1);
216
217 for (auto _ : state) {
218 state.PauseTiming();
219 void *oldAddr = mmap(nullptr, oldLength, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
220 state.ResumeTiming();
221
222 if (oldAddr != MAP_FAILED) {
223 #if defined __APPLE__
224 void *newAddr = MAP_FAILED;
225 #else
226 void *newAddr = mremap(oldAddr, oldLength, newLength, MREMAP_MAYMOVE);
227 #endif
228 if (newAddr != MAP_FAILED) {
229 state.PauseTiming();
230 munmap(newAddr, newLength);
231 state.ResumeTiming();
232 } else {
233 perror("mmap");
234 }
235 }
236 }
237 }
238
Bm_function_Msync(benchmark::State & state)239 static void Bm_function_Msync(benchmark::State &state)
240 {
241 size_t length = state.range(0);
242 int flags = state.range(1);
243 for (auto _ : state) {
244 state.PauseTiming();
245 char* mem = (char *)mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
246 state.ResumeTiming();
247
248 if (mem != MAP_FAILED) {
249 msync(mem, length, flags);
250
251 state.PauseTiming();
252 munmap(mem, length);
253 state.ResumeTiming();
254 }
255 }
256 }
257
Bm_function_mprotect(benchmark::State & state)258 static void Bm_function_mprotect(benchmark::State &state)
259 {
260 size_t pagesize = sysconf(_SC_PAGE_SIZE);
261 size_t size = pagesize * mprotectLength[state.range(0)];
262 #if defined __APPLE__
263 void *pages;
264 posix_memalign(&pages, pagesize, size);
265 #else
266 void *pages = memalign(pagesize, size);
267 #endif
268
269 for (auto _ : state) {
270 benchmark::DoNotOptimize(mprotect(pages, size, PROT_READ | PROT_WRITE));
271 }
272 state.SetItemsProcessed(state.iterations());
273
274 free(pages);
275 }
276
277 // Used to unlock some or all of a process's virtual memory
278 // allowing it to be swapped out to swap space on disk
Bm_function_Mlock_Munlock(benchmark::State & state)279 static void Bm_function_Mlock_Munlock(benchmark::State &state)
280 {
281 size_t length = state.range(0);
282 void *addr = mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
283 if (addr == MAP_FAILED) {
284 perror("mmap munlock");
285 }
286
287 for (auto _ : state) {
288 if (mlock(addr, length) != 0) {
289 perror("mlock munlock");
290 }
291
292 if (munlock(addr, length) != 0) {
293 perror("munlock proc");
294 }
295 }
296 munmap(addr, length);
297 }
298
299 MUSL_BENCHMARK_WITH_APPLY(Bm_function_Mmap_anonymous, PrepareArgs);
300 MUSL_BENCHMARK_WITH_APPLY(Bm_function_Munmap_anonymous, PrepareArgs);
301 MUSL_BENCHMARK_WITH_APPLY(Bm_function_Mmap_fd, PrepareArgs);
302 MUSL_BENCHMARK_WITH_APPLY(Bm_function_Munmap_fd, PrepareArgs);
303 MUSL_BENCHMARK_WITH_APPLY(Bm_function_Madvise, PrepareArgsInMdvise);
304 MUSL_BENCHMARK_WITH_APPLY(Bm_function_Mremap, PrepareArgsInMremap);
305 MUSL_BENCHMARK_WITH_APPLY(Bm_function_Msync, PrepareArgsInMsync);
306 MUSL_BENCHMARK_WITH_ARG(Bm_function_mprotect, "BENCHMARK_8");
307 MUSL_BENCHMARK_WITH_ARG(Bm_function_Mlock_Munlock, "COMMON_ARGS");
308