xref: /dragonfly/test/sysperf/randread.c (revision 9348a738)
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
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