1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdio.h> 18#include <sys/time.h> 19#include <sys/types.h> 20#include <unistd.h> 21#include <sys/syscall.h> 22#include <stdlib.h> 23#include <string.h> 24#include <sys/stat.h> 25#include <sys/errno.h> 26#include <fcntl.h> 27#include <string.h> 28#include <assert.h> 29#include <pthread.h> 30#include <sys/statfs.h> 31#include <sys/resource.h> 32#include "ioshark.h" 33#define IOSHARK_MAIN 34#include "ioshark_bench.h" 35 36/* 37 * Note on "quick" mode where we do reads on existing /system, 38 * /vendor and other files in ro partitions, instead of creating 39 * them. The ioshark compiler builds up a table of all the files 40 * in /system, /vendor and other ro partitions. For files in this 41 * list, the benchmark skips the pre-creation of these files and 42 * reads them directly. 43 * The code relevant to this is in *filename_cache*. 44 */ 45 46char *progname; 47 48#define MAX_INPUT_FILES 8192 49#define MAX_THREADS 8192 50 51struct thread_state_s { 52 char *filename; 53 FILE *fp; 54 int num_files; 55 void *db_handle; 56}; 57 58struct thread_state_s thread_state[MAX_INPUT_FILES]; 59int num_input_files = 0; 60int next_input_file; 61 62pthread_t tid[MAX_THREADS]; 63 64/* 65 * Global options 66 */ 67int do_delay = 0; 68int verbose = 0; 69int summary_mode = 0; 70int quick_mode = 0; 71 72#if 0 73static long gettid() 74{ 75 return syscall(__NR_gettid); 76} 77#endif 78 79void usage() 80{ 81 fprintf(stderr, "%s [-d preserve_delays] [-n num_iterations] [-t num_threads] -q -v | -s <list of parsed input files>\n", 82 progname); 83 fprintf(stderr, "%s -s, -v are mutually exclusive\n", 84 progname); 85 exit(EXIT_FAILURE); 86} 87 88pthread_mutex_t time_mutex = PTHREAD_MUTEX_INITIALIZER; 89pthread_mutex_t stats_mutex = PTHREAD_MUTEX_INITIALIZER; 90pthread_mutex_t work_mutex = PTHREAD_MUTEX_INITIALIZER; 91struct timeval aggregate_file_create_time; 92struct timeval debug_file_create_time; 93struct timeval aggregate_file_remove_time; 94struct timeval aggregate_IO_time; 95struct timeval aggregate_delay_time; 96 97u_int64_t aggr_op_counts[IOSHARK_MAX_FILE_OP]; 98struct rw_bytes_s aggr_io_rw_bytes; 99struct rw_bytes_s aggr_create_rw_bytes; 100 101/* 102 * Locking needed here because aggregate_delay_time is updated 103 * from multiple threads concurrently. 104 */ 105static void 106update_time(struct timeval *aggr_time, 107 struct timeval *delta_time) 108{ 109 struct timeval tmp; 110 111 pthread_mutex_lock(&time_mutex); 112 timeradd(aggr_time, delta_time, &tmp); 113 *aggr_time = tmp; 114 pthread_mutex_unlock(&time_mutex); 115} 116 117static void 118update_op_counts(u_int64_t *op_counts) 119{ 120 int i; 121 122 pthread_mutex_lock(&stats_mutex); 123 for (i = IOSHARK_LSEEK ; i < IOSHARK_MAX_FILE_OP ; i++) 124 aggr_op_counts[i] += op_counts[i]; 125 pthread_mutex_unlock(&stats_mutex); 126} 127 128static void 129update_byte_counts(struct rw_bytes_s *dest, struct rw_bytes_s *delta) 130{ 131 pthread_mutex_lock(&stats_mutex); 132 dest->bytes_read += delta->bytes_read; 133 dest->bytes_written += delta->bytes_written; 134 pthread_mutex_unlock(&stats_mutex); 135} 136 137static int work_next_file; 138static int work_num_files; 139 140void 141init_work(int next_file, int num_files) 142{ 143 pthread_mutex_lock(&work_mutex); 144 work_next_file = next_file; 145 work_num_files = work_next_file + num_files; 146 pthread_mutex_unlock(&work_mutex); 147} 148 149/* Dole out the next file to work on to the thread */ 150static struct thread_state_s * 151get_work() 152{ 153 struct thread_state_s *work = NULL; 154 155 pthread_mutex_lock(&work_mutex); 156 if (work_next_file < work_num_files) 157 work = &thread_state[work_next_file++]; 158 pthread_mutex_unlock(&work_mutex); 159 return work; 160} 161 162static void 163create_files(struct thread_state_s *state) 164{ 165 int i; 166 struct ioshark_file_state file_state; 167 char path[MAX_IOSHARK_PATHLEN]; 168 void *db_node; 169 struct rw_bytes_s rw_bytes; 170 char *filename; 171 int readonly; 172 173 memset(&rw_bytes, 0, sizeof(struct rw_bytes_s)); 174 for (i = 0 ; i < state->num_files ; i++) { 175 if (fread(&file_state, sizeof(struct ioshark_file_state), 176 1, state->fp) != 1) { 177 fprintf(stderr, "%s read error tracefile\n", 178 progname); 179 exit(EXIT_FAILURE); 180 } 181 /* 182 * Check to see if the file is in a readonly partition, 183 * in which case, we don't have to pre-create the file 184 * we can just read the existing file. 185 */ 186 filename = 187 get_ro_filename(file_state.global_filename_ix); 188 if (quick_mode) 189 assert(filename != NULL); 190 if (quick_mode == 0 || 191 is_readonly_mount(filename, file_state.size) == 0) { 192 sprintf(path, "file.%d.%d", 193 (int)(state - thread_state), 194 file_state.fileno); 195 create_file(path, file_state.size, 196 &rw_bytes); 197 filename = path; 198 readonly = 0; 199 } else { 200 readonly = 1; 201 } 202 db_node = files_db_add_byfileno(state->db_handle, 203 file_state.fileno, 204 readonly); 205 files_db_update_size(db_node, file_state.size); 206 files_db_update_filename(db_node, filename); 207 } 208 update_byte_counts(&aggr_create_rw_bytes, &rw_bytes); 209} 210 211static void 212do_one_io(void *db_node, 213 struct ioshark_file_operation *file_op, 214 u_int64_t *op_counts, 215 struct rw_bytes_s *rw_bytes, 216 char **bufp, int *buflen) 217{ 218 assert(file_op->file_op < IOSHARK_MAX_FILE_OP); 219 op_counts[file_op->file_op]++; 220 switch (file_op->file_op) { 221 int ret; 222 char *p; 223 int fd; 224 225 case IOSHARK_LSEEK: 226 case IOSHARK_LLSEEK: 227 ret = lseek(files_db_get_fd(db_node), 228 file_op->lseek_offset, 229 file_op->lseek_action); 230 if (ret < 0) { 231 fprintf(stderr, 232 "%s: lseek(%s %lu %d) returned error %d\n", 233 progname, files_db_get_filename(db_node), 234 file_op->lseek_offset, 235 file_op->lseek_action, errno); 236 exit(EXIT_FAILURE); 237 } 238 break; 239 case IOSHARK_PREAD64: 240 p = get_buf(bufp, buflen, file_op->prw_len, 0); 241 ret = pread(files_db_get_fd(db_node), p, 242 file_op->prw_len, file_op->prw_offset); 243 rw_bytes->bytes_read += file_op->prw_len; 244 if (ret < 0) { 245 fprintf(stderr, 246 "%s: pread(%s %zu %lu) error %d\n", 247 progname, 248 files_db_get_filename(db_node), 249 file_op->prw_len, 250 file_op->prw_offset, errno); 251 exit(EXIT_FAILURE); 252 } 253 break; 254 case IOSHARK_PWRITE64: 255 p = get_buf(bufp, buflen, file_op->prw_len, 1); 256 ret = pwrite(files_db_get_fd(db_node), p, 257 file_op->prw_len, file_op->prw_offset); 258 rw_bytes->bytes_written += file_op->prw_len; 259 if (ret < 0) { 260 fprintf(stderr, 261 "%s: pwrite(%s %zu %lu) error %d\n", 262 progname, 263 files_db_get_filename(db_node), 264 file_op->prw_len, 265 file_op->prw_offset, errno); 266 exit(EXIT_FAILURE); 267 } 268 break; 269 case IOSHARK_READ: 270 p = get_buf(bufp, buflen, file_op->rw_len, 0); 271 ret = read(files_db_get_fd(db_node), p, 272 file_op->rw_len); 273 rw_bytes->bytes_read += file_op->rw_len; 274 if (ret < 0) { 275 fprintf(stderr, 276 "%s: read(%s %zu) error %d\n", 277 progname, 278 files_db_get_filename(db_node), 279 file_op->rw_len, 280 errno); 281 exit(EXIT_FAILURE); 282 } 283 break; 284 case IOSHARK_WRITE: 285 p = get_buf(bufp, buflen, file_op->rw_len, 1); 286 ret = write(files_db_get_fd(db_node), p, 287 file_op->rw_len); 288 rw_bytes->bytes_written += file_op->rw_len; 289 if (ret < 0) { 290 fprintf(stderr, 291 "%s: write(%s %zu) error %d\n", 292 progname, 293 files_db_get_filename(db_node), 294 file_op->rw_len, 295 errno); 296 exit(EXIT_FAILURE); 297 } 298 break; 299 case IOSHARK_MMAP: 300 case IOSHARK_MMAP2: 301 ioshark_handle_mmap(db_node, file_op, 302 bufp, buflen, op_counts, 303 rw_bytes); 304 break; 305 case IOSHARK_OPEN: 306 if (file_op->open_flags & O_CREAT) { 307 fd = open(files_db_get_filename(db_node), 308 file_op->open_flags, 309 file_op->open_mode); 310 if (fd < 0) { 311 /* 312 * EEXIST error acceptable, others are fatal. 313 * Although we failed to O_CREAT the file (O_EXCL) 314 * We will force an open of the file before any 315 * IO. 316 */ 317 if (errno == EEXIST) { 318 return; 319 } else { 320 fprintf(stderr, 321 "%s: O_CREAT open(%s %x %o) error %d\n", 322 progname, 323 files_db_get_filename(db_node), 324 file_op->open_flags, 325 file_op->open_mode, errno); 326 exit(EXIT_FAILURE); 327 } 328 } 329 } else { 330 fd = open(files_db_get_filename(db_node), 331 file_op->open_flags); 332 if (fd < 0) { 333 if (file_op->open_flags & O_DIRECTORY) { 334 /* O_DIRECTORY open()s should fail */ 335 return; 336 } else { 337 fprintf(stderr, 338 "%s: open(%s %x) error %d\n", 339 progname, 340 files_db_get_filename(db_node), 341 file_op->open_flags, 342 errno); 343 exit(EXIT_FAILURE); 344 } 345 } 346 } 347 files_db_close_fd(db_node); 348 files_db_update_fd(db_node, fd); 349 break; 350 case IOSHARK_FSYNC: 351 case IOSHARK_FDATASYNC: 352 if (file_op->file_op == IOSHARK_FSYNC) { 353 ret = fsync(files_db_get_fd(db_node)); 354 if (ret < 0) { 355 fprintf(stderr, 356 "%s: fsync(%s) error %d\n", 357 progname, 358 files_db_get_filename(db_node), 359 errno); 360 exit(EXIT_FAILURE); 361 } 362 } else { 363 ret = fdatasync(files_db_get_fd(db_node)); 364 if (ret < 0) { 365 fprintf(stderr, 366 "%s: fdatasync(%s) error %d\n", 367 progname, 368 files_db_get_filename(db_node), 369 errno); 370 exit(EXIT_FAILURE); 371 } 372 } 373 break; 374 case IOSHARK_CLOSE: 375 ret = close(files_db_get_fd(db_node)); 376 if (ret < 0) { 377 fprintf(stderr, 378 "%s: close(%s) error %d\n", 379 progname, 380 files_db_get_filename(db_node), errno); 381 exit(EXIT_FAILURE); 382 } 383 files_db_update_fd(db_node, -1); 384 break; 385 default: 386 fprintf(stderr, "%s: unknown FILE_OP %d\n", 387 progname, file_op->file_op); 388 exit(EXIT_FAILURE); 389 break; 390 } 391} 392 393static void 394do_io(struct thread_state_s *state) 395{ 396 void *db_node; 397 struct ioshark_header header; 398 struct ioshark_file_operation file_op; 399 int fd; 400 int i; 401 char *buf = NULL; 402 int buflen = 0; 403 struct timeval total_delay_time; 404 u_int64_t op_counts[IOSHARK_MAX_FILE_OP]; 405 struct rw_bytes_s rw_bytes; 406 407 rewind(state->fp); 408 if (fread(&header, sizeof(struct ioshark_header), 1, state->fp) != 1) { 409 fprintf(stderr, "%s read error %s\n", 410 progname, state->filename); 411 exit(EXIT_FAILURE); 412 } 413 /* 414 * First open and pre-create all the files. Indexed by fileno. 415 */ 416 timerclear(&total_delay_time); 417 memset(&rw_bytes, 0, sizeof(struct rw_bytes_s)); 418 memset(op_counts, 0, sizeof(op_counts)); 419 fseek(state->fp, 420 sizeof(struct ioshark_header) + 421 header.num_files * sizeof(struct ioshark_file_state), 422 SEEK_SET); 423 /* 424 * Loop over all the IOs, and launch each 425 */ 426 for (i = 0 ; i < header.num_io_operations ; i++) { 427 if (fread(&file_op, sizeof(struct ioshark_file_operation), 428 1, state->fp) != 1) { 429 fprintf(stderr, "%s read error trace.outfile\n", 430 progname); 431 exit(EXIT_FAILURE); 432 } 433 if (do_delay) { 434 struct timeval start; 435 436 (void)gettimeofday(&start, (struct timezone *)NULL); 437 usleep(file_op.delta_us); 438 update_delta_time(&start, &total_delay_time); 439 } 440 db_node = files_db_lookup_byfileno(state->db_handle, 441 file_op.fileno); 442 if (db_node == NULL) { 443 fprintf(stderr, 444 "%s Can't lookup fileno %d, fatal error\n", 445 progname, file_op.fileno); 446 exit(EXIT_FAILURE); 447 } 448 if (file_op.file_op != IOSHARK_OPEN && 449 files_db_get_fd(db_node) == -1) { 450 int openflags; 451 452 /* 453 * This is a hack to workaround the fact that we did not 454 * see an open() for this file until now. open() the 455 * file O_RDWR, so that we can perform the IO. 456 */ 457 if (files_db_readonly(db_node)) 458 openflags = O_RDONLY; 459 else 460 openflags = O_RDWR; 461 fd = open(files_db_get_filename(db_node), 462 openflags); 463 if (fd < 0) { 464 fprintf(stderr, "%s: open(%s %x) error %d\n", 465 progname, 466 files_db_get_filename(db_node), 467 openflags, 468 errno); 469 exit(EXIT_FAILURE); 470 } 471 files_db_update_fd(db_node, fd); 472 } 473 do_one_io(db_node, &file_op, 474 op_counts, &rw_bytes, &buf, &buflen); 475 } 476 files_db_fsync_discard_files(state->db_handle); 477 files_db_close_files(state->db_handle); 478 update_time(&aggregate_delay_time, &total_delay_time); 479 update_op_counts(op_counts); 480 update_byte_counts(&aggr_io_rw_bytes, &rw_bytes); 481} 482 483void * 484io_thread(void *unused __attribute__((unused))) 485{ 486 struct thread_state_s *state; 487 488 srand(gettid()); 489 while ((state = get_work())) 490 do_io(state); 491 pthread_exit(NULL); 492 return(NULL); 493} 494 495static void 496do_create(struct thread_state_s *state) 497{ 498 struct ioshark_header header; 499 500 if (fread(&header, sizeof(struct ioshark_header), 1, state->fp) != 1) { 501 fprintf(stderr, "%s read error %s\n", 502 progname, state->filename); 503 exit(EXIT_FAILURE); 504 } 505 state->num_files = header.num_files; 506 state->db_handle = files_db_create_handle(); 507 create_files(state); 508} 509 510void * 511create_files_thread(void *unused __attribute__((unused))) 512{ 513 struct thread_state_s *state; 514 515 while ((state = get_work())) 516 do_create(state); 517 pthread_exit(NULL); 518 return(NULL); 519} 520 521int 522get_start_end(int *start_ix) 523{ 524 int i, j, ret_numfiles; 525 u_int64_t free_fs_bytes; 526 char *infile; 527 FILE *fp; 528 struct ioshark_header header; 529 struct ioshark_file_state file_state; 530 struct statfs fsstat; 531 static int fssize_clamp_next_index = 0; 532 static int chunk = 0; 533 534 if (fssize_clamp_next_index == num_input_files) 535 return 0; 536 if (statfs("/data/local/tmp", &fsstat) < 0) { 537 fprintf(stderr, "%s: Can't statfs /data/local/tmp\n", 538 progname); 539 exit(EXIT_FAILURE); 540 } 541 free_fs_bytes = (fsstat.f_bavail * fsstat.f_bsize) * 9 /10; 542 for (i = fssize_clamp_next_index; i < num_input_files; i++) { 543 infile = thread_state[i].filename; 544 fp = fopen(infile, "r"); 545 if (fp == NULL) { 546 fprintf(stderr, "%s: Can't open %s\n", 547 progname, infile); 548 exit(EXIT_FAILURE); 549 } 550 if (fread(&header, sizeof(struct ioshark_header), 551 1, fp) != 1) { 552 fprintf(stderr, "%s read error %s\n", 553 progname, infile); 554 exit(EXIT_FAILURE); 555 } 556 for (j = 0 ; j < header.num_files ; j++) { 557 if (fread(&file_state, sizeof(struct ioshark_file_state), 558 1, fp) != 1) { 559 fprintf(stderr, "%s read error tracefile\n", 560 progname); 561 exit(EXIT_FAILURE); 562 } 563 if (quick_mode == 0 || 564 !is_readonly_mount( 565 get_ro_filename(file_state.global_filename_ix), 566 file_state.size)) { 567 if (file_state.size > free_fs_bytes) { 568 fclose(fp); 569 goto out; 570 } 571 free_fs_bytes -= file_state.size; 572 } 573 } 574 fclose(fp); 575 } 576out: 577 if (verbose) { 578 if (chunk > 0 || i < num_input_files) { 579 printf("Breaking up input files, Chunk %d: %d to %d\n", 580 chunk++, fssize_clamp_next_index, i - 1); 581 } else { 582 printf("Entire Dataset fits start = %d to %d, free_bytes = %ju\n", 583 fssize_clamp_next_index, 584 i - fssize_clamp_next_index, 585 free_fs_bytes); 586 } 587 } 588 *start_ix = fssize_clamp_next_index; 589 ret_numfiles = i - fssize_clamp_next_index; 590 fssize_clamp_next_index = i; 591 return ret_numfiles; 592} 593 594int 595ioshark_pthread_create(pthread_t *tidp, void *(*start_routine)(void *)) 596{ 597 pthread_attr_t attr; 598 599 pthread_attr_init(&attr); 600 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 601 pthread_attr_setstacksize(&attr, (size_t)(1024*1024)); 602 return pthread_create(tidp, &attr, start_routine, (void *)NULL); 603} 604 605void 606wait_for_threads(int num_threads) 607{ 608 int i; 609 610 for (i = 0; i < num_threads; i++) { 611 pthread_join(tid[i], NULL); 612 tid[i] = 0; 613 } 614} 615 616#define IOSHARK_FD_LIM 8192 617 618static void 619sizeup_fd_limits(void) 620{ 621 struct rlimit r; 622 623 getrlimit(RLIMIT_NOFILE, &r); 624 if (r.rlim_cur >= IOSHARK_FD_LIM) 625 /* cur limit already at what we want */ 626 return; 627 /* 628 * Size up both the Max and Cur to IOSHARK_FD_LIM. 629 * If we are not running as root, this will fail, 630 * catch that below and exit. 631 */ 632 if (r.rlim_max < IOSHARK_FD_LIM) 633 r.rlim_max = IOSHARK_FD_LIM; 634 r.rlim_cur = IOSHARK_FD_LIM; 635 if (setrlimit(RLIMIT_NOFILE, &r) < 0) { 636 fprintf(stderr, "%s: Can't setrlimit (RLIMIT_NOFILE, 8192)\n", 637 progname); 638 exit(EXIT_FAILURE); 639 } 640 getrlimit(RLIMIT_NOFILE, &r); 641 if (r.rlim_cur < IOSHARK_FD_LIM) { 642 fprintf(stderr, "%s: Can't setrlimit up to 8192\n", 643 progname); 644 fprintf(stderr, "%s: Running as root ?\n", 645 progname); 646 exit(EXIT_FAILURE); 647 } 648} 649 650int 651main(int argc, char **argv) 652{ 653 int i; 654 FILE *fp; 655 struct stat st; 656 char *infile; 657 int num_threads = 0; 658 int num_iterations = 1; 659 int c; 660 int num_files, start_file; 661 struct thread_state_s *state; 662 663 progname = argv[0]; 664 while ((c = getopt(argc, argv, "dn:st:qv")) != EOF) { 665 switch (c) { 666 case 'd': 667 do_delay = 1; 668 break; 669 case 'n': 670 num_iterations = atoi(optarg); 671 break; 672 case 's': 673 /* Non-verbose summary mode for nightly runs */ 674 summary_mode = 1; 675 break; 676 case 't': 677 num_threads = atoi(optarg); 678 break; 679 case 'q': 680 /* 681 * If quick mode is enabled, then we won't 682 * pre-create files that we are doing IO on that 683 * live in readonly partitions (/system, /vendor etc) 684 */ 685 quick_mode = 1; 686 break; 687 case 'v': 688 verbose = 1; 689 break; 690 default: 691 usage(); 692 } 693 } 694 695 if ((verbose + summary_mode) == 2) 696 usage(); 697 698 if (num_threads > MAX_THREADS) 699 usage(); 700 701 if (optind == argc) 702 usage(); 703 704 sizeup_fd_limits(); 705 706 for (i = optind; i < argc; i++) { 707 infile = argv[i]; 708 if (stat(infile, &st) < 0) { 709 fprintf(stderr, "%s: Can't stat %s\n", 710 progname, infile); 711 exit(EXIT_FAILURE); 712 } 713 if (st.st_size == 0) { 714 fprintf(stderr, "%s: Empty file %s\n", 715 progname, infile); 716 continue; 717 } 718 fp = fopen(infile, "r"); 719 if (fp == NULL) { 720 fprintf(stderr, "%s: Can't open %s\n", 721 progname, infile); 722 continue; 723 } 724 thread_state[num_input_files].filename = infile; 725 thread_state[num_input_files].fp = fp; 726 num_input_files++; 727 } 728 729 if (num_input_files == 0) { 730 exit(EXIT_SUCCESS); 731 } 732 if (verbose) { 733 printf("Total Input Files = %d\n", num_input_files); 734 printf("Num Iterations = %d\n", num_iterations); 735 } 736 timerclear(&aggregate_file_create_time); 737 timerclear(&aggregate_file_remove_time); 738 timerclear(&aggregate_IO_time); 739 740 if (quick_mode) 741 init_filename_cache(); 742 743 capture_util_state_before(); 744 745 /* 746 * We pre-create the files that we need once and then we 747 * loop around N times doing IOs on the pre-created files. 748 * 749 * get_start_end() breaks up the total work here to make sure 750 * that all the files we need to pre-create fit into the 751 * available space in /data/local/tmp (hardcoded for now). 752 * 753 * If it won't fit, then we do several sweeps. 754 */ 755 while ((num_files = get_start_end(&start_file))) { 756 struct timeval time_for_pass; 757 758 /* Create files once */ 759 if (!summary_mode) 760 printf("Doing Pre-creation of Files\n"); 761 if (quick_mode && !summary_mode) 762 printf("Skipping Pre-creation of read-only Files\n"); 763 if (num_threads == 0 || num_threads > num_files) 764 num_threads = num_files; 765 (void)system("echo 3 > /proc/sys/vm/drop_caches"); 766 init_work(start_file, num_files); 767 (void)gettimeofday(&time_for_pass, 768 (struct timezone *)NULL); 769 for (i = 0; i < num_threads; i++) { 770 if (ioshark_pthread_create(&(tid[i]), 771 create_files_thread)) { 772 fprintf(stderr, 773 "%s: Can't create creator thread %d\n", 774 progname, i); 775 exit(EXIT_FAILURE); 776 } 777 } 778 wait_for_threads(num_threads); 779 update_delta_time(&time_for_pass, &aggregate_file_create_time); 780 /* Do the IOs N times */ 781 for (i = 0 ; i < num_iterations ; i++) { 782 (void)system("echo 3 > /proc/sys/vm/drop_caches"); 783 if (!summary_mode) { 784 if (num_iterations > 1) 785 printf("Starting Test. Iteration %d...\n", 786 i); 787 else 788 printf("Starting Test...\n"); 789 } 790 init_work(start_file, num_files); 791 (void)gettimeofday(&time_for_pass, 792 (struct timezone *)NULL); 793 for (c = 0; c < num_threads; c++) { 794 if (ioshark_pthread_create(&(tid[c]), 795 io_thread)) { 796 fprintf(stderr, 797 "%s: Can't create thread %d\n", 798 progname, c); 799 exit(EXIT_FAILURE); 800 } 801 } 802 wait_for_threads(num_threads); 803 update_delta_time(&time_for_pass, 804 &aggregate_IO_time); 805 } 806 807 /* 808 * We are done with the N iterations of IO. 809 * Destroy the files we pre-created. 810 */ 811 init_work(start_file, num_files); 812 while ((state = get_work())) { 813 struct timeval start; 814 815 (void)gettimeofday(&start, (struct timezone *)NULL); 816 files_db_unlink_files(state->db_handle); 817 update_delta_time(&start, &aggregate_file_remove_time); 818 files_db_free_memory(state->db_handle); 819 } 820 } 821 if (!summary_mode) { 822 printf("Total Creation time = %ju.%ju (msecs.usecs)\n", 823 get_msecs(&aggregate_file_create_time), 824 get_usecs(&aggregate_file_create_time)); 825 printf("Total Remove time = %ju.%ju (msecs.usecs)\n", 826 get_msecs(&aggregate_file_remove_time), 827 get_usecs(&aggregate_file_remove_time)); 828 if (do_delay) 829 printf("Total delay time = %ju.%ju (msecs.usecs)\n", 830 get_msecs(&aggregate_delay_time), 831 get_usecs(&aggregate_delay_time)); 832 printf("Total Test (IO) time = %ju.%ju (msecs.usecs)\n", 833 get_msecs(&aggregate_IO_time), 834 get_usecs(&aggregate_IO_time)); 835 if (verbose) 836 print_bytes("Upfront File Creation bytes", 837 &aggr_create_rw_bytes); 838 print_bytes("Total Test (IO) bytes", &aggr_io_rw_bytes); 839 if (verbose) 840 print_op_stats(aggr_op_counts); 841 report_cpu_disk_util(); 842 } else { 843 printf("%ju.%ju ", 844 get_msecs(&aggregate_file_create_time), 845 get_usecs(&aggregate_file_create_time)); 846 printf("%ju.%ju ", 847 get_msecs(&aggregate_file_remove_time), 848 get_usecs(&aggregate_file_remove_time)); 849 if (do_delay) 850 printf("%ju.%ju ", 851 get_msecs(&aggregate_delay_time), 852 get_usecs(&aggregate_delay_time)); 853 printf("%ju.%ju ", 854 get_msecs(&aggregate_IO_time), 855 get_usecs(&aggregate_IO_time)); 856 print_bytes(NULL, &aggr_io_rw_bytes); 857 report_cpu_disk_util(); 858 printf("\n"); 859 } 860 if (quick_mode) 861 free_filename_cache(); 862} 863