add mmap support
[tridge/junkcode.git] / ping_pong.c
1 /*
2   this measures the ping-pong byte range lock latency. It is
3   especially useful on a cluster of nodes sharing a common lock
4   manager as it will give some indication of the lock managers
5   performance under stress
6
7   tridge@samba.org, February 2002
8
9 */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <sys/time.h>
14 #include <time.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <getopt.h>
20 #include <sys/mman.h>
21
22 static struct timeval tp1,tp2;
23
24 static int do_reads, do_writes, use_mmap;
25
26 static void start_timer()
27 {
28         gettimeofday(&tp1,NULL);
29 }
30
31 static double end_timer()
32 {
33         gettimeofday(&tp2,NULL);
34         return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - 
35                 (tp1.tv_sec + (tp1.tv_usec*1.0e-6));
36 }
37
38 /* lock a byte range in a open file */
39 static int lock_range(int fd, int offset, int len)
40 {
41         struct flock lock;
42
43         lock.l_type = F_WRLCK;
44         lock.l_whence = SEEK_SET;
45         lock.l_start = offset;
46         lock.l_len = len;
47         lock.l_pid = 0;
48         
49         return fcntl(fd,F_SETLKW,&lock);
50 }
51
52 /* unlock a byte range in a open file */
53 static int unlock_range(int fd, int offset, int len)
54 {
55         struct flock lock;
56
57         lock.l_type = F_UNLCK;
58         lock.l_whence = SEEK_SET;
59         lock.l_start = offset;
60         lock.l_len = len;
61         lock.l_pid = 0;
62         
63         return fcntl(fd,F_SETLKW,&lock);
64 }
65
66 /* run the ping pong test on fd */
67 static void ping_pong(int fd, int num_locks)
68 {
69         unsigned count = 0;
70         int i=0;
71         unsigned char *val;
72         unsigned char incr=0, last_incr=0;
73         unsigned char *p = NULL;
74
75         if (use_mmap) {
76                 p = mmap(NULL, num_locks+1, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
77         }
78
79         val = (unsigned char *)calloc(num_locks+1, sizeof(unsigned char));
80
81         start_timer();
82
83         lock_range(fd, 0, 1);
84         i = 0;
85
86         while (1) {
87                 if (lock_range(fd, (i+1) % num_locks, 1) != 0) {
88                         printf("lock at %d failed! - %s\n",
89                                (i+1) % num_locks, strerror(errno));
90                 }
91                 if (do_reads) {
92                         unsigned char c;
93                         if (use_mmap) {
94                                 c = p[i];
95                         } if (pread(fd, &c, 1, i) != 1) {
96                                 printf("read failed at %d\n", i);
97                         }
98                         incr = c - val[i];
99                         val[i] = c;
100                 }
101                 if (do_writes) {
102                         char c = val[i] + 1;
103                         if (use_mmap) {
104                                 p[i] = c;
105                         } else if (pwrite(fd, &c, 1, i) != 1) {
106                                 printf("write failed at %d\n", i);
107                         }
108                 }
109                 if (unlock_range(fd, i, 1) != 0) {
110                         printf("unlock at %d failed! - %s\n",
111                                i, strerror(errno));
112                 }
113                 i = (i+1) % num_locks;
114                 count++;
115                 if (incr != last_incr) {
116                         last_incr = incr;
117                         printf("data increment = %u\n", incr);
118                         fflush(stdout);
119                 }
120                 if (end_timer() > 1.0) {
121                         printf("%8u locks/sec\r", 
122                                (unsigned)(2*count/end_timer()));
123                         fflush(stdout);
124                         start_timer();
125                         count=0;
126                 }
127         }
128 }
129
130 int main(int argc, char *argv[])
131 {
132         char *fname;
133         int fd, num_locks;
134         int c;
135
136         while ((c = getopt(argc, argv, "rwm")) != -1) {
137                 switch (c){
138                 case 'w':
139                         do_writes = 1;
140                         break;
141                 case 'r':
142                         do_reads = 1;
143                         break;
144                 case 'm':
145                         use_mmap = 1;
146                         break;
147                 default:
148                         fprintf(stderr, "Unknown option '%c'\n", c);
149                         exit(1);
150                 }
151         }
152
153         argv += optind;
154         argc -= optind;
155
156         if (argc < 2) {
157                 printf("ping_pong [options] <file> <num_locks>\n");
158                 printf("           -r    do reads\n");
159                 printf("           -w    do writes\n");
160                 printf("           -m    use mmap\n");
161                 exit(1);
162         }
163
164         fname = argv[0];
165         num_locks = atoi(argv[1]);
166
167         fd = open(fname, O_CREAT|O_RDWR, 0600);
168         if (fd == -1) exit(1);
169
170         ping_pong(fd, num_locks);
171
172         return 0;
173 }