/* * Copyright (c) International Business Machines Corp., 2001-2004 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include "fh.h" #include "util.h" #include "ffsb.h" #include "fileops.h" #include "ffsb_op.h" static void do_stats(struct timeval *start, struct timeval *end, ffsb_thread_t * ft, ffsb_fs_t * fs, syscall_t sys) { struct timeval diff; uint32_t value = 0; if (!ft && !fs) return; timersub(end, start, &diff); value = 1000000 * diff.tv_sec + diff.tv_usec; if (ft && ft_needs_stats(ft, sys)) ft_add_stat(ft, sys, value); if (fs && fs_needs_stats(fs, sys)) fs_add_stat(fs, sys, value); } void fop_bench(ffsb_fs_t * fs, unsigned opnum) { fs_set_opdata(fs, fs_get_datafiles(fs), opnum); } void fop_age(ffsb_fs_t * fs, unsigned opnum) { fs_set_opdata(fs, fs_get_agefiles(fs), opnum); } static unsigned readfile_helper(int fd, uint64_t size, uint32_t blocksize, char *buf, ffsb_thread_t * ft, ffsb_fs_t * fs) { int iterations, a; int last; iterations = size / blocksize; last = size % blocksize; for (a = 0; a < iterations; a++) fhread(fd, buf, blocksize, ft, fs); if (last) fhread(fd, buf, last, ft, fs); return iterations; } static uint64_t get_random_offset(randdata_t * rd, uint64_t filesize, int aligned) { if (!aligned) return getllrandom(rd, filesize); filesize /= 4096; return getllrandom(rd, filesize) * 4096; } void ffsb_readfile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum); struct ffsb_file *curfile = NULL; int fd; uint64_t filesize; char *buf = ft_getbuf(ft); int read_random = ft_get_read_random(ft); uint64_t read_size = ft_get_read_size(ft); uint32_t read_blocksize = ft_get_read_blocksize(ft); uint32_t read_skipsize = ft_get_read_skipsize(ft); int skip_reads = ft_get_read_skip(ft); struct randdata *rd = ft_get_randdata(ft); uint64_t iterations = 0; curfile = choose_file_reader(bf, rd); fd = fhopenread(curfile->name, ft, fs); filesize = ffsb_get_filesize(curfile->name); assert(filesize >= read_size); /* Sequential read, starting at a random point */ if (!read_random) { uint64_t range = filesize - read_size; uint64_t offset = 0; /* Skip or "stride" reads option */ if (skip_reads) { unsigned i, last; uint64_t minfilesize; iterations = read_size / read_blocksize; last = read_size % read_blocksize; /* Double check that the user hasn't specified * a read_size that is too large when combined * with the seeks */ if (last) minfilesize = last + iterations * (read_blocksize + read_skipsize); else minfilesize = read_blocksize + iterations - 1 * (read_blocksize + read_skipsize); if (minfilesize > filesize) { printf("Error: read size %llu bytes too big " "w/ skipsize %u and blocksize %u," " for file of size %llu bytes\n" " aborting\n\n", read_size, read_skipsize, read_blocksize, filesize); printf("minimum file size must be at least " " %llu bytes\n", minfilesize); exit(1); } for (i = 0; i < iterations; i++) { fhread(fd, buf, read_blocksize, ft, fs); fhseek(fd, (uint64_t) read_skipsize, SEEK_CUR, ft, fs); } if (last) { fhread(fd, buf, (uint64_t) last, ft, fs); iterations++; } } else { /* Regular sequential reads */ if (range) { offset = get_random_offset(rd, range, fs_get_alignio(fs)); fhseek(fd, offset, SEEK_SET, ft, fs); } iterations = readfile_helper(fd, read_size, read_blocksize, buf, ft, fs); } } else { /* Randomized read */ uint64_t range = filesize - read_blocksize; int i; iterations = read_size / read_blocksize; for (i = 0; i < iterations; i++) { uint64_t offset = get_random_offset(rd, range, fs_get_alignio(fs)); fhseek(fd, offset, SEEK_SET, ft, fs); fhread(fd, buf, read_blocksize, ft, fs); } } unlock_file_reader(curfile); fhclose(fd, ft, fs); ft_incr_op(ft, opnum, iterations, read_size); ft_add_readbytes(ft, read_size); } /* Just like ffsb_readfile but we read the whole file from start to * finish regardless of file size. */ void ffsb_readall(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum); struct ffsb_file *curfile = NULL; int fd; uint64_t filesize; char *buf = ft_getbuf(ft); uint32_t read_blocksize = ft_get_read_blocksize(ft); struct randdata *rd = ft_get_randdata(ft); unsigned iterations = 0; curfile = choose_file_reader(bf, rd); fd = fhopenread(curfile->name, ft, fs); filesize = ffsb_get_filesize(curfile->name); iterations = readfile_helper(fd, filesize, read_blocksize, buf, ft, fs); unlock_file_reader(curfile); fhclose(fd, ft, fs); ft_incr_op(ft, opnum, iterations, filesize); ft_add_readbytes(ft, filesize); } /* Shared core between ffsb_writefile and ffsb_writefile_fsync.*/ static unsigned ffsb_writefile_core(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum, uint64_t * filesize_ret, int fsync_file) { struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum); struct ffsb_file *curfile = NULL; int fd; uint64_t filesize; char *buf = ft_getbuf(ft); int write_random = ft_get_write_random(ft); uint32_t write_size = ft_get_write_size(ft); uint32_t write_blocksize = ft_get_write_blocksize(ft); struct randdata *rd = ft_get_randdata(ft); unsigned iterations = 0; curfile = choose_file_reader(bf, rd); fd = fhopenwrite(curfile->name, ft, fs); filesize = ffsb_get_filesize(curfile->name); assert(filesize >= write_size); /* Sequential write, starting at a random point */ if (!write_random) { uint64_t range = filesize - write_size; uint64_t offset = 0; if (range) { offset = get_random_offset(rd, range, fs_get_alignio(fs)); fhseek(fd, offset, SEEK_SET, ft, fs); } iterations = writefile_helper(fd, write_size, write_blocksize, buf, ft, fs); } else { /* Randomized write */ uint64_t range = filesize - write_blocksize; int i; iterations = write_size / write_blocksize; for (i = 0; i < iterations; i++) { uint64_t offset = get_random_offset(rd, range, fs_get_alignio(fs)); fhseek(fd, offset, SEEK_SET, ft, fs); fhwrite(fd, buf, write_blocksize, ft, fs); } } if (fsync_file) { if (fsync(fd)) { perror("fsync"); printf("aborting\n"); exit(1); } } unlock_file_reader(curfile); fhclose(fd, ft, fs); *filesize_ret = filesize; return iterations; } void ffsb_writefile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { unsigned iterations; uint64_t filesize; iterations = ffsb_writefile_core(ft, fs, opnum, &filesize, 0); ft_incr_op(ft, opnum, iterations, filesize); ft_add_writebytes(ft, filesize); } void ffsb_writefile_fsync(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { unsigned iterations; uint64_t filesize; iterations = ffsb_writefile_core(ft, fs, opnum, &filesize, 1); ft_incr_op(ft, opnum, iterations, filesize); ft_add_writebytes(ft, filesize); } /* Shared core between ffsb_writeall and ffsb_writeall_fsync.*/ static unsigned ffsb_writeall_core(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum, uint64_t * filesize_ret, int fsync_file) { struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum); struct ffsb_file *curfile = NULL; int fd; uint64_t filesize; char *buf = ft_getbuf(ft); uint32_t write_blocksize = ft_get_write_blocksize(ft); struct randdata *rd = ft_get_randdata(ft); unsigned iterations = 0; curfile = choose_file_reader(bf, rd); fd = fhopenwrite(curfile->name, ft, fs); filesize = ffsb_get_filesize(curfile->name); iterations = writefile_helper(fd, filesize, write_blocksize, buf, ft, fs); if (fsync_file) if (fsync(fd)) { perror("fsync"); printf("aborting\n"); exit(1); } unlock_file_reader(curfile); fhclose(fd, ft, fs); *filesize_ret = filesize; return iterations; } /* Just like ffsb_writefile but we write the whole file from start to * finish regardless of file size */ void ffsb_writeall(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { unsigned iterations; uint64_t filesize; iterations = ffsb_writeall_core(ft, fs, opnum, &filesize, 0); ft_incr_op(ft, opnum, iterations, filesize); ft_add_writebytes(ft, filesize); } void ffsb_writeall_fsync(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { unsigned iterations; uint64_t filesize; iterations = ffsb_writeall_core(ft, fs, opnum, &filesize, 1); ft_incr_op(ft, opnum, iterations, filesize); ft_add_writebytes(ft, filesize); } static unsigned ffsb_appendfile_core(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum, uint64_t * filesize_ret, int fsync_file) { struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum); struct ffsb_file *curfile; int fd; char *buf = ft_getbuf(ft); uint32_t write_size = ft_get_write_size(ft); uint32_t write_blocksize = ft_get_write_blocksize(ft); struct randdata *rd = ft_get_randdata(ft); unsigned iterations = 0; curfile = choose_file_reader(bf, rd); fd = fhopenappend(curfile->name, ft, fs); unlock_file_reader(curfile); curfile->size += (uint64_t) write_size; iterations = writefile_helper(fd, write_size, write_blocksize, buf, ft, fs); if (fsync_file) if (fsync(fd)) { perror("fsync"); printf("aborting\n"); exit(1); } fhclose(fd, ft, fs); *filesize_ret = write_size; return iterations; } void ffsb_appendfile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { unsigned iterations; uint64_t filesize; iterations = ffsb_appendfile_core(ft, fs, opnum, &filesize, 0); ft_incr_op(ft, opnum, iterations, filesize); ft_add_writebytes(ft, filesize); } void ffsb_appendfile_fsync(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { unsigned iterations; uint64_t filesize; iterations = ffsb_appendfile_core(ft, fs, opnum, &filesize, 1); ft_incr_op(ft, opnum, iterations, filesize); ft_add_writebytes(ft, filesize); } static unsigned ffsb_createfile_core(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum, uint64_t * filesize_ret, int fsync_file) { struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum); struct ffsb_file *newfile = NULL; int fd; uint64_t size; char *buf = ft_getbuf(ft); uint32_t write_blocksize = ft_get_write_blocksize(ft); struct randdata *rd = ft_get_randdata(ft); unsigned iterations = 0; if (fs->num_weights) { int num = 1 + getrandom(rd, fs->sum_weights); int curop = 0; while (fs->size_weights[curop].weight < num) { num -= fs->size_weights[curop].weight; curop++; } size = fs->size_weights[curop].size; } else { uint64_t range = fs_get_max_filesize(fs) - fs_get_min_filesize(fs); size = fs_get_min_filesize(fs); if (range != 0) size += getllrandom(rd, range); } newfile = add_file(bf, size, rd); fd = fhopencreate(newfile->name, ft, fs); iterations = writefile_helper(fd, size, write_blocksize, buf, ft, fs); if (fsync_file) if (fsync(fd)) { perror("fsync"); printf("aborting\n"); exit(1); } fhclose(fd, ft, fs); unlock_file_writer(newfile); *filesize_ret = size; return iterations; } void ffsb_createfile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { unsigned iterations; uint64_t filesize; iterations = ffsb_createfile_core(ft, fs, opnum, &filesize, 0); ft_incr_op(ft, opnum, iterations, filesize); ft_add_writebytes(ft, filesize); } void ffsb_createfile_fsync(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { unsigned iterations; uint64_t filesize; iterations = ffsb_createfile_core(ft, fs, opnum, &filesize, 1); ft_incr_op(ft, opnum, iterations, filesize); ft_add_writebytes(ft, filesize); } void ffsb_deletefile(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum); struct ffsb_file *curfile = NULL; randdata_t *rd = ft_get_randdata(ft); struct timeval start, end; int need_stats = ft_needs_stats(ft, SYS_UNLINK) || fs_needs_stats(fs, SYS_UNLINK); curfile = choose_file_writer(bf, rd); remove_file(bf, curfile); if (need_stats) gettimeofday(&start, NULL); if (unlink(curfile->name) == -1) { printf("error deleting %s in deletefile\n", curfile->name); perror("deletefile"); exit(0); } if (need_stats) { gettimeofday(&end, NULL); do_stats(&start, &end, ft, fs, SYS_UNLINK); } rw_unlock_write(&curfile->lock); ft_incr_op(ft, opnum, 1, 0); } void ffsb_open_close(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum); struct ffsb_file *curfile = NULL; randdata_t *rd = ft_get_randdata(ft); int fd; curfile = choose_file_reader(bf, rd); fd = fhopenread(curfile->name, ft, fs); fhclose(fd, ft, fs); unlock_file_reader(curfile); ft_incr_op(ft, opnum, 1, 0); } void ffsb_stat(ffsb_thread_t * ft, ffsb_fs_t * fs, unsigned opnum) { struct benchfiles *bf = (struct benchfiles *)fs_get_opdata(fs, opnum); struct ffsb_file *curfile = NULL; randdata_t *rd = ft_get_randdata(ft); curfile = choose_file_reader(bf, rd); fhstat(curfile->name, ft, fs); unlock_file_reader(curfile); ft_incr_op(ft, opnum, 1, 0); }