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 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 53 void fop_bench(ffsb_fs_t * fs, unsigned opnum) 54 { 55 fs_set_opdata(fs, fs_get_datafiles(fs), opnum); 56 } 57 58 void fop_age(ffsb_fs_t * fs, unsigned opnum) 59 { 60 fs_set_opdata(fs, fs_get_agefiles(fs), opnum); 61 } 62 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 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 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 */ 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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