1 /*
2 * Copyright (c) International Business Machines Corp., 2001-2004
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
12 * the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 #define _LARGEFILE64_SOURCE
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <pthread.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <errno.h>
27
28 #include "fh.h"
29 #include "util.h"
30 #include "ffsb.h"
31 #include "fileops.h"
32 #include "ffsb_op.h"
33
do_stats(struct timeval * start,struct timeval * end,ffsb_thread_t * ft,ffsb_fs_t * fs,syscall_t sys)34 static void do_stats(struct timeval *start, struct timeval *end,
35 ffsb_thread_t * ft, ffsb_fs_t * fs, syscall_t sys)
36 {
37 struct timeval diff;
38 uint32_t value = 0;
39
40 if (!ft && !fs)
41 return;
42
43 timersub(end, start, &diff);
44
45 value = 1000000 * diff.tv_sec + diff.tv_usec;
46
47 if (ft && ft_needs_stats(ft, sys))
48 ft_add_stat(ft, sys, value);
49 if (fs && fs_needs_stats(fs, sys))
50 fs_add_stat(fs, sys, value);
51 }
52
fop_bench(ffsb_fs_t * fs,unsigned opnum)53 void fop_bench(ffsb_fs_t * fs, unsigned opnum)
54 {
55 fs_set_opdata(fs, fs_get_datafiles(fs), opnum);
56 }
57
fop_age(ffsb_fs_t * fs,unsigned opnum)58 void fop_age(ffsb_fs_t * fs, unsigned opnum)
59 {
60 fs_set_opdata(fs, fs_get_agefiles(fs), opnum);
61 }
62
readfile_helper(int fd,uint64_t size,uint32_t blocksize,char * buf,ffsb_thread_t * ft,ffsb_fs_t * fs)63 static unsigned readfile_helper(int fd, uint64_t size, uint32_t blocksize,
64 char *buf, ffsb_thread_t * ft, ffsb_fs_t * fs)
65 {
66 int iterations, a;
67 int last;
68
69 iterations = size / blocksize;
70 last = size % blocksize;
71
72 for (a = 0; a < iterations; a++)
73 fhread(fd, buf, blocksize, ft, fs);
74 if (last)
75 fhread(fd, buf, last, ft, fs);
76 return iterations;
77 }
78
get_random_offset(randdata_t * rd,uint64_t filesize,int aligned)79 static uint64_t get_random_offset(randdata_t * rd, uint64_t filesize,
80 int aligned)
81 {
82 if (!aligned)
83 return getllrandom(rd, filesize);
84
85 filesize /= 4096;
86 return getllrandom(rd, filesize) * 4096;
87 }
88
ffsb_readfile(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)89 void ffsb_readfile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
90 {
91 struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
92 struct ffsb_file *curfile = NULL;
93
94 int fd;
95 uint64_t filesize;
96
97 char *buf = ft_getbuf(ft);
98 int read_random = ft_get_read_random(ft);
99 uint64_t read_size = ft_get_read_size(ft);
100 uint32_t read_blocksize = ft_get_read_blocksize(ft);
101 uint32_t read_skipsize = ft_get_read_skipsize(ft);
102 int skip_reads = ft_get_read_skip(ft);
103 struct randdata *rd = ft_get_randdata(ft);
104
105 uint64_t iterations = 0;
106
107 curfile = choose_file_reader(bf, rd);
108 fd = fhopenread(curfile->name, ft, fs);
109
110 filesize = ffsb_get_filesize(curfile->name);
111
112 assert(filesize >= read_size);
113
114 /* Sequential read, starting at a random point */
115 if (!read_random) {
116 uint64_t range = filesize - read_size;
117 uint64_t offset = 0;
118 /* Skip or "stride" reads option */
119 if (skip_reads) {
120 unsigned i, last;
121 uint64_t minfilesize;
122 iterations = read_size / read_blocksize;
123 last = read_size % read_blocksize;
124
125 /* Double check that the user hasn't specified
126 * a read_size that is too large when combined
127 * with the seeks
128 */
129 if (last)
130 minfilesize = last + iterations *
131 (read_blocksize + read_skipsize);
132 else
133 minfilesize = read_blocksize + iterations - 1 *
134 (read_blocksize + read_skipsize);
135
136 if (minfilesize > filesize) {
137 printf("Error: read size %llu bytes too big "
138 "w/ skipsize %u and blocksize %u,"
139 " for file of size %llu bytes\n"
140 " aborting\n\n", read_size,
141 read_skipsize, read_blocksize, filesize);
142 printf("minimum file size must be at least "
143 " %llu bytes\n", minfilesize);
144 exit(1);
145 }
146
147 for (i = 0; i < iterations; i++) {
148 fhread(fd, buf, read_blocksize, ft, fs);
149 fhseek(fd, (uint64_t) read_skipsize, SEEK_CUR,
150 ft, fs);
151 }
152 if (last) {
153 fhread(fd, buf, (uint64_t) last, ft, fs);
154 iterations++;
155 }
156 } else {
157 /* Regular sequential reads */
158 if (range) {
159 offset = get_random_offset(rd, range,
160 fs_get_alignio(fs));
161 fhseek(fd, offset, SEEK_SET, ft, fs);
162 }
163 iterations = readfile_helper(fd, read_size,
164 read_blocksize, buf,
165 ft, fs);
166 }
167 } else {
168 /* Randomized read */
169 uint64_t range = filesize - read_blocksize;
170 int i;
171
172 iterations = read_size / read_blocksize;
173
174 for (i = 0; i < iterations; i++) {
175 uint64_t offset = get_random_offset(rd, range,
176 fs_get_alignio(fs));
177 fhseek(fd, offset, SEEK_SET, ft, fs);
178 fhread(fd, buf, read_blocksize, ft, fs);
179 }
180 }
181
182 unlock_file_reader(curfile);
183 fhclose(fd, ft, fs);
184
185 ft_incr_op(ft, opnum, iterations, read_size);
186 ft_add_readbytes(ft, read_size);
187 }
188
189 /* Just like ffsb_readfile but we read the whole file from start to
190 * finish regardless of file size.
191 */
ffsb_readall(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)192 void ffsb_readall(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
193 {
194 struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
195 struct ffsb_file *curfile = NULL;
196 int fd;
197 uint64_t filesize;
198
199 char *buf = ft_getbuf(ft);
200 uint32_t read_blocksize = ft_get_read_blocksize(ft);
201 struct randdata *rd = ft_get_randdata(ft);
202
203 unsigned iterations = 0;
204
205 curfile = choose_file_reader(bf, rd);
206 fd = fhopenread(curfile->name, ft, fs);
207
208 filesize = ffsb_get_filesize(curfile->name);
209 iterations = readfile_helper(fd, filesize, read_blocksize, buf, ft, fs);
210
211 unlock_file_reader(curfile);
212 fhclose(fd, ft, fs);
213
214 ft_incr_op(ft, opnum, iterations, filesize);
215 ft_add_readbytes(ft, filesize);
216 }
217
218 /* Shared core between ffsb_writefile and ffsb_writefile_fsync.*/
219
ffsb_writefile_core(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum,uint64_t * filesize_ret,int fsync_file)220 static unsigned ffsb_writefile_core(ffsb_thread_t * ft, ffsb_fs_t * fs,
221 unsigned opnum, uint64_t * filesize_ret,
222 int fsync_file)
223 {
224 struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
225 struct ffsb_file *curfile = NULL;
226
227 int fd;
228 uint64_t filesize;
229
230 char *buf = ft_getbuf(ft);
231 int write_random = ft_get_write_random(ft);
232 uint32_t write_size = ft_get_write_size(ft);
233 uint32_t write_blocksize = ft_get_write_blocksize(ft);
234 struct randdata *rd = ft_get_randdata(ft);
235 unsigned iterations = 0;
236
237 curfile = choose_file_reader(bf, rd);
238 fd = fhopenwrite(curfile->name, ft, fs);
239
240 filesize = ffsb_get_filesize(curfile->name);
241
242 assert(filesize >= write_size);
243
244 /* Sequential write, starting at a random point */
245 if (!write_random) {
246 uint64_t range = filesize - write_size;
247 uint64_t offset = 0;
248 if (range) {
249 offset = get_random_offset(rd, range,
250 fs_get_alignio(fs));
251 fhseek(fd, offset, SEEK_SET, ft, fs);
252 }
253 iterations = writefile_helper(fd, write_size, write_blocksize,
254 buf, ft, fs);
255 } else {
256 /* Randomized write */
257 uint64_t range = filesize - write_blocksize;
258 int i;
259 iterations = write_size / write_blocksize;
260
261 for (i = 0; i < iterations; i++) {
262 uint64_t offset = get_random_offset(rd, range,
263 fs_get_alignio(fs));
264 fhseek(fd, offset, SEEK_SET, ft, fs);
265 fhwrite(fd, buf, write_blocksize, ft, fs);
266 }
267 }
268
269 if (fsync_file) {
270 if (fsync(fd)) {
271 perror("fsync");
272 printf("aborting\n");
273 exit(1);
274 }
275 }
276 unlock_file_reader(curfile);
277 fhclose(fd, ft, fs);
278 *filesize_ret = filesize;
279 return iterations;
280 }
281
ffsb_writefile(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)282 void ffsb_writefile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
283 {
284 unsigned iterations;
285 uint64_t filesize;
286
287 iterations = ffsb_writefile_core(ft, fs, opnum, &filesize, 0);
288 ft_incr_op(ft, opnum, iterations, filesize);
289 ft_add_writebytes(ft, filesize);
290 }
291
ffsb_writefile_fsync(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)292 void ffsb_writefile_fsync(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
293 {
294 unsigned iterations;
295 uint64_t filesize;
296
297 iterations = ffsb_writefile_core(ft, fs, opnum, &filesize, 1);
298 ft_incr_op(ft, opnum, iterations, filesize);
299 ft_add_writebytes(ft, filesize);
300 }
301
302 /* Shared core between ffsb_writeall and ffsb_writeall_fsync.*/
303
ffsb_writeall_core(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum,uint64_t * filesize_ret,int fsync_file)304 static unsigned ffsb_writeall_core(ffsb_thread_t * ft, ffsb_fs_t * fs,
305 unsigned opnum, uint64_t * filesize_ret,
306 int fsync_file)
307 {
308 struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
309 struct ffsb_file *curfile = NULL;
310 int fd;
311 uint64_t filesize;
312
313 char *buf = ft_getbuf(ft);
314 uint32_t write_blocksize = ft_get_write_blocksize(ft);
315 struct randdata *rd = ft_get_randdata(ft);
316
317 unsigned iterations = 0;
318
319 curfile = choose_file_reader(bf, rd);
320 fd = fhopenwrite(curfile->name, ft, fs);
321
322 filesize = ffsb_get_filesize(curfile->name);
323 iterations = writefile_helper(fd, filesize, write_blocksize, buf,
324 ft, fs);
325 if (fsync_file)
326 if (fsync(fd)) {
327 perror("fsync");
328 printf("aborting\n");
329 exit(1);
330 }
331
332 unlock_file_reader(curfile);
333 fhclose(fd, ft, fs);
334 *filesize_ret = filesize;
335 return iterations;
336 }
337
338 /* Just like ffsb_writefile but we write the whole file from start to
339 * finish regardless of file size
340 */
ffsb_writeall(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)341 void ffsb_writeall(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
342 {
343 unsigned iterations;
344 uint64_t filesize;
345
346 iterations = ffsb_writeall_core(ft, fs, opnum, &filesize, 0);
347 ft_incr_op(ft, opnum, iterations, filesize);
348 ft_add_writebytes(ft, filesize);
349 }
350
ffsb_writeall_fsync(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)351 void ffsb_writeall_fsync(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
352 {
353 unsigned iterations;
354 uint64_t filesize;
355
356 iterations = ffsb_writeall_core(ft, fs, opnum, &filesize, 1);
357 ft_incr_op(ft, opnum, iterations, filesize);
358 ft_add_writebytes(ft, filesize);
359 }
360
ffsb_appendfile_core(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum,uint64_t * filesize_ret,int fsync_file)361 static unsigned ffsb_appendfile_core(ffsb_thread_t * ft, ffsb_fs_t * fs,
362 unsigned opnum, uint64_t * filesize_ret,
363 int fsync_file)
364 {
365 struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
366 struct ffsb_file *curfile;
367
368 int fd;
369
370 char *buf = ft_getbuf(ft);
371 uint32_t write_size = ft_get_write_size(ft);
372 uint32_t write_blocksize = ft_get_write_blocksize(ft);
373 struct randdata *rd = ft_get_randdata(ft);
374 unsigned iterations = 0;
375
376 curfile = choose_file_reader(bf, rd);
377 fd = fhopenappend(curfile->name, ft, fs);
378
379 unlock_file_reader(curfile);
380
381 curfile->size += (uint64_t) write_size;
382
383 iterations = writefile_helper(fd, write_size, write_blocksize, buf,
384 ft, fs);
385 if (fsync_file)
386 if (fsync(fd)) {
387 perror("fsync");
388 printf("aborting\n");
389 exit(1);
390 }
391
392 fhclose(fd, ft, fs);
393 *filesize_ret = write_size;
394 return iterations;
395 }
396
ffsb_appendfile(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)397 void ffsb_appendfile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
398 {
399 unsigned iterations;
400 uint64_t filesize;
401
402 iterations = ffsb_appendfile_core(ft, fs, opnum, &filesize, 0);
403 ft_incr_op(ft, opnum, iterations, filesize);
404 ft_add_writebytes(ft, filesize);
405 }
406
ffsb_appendfile_fsync(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)407 void ffsb_appendfile_fsync(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
408 {
409 unsigned iterations;
410 uint64_t filesize;
411
412 iterations = ffsb_appendfile_core(ft, fs, opnum, &filesize, 1);
413 ft_incr_op(ft, opnum, iterations, filesize);
414 ft_add_writebytes(ft, filesize);
415 }
416
ffsb_createfile_core(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum,uint64_t * filesize_ret,int fsync_file)417 static unsigned ffsb_createfile_core(ffsb_thread_t * ft, ffsb_fs_t * fs,
418 unsigned opnum, uint64_t * filesize_ret,
419 int fsync_file)
420 {
421 struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
422 struct ffsb_file *newfile = NULL;
423
424 int fd;
425 uint64_t size;
426
427 char *buf = ft_getbuf(ft);
428 uint32_t write_blocksize = ft_get_write_blocksize(ft);
429 struct randdata *rd = ft_get_randdata(ft);
430 unsigned iterations = 0;
431
432 if (fs->num_weights) {
433 int num = 1 + getrandom(rd, fs->sum_weights);
434 int curop = 0;
435
436 while (fs->size_weights[curop].weight < num) {
437 num -= fs->size_weights[curop].weight;
438 curop++;
439 }
440 size = fs->size_weights[curop].size;
441 } else {
442 uint64_t range =
443 fs_get_max_filesize(fs) - fs_get_min_filesize(fs);
444 size = fs_get_min_filesize(fs);
445 if (range != 0)
446 size += getllrandom(rd, range);
447 }
448
449 newfile = add_file(bf, size, rd);
450 fd = fhopencreate(newfile->name, ft, fs);
451 iterations = writefile_helper(fd, size, write_blocksize, buf, ft, fs);
452
453 if (fsync_file)
454 if (fsync(fd)) {
455 perror("fsync");
456 printf("aborting\n");
457 exit(1);
458 }
459
460 fhclose(fd, ft, fs);
461 unlock_file_writer(newfile);
462 *filesize_ret = size;
463 return iterations;
464 }
465
ffsb_createfile(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)466 void ffsb_createfile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
467 {
468 unsigned iterations;
469 uint64_t filesize;
470
471 iterations = ffsb_createfile_core(ft, fs, opnum, &filesize, 0);
472 ft_incr_op(ft, opnum, iterations, filesize);
473 ft_add_writebytes(ft, filesize);
474 }
475
ffsb_createfile_fsync(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)476 void ffsb_createfile_fsync(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
477 {
478 unsigned iterations;
479 uint64_t filesize;
480
481 iterations = ffsb_createfile_core(ft, fs, opnum, &filesize, 1);
482 ft_incr_op(ft, opnum, iterations, filesize);
483 ft_add_writebytes(ft, filesize);
484 }
485
ffsb_deletefile(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)486 void ffsb_deletefile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
487 {
488 struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
489 struct ffsb_file *curfile = NULL;
490 randdata_t *rd = ft_get_randdata(ft);
491 struct timeval start, end;
492 int need_stats = ft_needs_stats(ft, SYS_UNLINK) ||
493 fs_needs_stats(fs, SYS_UNLINK);
494
495 curfile = choose_file_writer(bf, rd);
496 remove_file(bf, curfile);
497
498 if (need_stats)
499 gettimeofday(&start, NULL);
500
501 if (unlink(curfile->name) == -1) {
502 printf("error deleting %s in deletefile\n", curfile->name);
503 perror("deletefile");
504 exit(0);
505 }
506
507 if (need_stats) {
508 gettimeofday(&end, NULL);
509 do_stats(&start, &end, ft, fs, SYS_UNLINK);
510 }
511
512 rw_unlock_write(&curfile->lock);
513
514 ft_incr_op(ft, opnum, 1, 0);
515 }
516
ffsb_open_close(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)517 void ffsb_open_close(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
518 {
519 struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
520 struct ffsb_file *curfile = NULL;
521 randdata_t *rd = ft_get_randdata(ft);
522 int fd;
523
524 curfile = choose_file_reader(bf, rd);
525 fd = fhopenread(curfile->name, ft, fs);
526 fhclose(fd, ft, fs);
527 unlock_file_reader(curfile);
528 ft_incr_op(ft, opnum, 1, 0);
529 }
530
ffsb_stat(ffsb_thread_t * ft,ffsb_fs_t * fs,unsigned opnum)531 void ffsb_stat(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum)
532 {
533 struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum);
534 struct ffsb_file *curfile = NULL;
535 randdata_t *rd = ft_get_randdata(ft);
536
537 curfile = choose_file_reader(bf, rd);
538 fhstat(curfile->name, ft, fs);
539 unlock_file_reader(curfile);
540
541 ft_incr_op(ft, opnum, 1, 0);
542 }
543