1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2018 Dell EMC Isilon
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29 #include <sys/param.h>
30 #include <sys/mman.h>
31 #include <sys/stat.h>
32 #include <sys/wait.h>
33
34 #include <machine/atomic.h>
35
36 #include <err.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <unistd.h>
44
45 #define PARALLEL 3
46 #define SYNC 0
47
48 static void cr1(void);
49 static void cr2(void);
50 static void cr3(void);
51 static void rn1(void);
52 static void rw1(void);
53 static void rw2(void);
54 static void (*functions[])(void) = {&cr1, &cr2, &cr3, &rn1, &rw1, &rw2};
55
56 static volatile u_int *share;
57 static int tests;
58
59 static void
cr1(void)60 cr1(void)
61 {
62 int fd, i, j;
63 int loops = 9000;
64 char file[128];
65
66 setproctitle("%s sync", __func__);
67 atomic_add_int(&share[SYNC], 1);
68 while (share[SYNC] != (volatile u_int)tests * PARALLEL)
69 usleep(100);
70 setproctitle("%s", __func__);
71 for (j = 0; j < 10; j++) {
72 for (i = 0; i < loops; i++) {
73 snprintf(file, sizeof(file), "%s.%06d.%03d",
74 __func__, getpid(), i);
75 if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC,
76 DEFFILEMODE)) == -1)
77 err(1, "open(%s)", file);
78 close(fd);
79 if (i % 1000 == 0)
80 usleep(100);
81 }
82 for (i = 0; i < loops; i++) {
83 snprintf(file, sizeof(file), "%s.%06d.%03d",
84 __func__, getpid(), i);
85 if (unlink(file) == -1)
86 err(1, "unlink(%s)", file);
87 }
88 }
89 }
90
91 static void
cr2(void)92 cr2(void)
93 {
94 int fd, i, j;
95 char file[1024];
96
97 setproctitle("%s sync", __func__);
98 atomic_add_int(&share[SYNC], 1);
99 while (share[SYNC] != (volatile u_int)tests * PARALLEL)
100 usleep(100);
101 setproctitle("%s", __func__);
102 for (j = 0; j < 3; j++) {
103 for (i = 0; i < 40000; i++) {
104 snprintf(file, sizeof(file), "%s.%06d.%03d",
105 __func__, getpid(), i);
106 if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC,
107 DEFFILEMODE)) == -1)
108 err(1, "open(%s)", file);
109 close(fd);
110 if (unlink(file) == -1)
111 err(1, "unlink(%s)", file);
112 if (i % 1000 == 0)
113 usleep(100);
114 }
115 }
116 }
117
118 static void
cr3(void)119 cr3(void)
120 {
121 int fd, i, j;
122 int loops = 10000;
123 char file[1024], path[1024];
124
125 setproctitle("%s sync", __func__);
126 atomic_add_int(&share[SYNC], 1);
127 while (share[SYNC] != (volatile u_int)tests * PARALLEL)
128 usleep(100);
129 setproctitle("%s", __func__);
130 getcwd(path, sizeof(path));
131 for (j = 0; j < 7; j++) {
132 for (i = 0; i < loops; i++) {
133 snprintf(file, sizeof(file), "%s/%s.%06d.%03d",
134 path, __func__, getpid(), i);
135 if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC,
136 DEFFILEMODE)) == -1)
137 err(1, "open(%s)", file);
138 close(fd);
139 if (i % 1000 == 0)
140 usleep(100);
141 }
142 for (i = 0; i < loops; i++) {
143 snprintf(file, sizeof(file), "%s/%s.%06d.%03d",
144 path, __func__, getpid(), i);
145 if (unlink(file) == -1)
146 err(1, "unlink(%s)", file);
147 }
148 }
149 }
150
151 static void
rn1(void)152 rn1(void)
153 {
154 int fd, i, j;
155 int loops = 10000;
156 char file[128], new[128];
157
158 setproctitle("%s sync", __func__);
159 atomic_add_int(&share[SYNC], 1);
160 while (share[SYNC] != (volatile u_int)tests * PARALLEL)
161 usleep(100);
162 setproctitle("%s", __func__);
163
164 for (j = 0; j < 8; j++) {
165 for (i = 0; i < loops; i++) {
166 snprintf(file, sizeof(file), "%s.%06d.%03d",
167 __func__, getpid(), i);
168 if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC,
169 DEFFILEMODE)) == -1)
170 err(1, "open(%s)", file);
171 close(fd);
172 snprintf(new, sizeof(new), "%s.%06d.%03d.new",
173 __func__, getpid(), i);
174 if (rename(file, new) == -1)
175 err(1, "rename(%s, %s)", file, new);
176 if (unlink(new) == -1)
177 err(1, "unlink(%s)", new);
178 if (i % 1000 == 0)
179 usleep(100);
180 }
181 }
182 }
183
184 static void
rw1(void)185 rw1(void)
186 {
187 int fd, i;
188 int loops = 10000;
189 char buf[512], file[128];
190
191 setproctitle("%s sync", __func__);
192 atomic_add_int(&share[SYNC], 1);
193 while (share[SYNC] != (volatile u_int)tests * PARALLEL)
194 usleep(100);
195
196 setproctitle("%s", __func__);
197 memset(buf, 0, sizeof(buf));
198 for (i = 0; i < loops; i++) {
199 snprintf(file, sizeof(file), "rw1.%06d.%03d", getpid(), i);
200 if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC,
201 DEFFILEMODE)) == -1)
202 err(1, "open(%s)", file);
203 if (write(fd, buf, sizeof(buf)) != sizeof(buf))
204 err(1, "write(%s)", file);
205 close(fd);
206 }
207 for (i = 0; i < loops; i++) {
208 snprintf(file, sizeof(file), "rw1.%06d.%03d", getpid(), i);
209 if ((fd = open(file, O_RDONLY)) == -1)
210 err(1, "open(%s)", file);
211 if (read(fd, buf, sizeof(buf)) != sizeof(buf))
212 err(1, "write(%s)", file);
213 close(fd);
214 usleep(100);
215 }
216 for (i = 0; i < loops; i++) {
217 snprintf(file, sizeof(file), "rw1.%06d.%03d", getpid(), i);
218 if (unlink(file) == -1)
219 err(1, "unlink(%s)", file);
220 }
221 }
222
223 static void
rw2(void)224 rw2(void)
225 {
226 int fd, i;
227 int loops = 8000;
228 int siz = 4096;
229 char *buf, file[128];
230
231 setproctitle("%s sync", __func__);
232 atomic_add_int(&share[SYNC], 1);
233 while (share[SYNC] != (volatile u_int)tests * PARALLEL)
234 usleep(100);
235
236 setproctitle("%s", __func__);
237 buf = calloc(1, siz);
238 for (i = 0; i < loops; i++) {
239 snprintf(file, sizeof(file), "rw1.%06d.%03d", getpid(), i);
240 if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC,
241 DEFFILEMODE)) == -1)
242 err(1, "open(%s)", file);
243 if (write(fd, buf, siz) != siz)
244 err(1, "write(%s)", file);
245 close(fd);
246 }
247 for (i = 0; i < loops; i++) {
248 snprintf(file, sizeof(file), "rw1.%06d.%03d", getpid(), i);
249 if ((fd = open(file, O_RDONLY)) == -1)
250 err(1, "open(%s)", file);
251 if (read(fd, buf, siz) != siz)
252 err(1, "write(%s)", file);
253 close(fd);
254 usleep(100);
255 }
256 for (i = 0; i < loops; i++) {
257 snprintf(file, sizeof(file), "rw1.%06d.%03d", getpid(), i);
258 if (unlink(file) == -1)
259 err(1, "unlink(%s)", file);
260 }
261 }
262
263 static void
spawn(void f (),int idx)264 spawn(void f(), int idx)
265 {
266 pid_t pids[PARALLEL];
267 int i, status;
268 char dir[128];
269
270 snprintf(dir, sizeof(dir), "f%d.%d.d",getpid(), idx);
271 rmdir(dir);
272 if (mkdir(dir, 0770) == -1)
273 err(1, "mkdir(%s)", dir);
274 if (chdir(dir) == -1)
275 err(1, "chdir(%s)", dir);
276 for (i = 0; i < PARALLEL; i++) {
277 if ((pids[i] = fork()) == 0) {
278 f();
279 _exit(0);
280 }
281 if (pids[i] == -1)
282 err(1, "fork(). %s:%d", __func__, __LINE__);
283 }
284 for (i = 0; i < PARALLEL; i++) {
285 if (waitpid(pids[i], &status, 0) != pids[i])
286 err(1, "waitpid(). %s:%d", __func__, __LINE__);
287 }
288 if (chdir("..") == -1)
289 err(1, "chdir(..)");
290 if (rmdir(dir) == -1)
291 err(1, "rmdir(%s)", dir);
292
293 }
294
295 void
usage(void)296 usage(void)
297 {
298 fprintf(stderr, "Usage: %s [-t]\n", getprogname());
299 exit(1);
300 }
301
302 int
main(int argc,char * argv[])303 main(int argc, char *argv[])
304 {
305 pid_t *pids;
306 struct timeval t1, t2, diff;
307 size_t len;
308 time_t start __unused;
309 int ch, i, status, timing;
310
311 timing = 0;
312 while ((ch = getopt(argc, argv, "t")) != -1)
313 switch(ch) {
314 case 't':
315 timing = 1;
316 break;
317 default:
318 usage();
319 }
320 argc -= optind;
321 argv += optind;
322
323 setproctitle("%s", __func__);
324 tests = (int)(sizeof(functions) / sizeof(functions[0]));
325 pids = malloc(tests * sizeof(pid_t));
326 len = PAGE_SIZE;
327 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE,
328 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)
329 err(1, "mmap");
330
331 gettimeofday(&t1, NULL);
332 for (i = 0; i < tests; i++) {
333 if ((pids[i] = fork()) == 0) {
334 start = time(NULL);
335 spawn(functions[i], i);
336 #if defined(DEBUG)
337 fprintf(stderr, "%d: %ld elapsed\n", i ,
338 (long)(time(NULL) - start));
339 #endif
340 _exit(0);
341 }
342 if (pids[i] == -1)
343 err(1, "fork(). %s:%d", __func__, __LINE__);
344 }
345 for (i = 0; i < tests; i++) {
346 if (waitpid(pids[i], &status, 0) != pids[i])
347 err(1, "waitpid(%d). i=%d %s:%d", pids[i], i,
348 __func__, __LINE__);
349 }
350 gettimeofday(&t2, NULL);
351 timersub(&t2, &t1, &diff);
352 if (timing == 1)
353 printf("%jd.%06ld\n",(intmax_t)diff.tv_sec, diff.tv_usec);
354
355 return (0);
356 }
357