1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 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 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 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 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 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 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 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 296 usage(void) 297 { 298 fprintf(stderr, "Usage: %s [-t]\n", getprogname()); 299 exit(1); 300 } 301 302 int 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