xref: /dragonfly/test/sysperf/randread.c (revision 9022bcc8c0e94b834076723970831961f8b9a6fd)
1 /*
2  * cc randread.c -o ~/bin/randread -O2 -lm
3  *
4  * randread device [bufsize:512 [range%:90 [nprocs:32]]]
5  *
6  * requires TSC
7  */
8 #include <sys/types.h>
9 #include <sys/sysctl.h>
10 #include <sys/stat.h>
11 #include <sys/file.h>
12 #include <sys/mman.h>
13 #include <sys/errno.h>
14 #include <sys/wait.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <math.h>
20 #include <assert.h>
21 #include <machine/atomic.h>
22 #include <machine/cpufunc.h>
23 
24 typedef struct pdata {
25           int64_t   counter;
26           int64_t lotime;
27           int64_t hitime;
28           int64_t tsc_total1;
29           int64_t tsc_total2;
30           int64_t unused00;
31           int64_t unused01;
32           int       unused02;
33           int       reset;
34 } pdata_t;
35 
36 int
main(int ac,char ** av)37 main(int ac, char **av)
38 {
39     char *buf;
40     size_t bytes = 512;
41     off_t limit;
42     int fd;
43     int i;
44     int loops;
45     int nprocs = 32;
46     double range = 90.0;
47     volatile pdata_t *pdata;
48     int64_t tsc1;
49     int64_t tsc2;
50     int64_t delta;
51     int64_t tscfreq = 0;
52     int64_t lotime;
53     int64_t hitime;
54     size_t tscfreq_size = sizeof(tscfreq);
55 
56     sysctlbyname("hw.tsc_frequency", &tscfreq, &tscfreq_size, NULL, 0);
57     assert(tscfreq != 0);
58 
59     if (ac < 2 || ac > 5) {
60           fprintf(stderr, "%s <device> [bufsize:512 [range%:90 [nprocs:32]]]\n",
61                     av[0]);
62           exit (1);
63     }
64 
65     if (ac >= 3) {
66           bytes = (size_t)strtoul(av[2], NULL, 0);
67           if (bytes < 512 || (bytes ^ (bytes - 1)) != ((bytes << 1) - 1)) {
68               fprintf(stderr, "bytes must be a power of 2 >= 512\n");
69               exit (1);
70           }
71     }
72     buf = malloc(bytes);
73 
74     if (ac >= 4) {
75           range = strtod(av[3], NULL);
76     }
77 
78     if (ac >= 5) {
79           nprocs = strtol(av[4], NULL, 0);
80           if (nprocs < 0 || nprocs > 512) {
81               fprintf(stderr, "absurd nprocs (%d)\n", nprocs);
82               exit(1);
83           }
84     }
85 
86     fd = open(av[1], O_RDONLY);
87     if (fd < 0) {
88           fprintf(stderr, "open %s: %s\n", av[1], strerror(errno));
89           exit (1);
90     }
91 
92     lseek(fd, 0L, 2);
93     limit = lseek(fd, 0L, 1);
94     limit = (off_t)((double)limit * range / 100.0);
95     limit &= ~(off_t)(bytes - 1);
96     printf("device %s bufsize %zd limit %4.3fGB nprocs %d\n",
97           av[1], bytes, (double)limit / (1024.0*1024.0*1024.0), nprocs);
98 
99     pdata = mmap(NULL, nprocs * sizeof(*pdata), PROT_READ|PROT_WRITE,
100                         MAP_SHARED|MAP_ANON, -1, 0);
101 
102     for (i = 0; i < nprocs; ++i) {
103           if (fork() == 0) {
104               close(fd);
105               fd = open(av[1], O_RDONLY);
106               srandomdev();
107               pdata += i;
108 
109               tsc2 = rdtsc();
110               pdata->lotime = 0x7FFFFFFFFFFFFFFFLL;
111 
112               for (;;) {
113                     long pos;
114 
115                     if (pdata->reset) {
116                               pdata->counter = 0;
117                               pdata->tsc_total1 = 0;
118                               pdata->tsc_total2 = 0;
119                               pdata->lotime = 0x7FFFFFFFFFFFFFFFLL;
120                               pdata->hitime = 0;
121                               pdata->reset = 0;
122                     }
123 
124                     pos = random() ^ ((long)random() << 31);
125                     pos &= 0x7FFFFFFFFFFFFFFFLLU;
126                     pos = (pos % limit) & ~(off_t)(bytes - 1);
127                     lseek(fd, pos, 0);
128                     read(fd, buf, bytes);
129                     tsc1 = tsc2;
130                     tsc2 = rdtsc();
131                     delta = tsc2 - tsc1;
132                     ++pdata->counter;
133                     pdata->tsc_total1 += delta;
134                     pdata->tsc_total2 += delta * delta;
135                     if (pdata->lotime > delta)
136                               pdata->lotime = delta;
137                     if (pdata->hitime < delta)
138                               pdata->hitime = delta;
139               }
140           }
141     }
142 
143     tsc2 = rdtsc();
144     loops = 0;
145 
146     for (;;) {
147           int64_t count;
148           int64_t total1;
149           int64_t total2;
150           double v;
151           double lo;
152           double hi;
153           double s1;
154           double s2;
155           double stddev;
156 
157           sleep(1);
158           lotime = pdata[0].lotime;
159           hitime = pdata[0].hitime;
160           total1 = 0;
161           total2 = 0;
162           count = 0;
163 
164           for (i = 0; i < nprocs; ++i) {
165                     count += pdata[i].counter;
166                     total1 += pdata[i].tsc_total1;
167                     total2 += pdata[i].tsc_total2;
168                     if (lotime > pdata[i].lotime)
169                               lotime = pdata[i].lotime;
170                     if (hitime < pdata[i].hitime)
171                               hitime = pdata[i].hitime;
172                     pdata[i].reset = 1;
173           }
174           tsc1 = tsc2;
175           tsc2 = rdtsc();
176           delta = tsc2 - tsc1;
177           v = count * ((double)delta / (double)tscfreq);
178           lo = (double)lotime / (double)tscfreq;
179           hi = (double)hitime / (double)tscfreq;
180 
181           s1 = ((double)total2 - (double)total1 * (double)total1 / (double)count) / ((double)count - 1);
182           if (s1 < 0.0)
183                     stddev = -sqrt(-s1);
184           else
185                     stddev = sqrt(s1);
186           stddev = stddev / (double)tscfreq;      /* normalize to 1 second units */
187 
188           if (loops) {
189                     printf("%6.0f/s avg=%6.2fuS bw=%-6.2fMB/s "
190                            "lo=%-3.2fuS, hi=%-3.2fuS stddev=%3.2fuS\n",
191                            v,
192                            1e6 * nprocs / v,
193                            (double)count * bytes / 1e6 / ((double)delta / (double)tscfreq),
194                            lo * 1e6,
195                            hi * 1e6,
196                            stddev * 1e6);
197           }
198           ++loops;
199     }
200     return 0;
201 }
202