lease02: Do a lock-unlock sequence instead of lock-lock
[jlayton/lockperf.git] / lease02.c
1 /*
2  * Lease performance test 2
3  *
4  * Fork off a given number of children who each open their own
5  * file. Then have each child take a read lease and release the lease
6  * for the given number of times.
7  *
8  * Time this to measure lease performance for lease heavy workloads where the
9  * locks are generally uncontended.
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif /* HAVE_CONFIG_H */
15
16 #include <stdio.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/wait.h>
24 #include <stdlib.h>
25 #include <time.h>
26 #include <sys/mman.h>
27
28 #include "timespec.h"
29
30 #define NRPROC (128)
31 #define NRLOCK (20480)
32
33 static struct timespec *diff;
34
35 static int
36 leaseunlease(int nrlock, struct timespec *slot)
37 {
38         int fd, i, ret;
39         pid_t pid = getpid();
40         char name[10]; /* big enough for pid_t in hex + NULL */
41         struct timespec start, end;
42
43         ret = snprintf(name, sizeof(name), "%x", pid);
44         if (ret >= (int)sizeof(name)) {
45                 perror("sprintf");
46                 return 1;
47         }
48
49         fd = open(name, O_CREAT|O_RDONLY, 0644);
50         if (fd < 0) {
51                 perror("open");
52                 return fd;
53         }
54
55         ret = clock_gettime(CLOCK_MONOTONIC_RAW, &start);
56         if (ret) {
57                 perror("clock_gettime");
58                 return ret;
59         }
60
61         for (i = 0; i < nrlock; ++i) {
62                 ret = fcntl(fd, F_SETLEASE, F_RDLCK);
63                 if (ret < 0) {
64                         perror("fcntl");
65                         break;
66                 }
67                 ret = fcntl(fd, F_SETLEASE, F_UNLCK);
68                 if (ret < 0) {
69                         perror("fcntl");
70                         break;
71                 }
72         }
73
74         ret = clock_gettime(CLOCK_MONOTONIC_RAW, &end);
75         if (ret) {
76                 perror("clock_gettime");
77                 return ret;
78         }
79
80         close(fd);
81         *slot = timespec_sub(end, start);
82         return ret;
83 }
84
85 void
86 usage(char *prog)
87 {
88         printf("usage: %s [-n nr_procs] [-l nr_locks] directory\n", prog);
89 }
90
91 int
92 main(int argc, char **argv)
93 {
94         int i, opt, valid = 0;
95         int nproc = NRPROC;
96         int nlock = NRLOCK;
97         pid_t *pids;
98         char *dirname;
99         struct timespec total = { .tv_sec = 0,
100                                   .tv_nsec = 0 };
101
102         while ((opt = getopt(argc, argv, "l:n:")) != -1) {
103                 switch (opt) {
104                 case 'l':
105                         nlock = atoi(optarg);
106                         break;
107                 case 'n':
108                         nproc = atoi(optarg);
109                         break;
110                 default:
111                         usage(argv[0]);
112                         return 1;
113                 }
114         }
115
116         dirname = argv[optind];
117         if (!dirname) {
118                 usage(argv[0]);
119                 return 1;
120         }
121
122         if (mkdir(dirname, S_IRWXU)) {
123                 perror("mkdir");
124                 return 1;
125         }
126
127         if (chdir(dirname)) {
128                 perror("chdir");
129                 return 1;
130         }
131
132         pids = calloc(nproc, sizeof(pid_t));
133         if (!pids) {
134                 fprintf(stderr, "Unable to allocate pids array!");
135                 return 1;
136         }
137
138         diff = mmap(0, nproc * sizeof(*diff), PROT_READ | PROT_WRITE,
139                         MAP_ANONYMOUS | MAP_SHARED, -1, 0);
140         if (diff == (struct timespec *)-1) {
141                 fprintf(stderr, "Unable to allocate timespec array!");
142                 return 1;
143         }
144
145         for (i = 0; i < nproc; ++i) {
146                 pids[i] = fork();
147                 if (!pids[i])
148                         return leaseunlease(nlock, &diff[i]);
149         }
150
151         for (i = 0; i < nproc; ++i) {
152                 int status;
153
154                 if (pids[i] < 0) {
155                         fprintf(stderr, "process %d failed to fork\n", i);
156                         continue;
157                 }
158                 if (waitpid(pids[i], &status, 0) < 0) {
159                         fprintf(stderr, "unable to reap pid %d\n", pids[i]);
160                         continue;
161                 }
162                 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
163                         fprintf(stderr, "pid %d exited abnormally(0x%x)\n", pids[i],status);
164                         continue;
165                 }
166                 total = timespec_add(total, diff[i]);
167                 ++valid;
168         }
169
170         if (valid != nproc) {
171                 fprintf(stderr, "Some children didn't run properly -- "
172                                 "requested %d but only got %d\n", nproc, valid);
173                 return 1;
174         }
175
176         printf("%ld.%09ld\n", total.tv_sec, total.tv_nsec);
177         return 0;
178 }