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