blob: 3212c18b21b7a1c917af7645f2171027ee15bdea [file] [log] [blame]
/*
* 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 <sys/stat.h>
#include <sys/types.h>
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#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);
}