1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License (the "License").
7 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://opensource.org/licenses/CDDL-1.0.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <sys/mman.h>
27 #include <sys/stat.h>
28 #include <sys/time.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <time.h>
32
33 static void
cleanup(char * file)34 cleanup(char *file)
35 {
36 (void) remove(file);
37 }
38
39 int
main(int argc,char * argv[])40 main(int argc, char *argv[])
41 {
42 char *testdir = getenv("TESTDIR");
43 if (!testdir) {
44 fprintf(stderr, "environment variable TESTDIR not set\n");
45 return (1);
46 }
47
48 struct stat st;
49 umask(0);
50 if (stat(testdir, &st) != 0 &&
51 mkdir(testdir, 0777) != 0) {
52 perror("mkdir");
53 return (1);
54 }
55
56 if (argc > 3) {
57 fprintf(stderr, "usage: %s "
58 "[run time in mins] "
59 "[max msync time in ms]\n", argv[0]);
60 return (1);
61 }
62
63 int run_time_mins = 1;
64 if (argc >= 2) {
65 run_time_mins = atoi(argv[1]);
66 }
67
68 int max_msync_time_ms = 2000;
69 if (argc >= 3) {
70 max_msync_time_ms = atoi(argv[2]);
71 }
72
73 char filepath[512];
74 filepath[0] = '\0';
75 char *file = &filepath[0];
76
77 (void) snprintf(file, 512, "%s/msync_file", testdir);
78
79 const int LEN = 8;
80 cleanup(file);
81
82 int fd = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR |
83 S_IRGRP | S_IROTH);
84
85 if (fd == -1) {
86 (void) fprintf(stderr, "%s: %s: ", argv[0], file);
87 perror("open");
88 return (1);
89 }
90
91 if (ftruncate(fd, LEN) != 0) {
92 perror("ftruncate");
93 cleanup(file);
94 return (1);
95 }
96
97 void *ptr = mmap(NULL, LEN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
98
99 if (ptr == MAP_FAILED) {
100 perror("mmap");
101 cleanup(file);
102 return (1);
103 }
104
105 struct timeval tstart;
106 gettimeofday(&tstart, NULL);
107
108 long long x = 0LL;
109
110 for (;;) {
111 *((long long *)ptr) = x;
112 x++;
113
114 struct timeval t1, t2;
115 gettimeofday(&t1, NULL);
116 if (msync(ptr, LEN, MS_SYNC|MS_INVALIDATE) != 0) {
117 perror("msync");
118 cleanup(file);
119 return (1);
120 }
121
122 gettimeofday(&t2, NULL);
123
124 double elapsed = (t2.tv_sec - t1.tv_sec) * 1000.0;
125 elapsed += ((t2.tv_usec - t1.tv_usec) / 1000.0);
126 if (elapsed > max_msync_time_ms) {
127 fprintf(stderr, "slow msync: %f ms\n", elapsed);
128 if (munmap(ptr, LEN) != 0)
129 perror("munmap");
130 cleanup(file);
131 return (1);
132 }
133
134 double elapsed_start = (t2.tv_sec - tstart.tv_sec) * 1000.0;
135 elapsed_start += ((t2.tv_usec - tstart.tv_usec) / 1000.0);
136 if (elapsed_start > run_time_mins * 60 * 1000) {
137 break;
138 }
139 }
140
141 if (munmap(ptr, LEN) != 0) {
142 perror("munmap");
143 cleanup(file);
144 return (1);
145 }
146
147 if (close(fd) != 0) {
148 perror("close");
149 }
150
151 cleanup(file);
152 return (0);
153 }
154