2 * The only function of interest is:
3 * double estimate_throughput(char *device, int streamers);
4 * @device: the device we want to test.
5 * @streamers: the number of sequential readers we're interested in.
8 #include <diskbfq_th.h>
10 /* given a device name, return its size in sectors */
11 static int64_t read_size(char *device)
15 char *path, *devname = device;
18 for (i = strlen(device) - 1; i >= 0; i--) {
19 if (device[i] == '/') {
20 devname = device + i + 1;
25 size = sizeof(SYSFS_BASE) + strlen(devname) + sizeof("/size");
26 path = calloc(1, size);
30 snprintf(path, size, SYSFS_BASE "%s/size", devname);
31 fp = fopen(path, "r");
37 count = fscanf(fp, "%llu", (unsigned long long*) &rval);
47 /* reader: reads from the device until stop_all becomes true */
48 static void *reader_body(void *arg)
50 struct reader_data *rdata = arg;
51 off_t offset = rdata->offset * 512;
52 char buffer[2 * READ_BLKSIZE], *bufptr;
56 /* O_DIRECT needs page-aligned buffer/offset/blksize */
57 page_size = sysconf(_SC_PAGESIZE);
58 bufptr = (char *)(((uintptr_t)buffer + page_size) & ~(page_size - 1));
60 while (!*rdata->stop) {
61 /* offset may lose alignment if a read ends prematurely */
62 offset = (offset + page_size) & ~(page_size - 1);
64 /* should not happen, wrap if we're too fast */
65 if (offset > READ_ROOM * 512 - READ_BLKSIZE)
66 offset = rdata->offset * 512;
68 /* use pread() to share devfd among all the threads */
69 count = pread(rdata->devfd, bufptr, READ_BLKSIZE, offset);
74 rdata->completed += count / 512;
78 dprintf("reader: completed = %lld, error = %d\n",
79 rdata->completed, rdata->error);
83 /* wait for the termination of all the readers (collecting errors, if any) */
84 static void wait_all(struct dprof_data *ddata, int *error)
86 struct reader_data *rdata;
90 for (i = 0; i < ddata->streamers; i++) {
91 rdata = ddata->reader_data + i;
94 pthread_join(rdata->id, NULL);
95 if (rdata->error && error)
96 *error = rdata->error;
100 /* create and start all the readers */
101 static struct dprof_data *create_readers(int streamers, int devfd,
104 struct dprof_data *ddata;
105 struct reader_data *rdata;
109 ddata = calloc(1, sizeof(struct reader_data) * streamers +
110 sizeof(struct dprof_data));
114 ddata->streamers = streamers;
116 /* space the readers evenly over the disk surface */
117 step = (devsize - streamers * READ_ROOM) / streamers;
119 for (i = 0; i < streamers; i++) {
120 rdata = ddata->reader_data + i;
121 rdata->offset = step * i;
122 rdata->stop = &ddata->stop_all;
123 rdata->devfd = devfd;
125 error = pthread_create(&rdata->id, NULL, reader_body, rdata);
127 wait_all(ddata, NULL);
137 /* return the throughput, in KiB/s */
138 static double calc_throughput(struct dprof_data *ddata,
139 struct timeval *begin,
142 struct reader_data *rdata;
143 double total = 0, delta;
146 for (i = 0; i < ddata->streamers; i++) {
147 rdata = ddata->reader_data + i;
148 total += rdata->completed;
151 delta = end->tv_usec - begin->tv_usec;
152 delta += (end->tv_sec - begin->tv_sec) * 1000000.0;
154 /* total is in sectors, delta in usecs, convert to KiB/s */
155 return total / delta * (512 * 1000000 / 1024);
158 double estimate_throughput(char *device, int streamers)
160 struct timeval begin, end;
161 struct dprof_data *ddata;
162 double throughput = -1;
164 int devfd, error = 0;
166 /* get device size */
167 devsize = read_size(device);
171 /* open the device */
172 devfd = open(device, O_RDONLY | O_DIRECT);
176 /* let the good times roll... */
177 gettimeofday(&begin, NULL);
179 /* start all the threads */
180 ddata = create_readers(streamers, devfd, devsize);
185 sleep(MEAS_INTERVAL);
187 /* wait for their completion */
188 wait_all(ddata, &error);
190 /* this is the end... */
191 gettimeofday(&end, NULL);
194 throughput = calc_throughput(ddata, &begin, &end);